2013.3.20
前へ
次へ
ホームページトップへ戻る

復活!CP/M ワンボードマイコンでCP/Mを!
CP/MがTK−80互換のワンボードマイコンの上で復活します
ND80ZVとMYCPU80の上でCP/Mが走ります

[第351回]


●MIDI演奏プログラムの環境設定

前回からの続きです。
MIDI演奏プログラムの詳細について説明をしております。
前回説明をしました続きのところです。

8010 D3FF       OUT (FF),A;start message
              ;
              ;cpu wait settei
8012 0D         DEC C
8013 3E00       LD A,00
8015 ED79       OUT (C),A;memory wait=0,i/o wait=1
              ;
              ;16F886 settei
8017 3E88       LD A,88
8019 D3FB       OUT (FB),A;82C55 A=out,B=out,C0-3=out,C4-7=in
801B 3EFB       LD A,FB;16F886out enable
801D D3FA       OUT (FA),A 
OUT (FF),A
はエラーが発生して異常終了したかどうかのサインとして、フロントパネルのI/O出力(アドレスFF)の表示を利用するためです。
プログラムの実行には関係はありません。

その次のアドレス8012H〜8016Hの説明です。
当プログラムはCPUクロック10MHzで実行します。
余計なウェイトを外すため、I/Oレジスタ32Hに00を書き込んでいます。
CレジスタにはILレジスタのアドレス33Hが入っていますから、それを−1します。

今気が付きました。
本当はさらに不要なリフレッシュも禁止すべきでした。
そのためには、この後ろに
LD C,36
OUT (C),A
を追加しておくべきでした。

アドレス8017H〜801EHの説明です。
MIDIデータの送信、受信はPIC16F886を使って行います。
今回は送信のみです。
PIC16F886にMIDIデータを送るためには、CPUデータバスとPIC16F886の間に置いたバッファをアクティブにしなければなりません。
ここではそのための初期設定を行なっています。
この部分が関係するMIDI関連の回路図は[第330回]にありますので参照願います。

●作業エリア

当プログラムではデータエリアはわずかしか使いません。
プログラムの先頭で定義しているのは下記の3つのみです。

              ;cpu clock=10MHz
              ;
                ORG $8000
              ;
                ZB3ENTRY=$1033
              ;
                DATATOP=$8400
                TRKNO=$840B
                BPQN=$840C
DATATOPはMIDIファイルをロードする先頭のアドレスです。
覚えのために書いただけで、プログラムでは参照していません。
TRKNOとBPQNはMIDIファイルを8400Hからロードしたときに、ヘッダートラックのデータトラック数が入るアドレスと4分音符の分解能が入るアドレスです。
そのアドレスのデータをプログラムでそのまま使います。

プログラムの終わりには少しのワークエリアと、トラック毎のデータエリアが置かれます。

              ;
              ; work space
              ;
82D6 0000     TIMEDT:DW $0000
82D8 0000     DEWK:DW $0000
82DA 0000     HLWK:DW $0000
82DC 00       CNTR:DB 00
82DD 00       ENDCK:DB 00
              ;
82DE 00       TPRMTOP:NOP
                ;TRK1 endmk 1byte
                ;TRK1 time0mk 1byte
                ;TRK1 timedata 3bytes
                ;TRK1 dataaddress 2bytes
                ;TRK1 previous datacode
                ; .......
              ; 

●トラック用ワークエリアの設定

最初にトラック用の作業エリアを準備します。

              ;
                
801F DD21DE82   LD IX,TPRMTOP
8023 210B84     LD HL,TRKNO
8026 7E         LD A,(HL)
8027 32DC82     LD (CNTR),A
802A 23         INC HL
802B 111182     LD DE,MTRK
802E CDEB81     CALL SEARCH
8031 7D         LD A,L
8032 FE12       CP 12
8034 C26281     JP NZ,ERROR
8037 7C         LD A,H
8038 FE84       CP 84
803A C26281     JP NZ,ERROR
              ;set track parameter
803D 23       ST0LP:INC HL
803E 23         INC HL;pass upper 2bytes
803F 56         LD D,(HL)
8040 23         INC HL
8041 5E         LD E,(HL);bytes of TRK
8042 23         INC HL
8043 ED53D882   LD (DEWK),DE
8047 22DA82     LD (HLWK),HL
804A CD1682     CALL VLREAD
804D DD3600FF   LD (IX+00),FF
8051 78         LD A,B
8052 B2         OR D
8053 B3         OR E
8054 DD7701     LD (IX+01),A
8057 DD7302     LD (IX+02),E
805A DD7203     LD (IX+03),D
805D DD7004     LD (IX+04),B
8060 DD7505     LD (IX+05),L
8063 DD7406     LD (IX+06),H
8066 3ADC82     LD A,(CNTR)
8069 3D         DEC A
806A CA8A80     JP Z,START10
806D 32DC82     LD (CNTR),A
8070 110800     LD DE,$0008
8073 DD19       ADD IX,DE
8075 ED5BD882   LD DE,(DEWK)
8079 2ADA82     LD HL,(HLWK)
807C 19         ADD HL,DE
807D 7E         LD A,(HL)
807E FE4D       CP 4D;'M'
8080 C26281     JP NZ,ERROR
8083 23         INC HL
8084 23         INC HL
8085 23         INC HL
8086 23         INC HL
8087 C33D80     JP ST0LP

TRKNOのところにあるデータトラック数をカウンタCNTRに入れて、その数だけトラック用ワークエリアを設定します。
各データトラックの先頭にはMTrkの文字が置かれています。
最初のデータトラックの先頭位置を知るために、文字列サーチサブルーチンSEARCHをコールしてMTrkをサーチします。
こうしなくても最初のデータトラックの位置は本当はわかっているのですが適正なファイルであることを確認するためにそのようにしています。
最初のデータトラックのMTrkの次のアドレスは8412Hになるはずなのですが、もしそうでない場合には当プログラムでは扱えないファイルなので実行を中止します。

トラックの先頭にはそのトラックのバイト数を示す4バイトの16進数が置かれています。
上位2バイトは00なのでパスします。
その次には1バイト以上の可変長の時間データとイベントコードがあります。
その可変長時間データを読み込んで普通の16進数データに変換します。
その変換はVLREADサブルーチンで行ないます。
変換した結果はB、D、Eレジスタに入れられます。
当プログラムで扱うMIDIファイルの可変長時間データは最大でも3バイトです。
そのことにつきましては[第349回]で説明をしていますので参照願います。

トラックエリアのアドレスはIXレジスタで管理します。
(IX+00)には最初FFを入れます。
メインプログラムの処理が進んでトラックの最後まで処理が完了したら、ここには00が入ります。
それによってこのトラックのワークエリアはそれ以後は読み飛ばされます。
そのためのエンドマークです。
(IX+01)は時間データが000000の時には00が入ります。
それ以外のときには非00の数が入ります。
ここはメインプログラムが複数バイトを処理している間に割り込みが発生しないようにする大切な役目をしています。
そのことについては割り込みプログラムの説明のときに説明をいたします。
(IX+2)〜(IX+4)には時間データが入ります。
(IX+5)と(IX+6)にはイベントデータの最初のデータのアドレスが入れられます。
(IX+7)はここでは場所だけを確保します。値はまだ入りません。

以上の作業を、データトラックの数だけ繰り返します。
繰り返しが終了したら、MIDIデータの処理ルーチンの開始アドレス(START10)にジャンプします。

下はエラーおよび正常処理終了ルーチンです。

              ;MIDI end
8162 3E0E     ERROR:LD A,0E
8164 D3FF       OUT (FF),A
8166 F3       MIDIEND:DI
8167 011000     LD BC,$0010
816A AF         XOR A
816B ED79       OUT (C),A;INT disenable,countdown stop
816D C33310     JP ZB3ENTRY

エラーが発生したときはフロントパネルのI/OデータLEDに0EHを出力したあと、タイマー割り込みの終了処理をしてZB3BASICのエントリポイントにジャンプします。
正常に処理が終了したときはI/OデータLEDには何も出力しないで、終了処理をしてZB3BASICのエントリポイントにジャンプします。

●文字列サーチサブルーチン

文字列をサーチするサブルーチンです。
MTrkの文字列を検索するために使われます。

              ;
              ;string search
81EB 7C       SEARCH:LD A,H
81EC FEA0       CP A0
81EE CA0D82     JP Z,SEARCHE
81F1 D5         PUSH DE
81F2 1A         LD A,(DE)
81F3 BE       SEARCH1:CP (HL)
81F4 CAFB81     JP Z,SEARCH2
81F7 23         INC HL
81F8 C3F381     JP SEARCH1
81FB E5       SEARCH2:PUSH HL
81FC 23       SEARCH3:INC HL
81FD 13         INC DE
81FE 1A         LD A,(DE)
81FF B7         OR A
8200 CA0E82     JP Z,SEARCH4
8203 BE         CP (HL)
8204 CAFC81     JP Z,SEARCH3
8207 E1         POP HL
8208 23         INC HL
8209 D1         POP DE
820A C3EB81     JP SEARCH
820D B7       SEARCHE:OR A;reset Zflag
820E D1       SEARCH4:POP DE;dummy
820F D1         POP DE
8210 C9         RET
              ; 
8211 4D       MTRK:DB 4D;M
8212 54         DB 54;T
8213 72         DB 72;r
8214 6B         DB 6B;k
8215 00         DB 00
              ;

●可変長データ→16進数変換サブルーチン

可変長データを普通の16進数に変換するサブルーチンです。
変換後の数はB、D、Eレジスタに入れられます。
Bが上位バイト、Eが下位バイトです。

               ;
              ;variable length data read
8216 0600     VLREAD:LD B,00
8218 7E         LD A,(HL)
8219 B7         OR A
821A F24682     JP P,VLREAD2
821D E67F       AND 7F
821F 57         LD D,A
8220 23         INC HL
8221 7E         LD A,(HL)
8222 5F         LD E,A
8223 B7         OR A
8224 F23E82     JP P,VLREAD1
8227 E67F       AND 7F
8229 5F         LD E,A
822A CB13       RL E
822C CB1A       RR D
822E CB1B       RR E
8230 42         LD B,D
8231 53         LD D,E
8232 23         INC HL
8233 5E         LD E,(HL)
8234 CB13       RL E
8236 CB18       RR B
8238 CB1A       RR D
823A CB1B       RR E
823C 23         INC HL
823D C9         RET
823E CB13     VLREAD1:RL E
8240 CB1A       RR D
8242 CB1B       RR E
8244 23         INC HL
8245 C9         RET
8246 5F       VLREAD2:LD E,A
8247 1600       LD D,00
8249 23         INC HL
824A C9         RET

プログラムの先頭で最上位データのBレジスタには00を入れておきます。
MIDIの可変長データのルールについては[第338回]で説明をいたしました。
数値はつねに7ビットで表記されます。
最上位のビット7は、次に下位データが続くとき1、続かないときに0になります。
ですから最初のデータのビット7が0(つまり正の数)なら、1バイトだけの数です。
そのときはVLREAD2にジャンプします。
そこでEにデータが入れられ、Dには00が入れられてリターンします。

それ以外の場合には、ひとまず2バイトの数と仮定して、最初のデータの下位7ビットをDに入れます。
次のデータのビット7が0のときは、データが2バイトですからそのままVLREAD1にジャンプします。
VLREAD1では一度Eを左に1ビットシフトしてからあらためてDEを右に1ビットシフトします。
これでDEに変換後の値が入ります。

それ以外は3バイトの数です。
VLREAD1と同じ処理を行なった後、DをBに、EをDに入れます。
3バイト目のデータをEに入れたあと、一度Eを左に1ビットシフトしてからあらためてBDEを右に1ビットシフトします。
これでBDEに変換後の値が入ります。

次回はいよいよ実際のMIDIデータ処理の説明に入ります。

ワンボードマイコンでCP/Mを![第351回]
2013.3.20upload

前へ
次へ
ホームページトップへ戻る