復活!CP/M ワンボードマイコンでCP/Mを!
CP/MがTK−80互換のワンボードマイコンの上で復活します
ND80ZVとMYCPU80の上でCP/Mが走ります!
[第349回]
●MIDI演奏プログラムのプログラムリスト
やっとプログラムの説明にまでたどりつきました。
MIDI演奏プログラムはE−80(仮称)ミニコンで動作するプログラムです。
当然のことながらMIDI出力回路が必須になりますし、またMIDI音源も必須です。
またZ8S180内蔵の16ビットタイマーを使った割り込みも利用しています。
そういうことからしますと、かなり特殊なプログラムということになりますので、そんなプログラムの動作をここで説明しましても、読者の皆様方にとりましては、なんの役にも立たないではないか、ということかもしれません。
あ。
しかし。
せっかくここまでいろいろやってきましたことでもありますから、近い内にND80ZV(ND80Z3.5)でも同じことができるようにしてみたいと思っております。
もっともその場合でもMIDI音源は必要ですし、最低MIDI出力回路を増設する必要はありますけれど。
今回お見せしますのは、そういうやや特殊なプログラムなのですけれど、タイマーによる割込みを使っている点などは、応用のための参考にしていただけると思いますし、複数トラックに記述されたMIDIイベントを同時進行的に処理するあたりなども何かの参考にしていただけるのではないかと思います。
E−80(仮称)ミニコンに移植したZB3BASICシステムの上で動作していますが、システムルーチンは使っていません。
動作に必要なプログラムは全て下のプログラムリストに含まれています。
MIDIファイル特有の可変長データから普通の16進数データに変換するところや、演奏のための最低時間単位(ティック)を算出するために、テンポデータを4分音符の分解能で除算するところなども、プログラムテクニックとして参考にしていただけるのではと思います。
MIDI演奏プログラムのアセンブルリストです。
2013/3/15 10:9 midisq8.txt END=82DE ;;; E-80 232C(MIDI) midi sequence ; 13/1/19 2/24 2/25 2/26 3/4 3/5 3/6 3/10 ;3/11 3/12 3/15 ; ;cpu clock=10MHz ; ORG $8000 ; ZB3ENTRY=$1033 ; DATATOP=$8400 TRKNO=$840B BPQN=$840C ; 8000 C30680 JP START 8003 00 NOP ; 8004 7F82 DW INT;timer0 int address ; 8006 3E80 START:LD A,80 8008 ED47 LD I,A 800A AF XOR A 800B 013300 LD BC,$0033;ILregister 800E ED79 OUT (C),A 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 ; 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 ; 808A 01A107 START10:LD BC,$07A1;(tempodata=0.5s) 808D CD8281 CALL TMPSB 8090 CDD381 CALL TMSB 8093 DD21DE82 START1:LD IX,TPRMTOP 8097 3A0B84 LD A,(TRKNO) 809A 32DC82 LD (CNTR),A 809D AF XOR A 809E 32DD82 LD (ENDCK),A ;loop 80A1 3A0B84 ST1LP:LD A,(TRKNO) 80A4 47 LD B,A 80A5 3D DEC A 80A6 CAB680 JP Z,ST1LP1;mode0? 80A9 3ADC82 LD A,(CNTR) 80AC B8 CP B 80AD C2B680 JP NZ,ST1LP1 80B0 DD7E00 LD A,(IX+00);if mode1,pass trk1 timedata 80B3 C3C380 JP ST1LP2 80B6 3ADD82 ST1LP1:LD A,(ENDCK) 80B9 47 LD B,A 80BA DD7E00 LD A,(IX+00) 80BD F5 PUSH AF 80BE B0 OR B 80BF 32DD82 LD (ENDCK),A 80C2 F1 POP AF 80C3 B7 ST1LP2:OR A 80C4 CA3781 JP Z,NEXT 80C7 DD7E01 LD A,(IX+01) 80CA B7 OR A 80CB C23781 JP NZ,NEXT 80CE DD6E05 LD L,(IX+05) 80D1 DD6606 LD H,(IX+06) 80D4 7E LD A,(HL) 80D5 FEFF CP FF 80D7 CA0781 JP Z,CODEFF 80DA FEF0 CP F0 80DC CA5381 JP Z,CODEF0 80DF E6F0 AND F0 80E1 F2FE80 JP P,RUNSTS;running status 80E4 FEC0 CP C0 80E6 CAF580 JP Z,CXOUT 80E9 FED0 CP D0 80EB CAF580 JP Z,CXOUT 80EE 7E LD A,(HL) 80EF DD7707 LD (IX+07),A;code save 80F2 CD4B82 CALL MIDIOUT 80F5 CD4B82 CXOUT:CALL MIDIOUT 80F8 CD4B82 CALL MIDIOUT 80FB C31881 JP NEXTDT ;running status 80FE DD7E07 RUNSTS:LD A,(IX+07) 8101 CD6582 CALL MIDIAOUT 8104 C3F580 JP CXOUT ; 8107 23 CODEFF:INC HL 8108 7E LD A,(HL) 8109 FE2F CP 2F 810B CA3381 JP Z,TRKEND 810E FE51 CP 51 8110 CA7081 JP Z,TMPSET ;pass text data or something 8113 23 INC HL 8114 CD1682 CALL VLREAD 8117 19 ADD HL,DE;pass to next data top(variable length top) 8118 CD1682 NEXTDT:CALL VLREAD 811B DD7302 LD (IX+02),E 811E DD7203 LD (IX+03),D 8121 DD7004 LD (IX+04),B 8124 78 LD A,B 8125 B2 OR D 8126 B3 OR E 8127 DD7701 LD (IX+01),A 812A DD7505 LD (IX+05),L 812D DD7406 LD (IX+06),H 8130 C33781 JP NEXT 8133 DD360000 TRKEND:LD (IX+00),00 8137 3ADC82 NEXT:LD A,(CNTR) 813A 3D DEC A 813B CA4981 JP Z,NEXT2 813E 32DC82 LD (CNTR),A 8141 110800 LD DE,$0008 8144 DD19 ADD IX,DE 8146 C3A180 JP ST1LP 8149 3ADD82 NEXT2:LD A,(ENDCK) 814C B7 OR A 814D CA6681 JP Z,MIDIEND 8150 C39380 JP START1 ; 8153 CD4B82 CODEF0:CALL MIDIOUT 8156 4E LD C,(HL) 8157 23 INC HL 8158 CD4B82 CODEF0_2:CALL MIDIOUT 815B 0D DEC C 815C C25881 JP NZ,CODEF0_2 815F C31881 JP NEXTDT ; ;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 ; 8170 23 TMPSET:INC HL 8171 23 INC HL;pass 'length' 8172 46 LD B,(HL) 8173 23 INC HL 8174 4E LD C,(HL);BC=TEMPO*256 cut off LSB(byte) 8175 23 INC HL 8176 23 INC HL 8177 E5 PUSH HL 8178 CD8281 CALL TMPSB ; ;timer set and int on 817B CDD381 CALL TMSB 817E E1 POP HL 817F C31881 JP NEXTDT ; ;subroutine ; ;TEMPO keisan ; 8182 210C84 TMPSB:LD HL,BPQN 8185 56 LD D,(HL) 8186 23 INC HL 8187 5E LD E,(HL);DE=BPQN(bit per quarter note) ;TEMPO/BPQN 8188 60 LD H,B 8189 69 LD L,C 818A 3E09 LD A,09 ;if bit7 of D is '0',shift to left DE 818C CB7A SFTDE:BIT 7,D 818E C29A81 JP NZ,SFTDE2 8191 B7 OR A 8192 CB13 RL E 8194 CB12 RL D 8196 3C INC A 8197 C38C81 JP SFTDE 819A B7 SFTDE2:OR A 819B CB1A RR D 819D CB1B RR E ;if bit7 of H is '0',shift to left HL 819F CB7C SFTHL:BIT 7,H 81A1 C2AD81 JP NZ,SFTHL2 81A4 B7 OR A 81A5 CB15 RL L 81A7 CB14 RL H 81A9 3D DEC A 81AA C39F81 JP SFTHL 81AD B7 SFTHL2:OR A 81AE CB1C RR H 81B0 CB1D RR L 81B2 010000 LD BC,$0000 ;divide HL by DE 81B5 B7 DIVHLDE:OR A 81B6 ED52 SBC HL,DE 81B8 D2BC81 JP NC,DIVHLDE2 81BB 19 ADD HL,DE 81BC 3F DIVHLDE2:CCF 81BD CB11 RL C 81BF CB10 RL B 81C1 CB15 RL L 81C3 CB14 RL H 81C5 3D DEC A 81C6 C2B581 JP NZ,DIVHLDE ;BC/2 81C9 B7 OR A 81CA CB18 RR B 81CC CB19 RR C 81CE ED43D682 LD (TIMEDT),BC 81D2 C9 RET ; ;timer set 81D3 010C00 TMSB:LD BC,$000C 81D6 2AD682 LD HL,(TIMEDT) 81D9 ED69 OUT (C),L;timer0 data registerL 81DB 0C INC C 81DC ED61 OUT (C),H;timer0 data registerH 81DE 0C INC C 81DF ED69 OUT (C),L;timer0 reload registerL 81E1 0C INC C 81E2 ED61 OUT (C),H;timer0 reload registerH 81E4 0C INC C 81E5 3E11 LD A,11;INT enable,countdown start 81E7 ED79 OUT (C),A 81E9 FB EI 81EA C9 RET ; ;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 ; ;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 ; 824B DBFE MIDIOUT:IN A,(FE) 824D E620 AND 20 824F CA4B82 JP Z,MIDIOUT 8252 7E LD A,(HL) 8253 D3FD OUT (FD),A 8255 3E02 LD A,02;bit1=L,bit0=H;bit0-4 are INVERT 8257 D3FE OUT (FE),A 8259 DBFE MIDIOUT2:IN A,(FE) 825B E620 AND 20 825D C25982 JP NZ,MIDIOUT2 8260 AF XOR A 8261 D3FE OUT (FE),A 8263 23 INC HL 8264 C9 RET ; 8265 F5 MIDIAOUT:PUSH AF 8266 DBFE MIDIAOUT1:IN A,(FE) 8268 E620 AND 20 826A CA6682 JP Z,MIDIAOUT1 826D F1 POP AF 826E D3FD OUT (FD),A 8270 3E02 LD A,02;bit1=L,bit0=H;bit0-4 are INVERT 8272 D3FE OUT (FE),A 8274 DBFE MIDIAOUT2:IN A,(FE) 8276 E620 AND 20 8278 C27482 JP NZ,MIDIAOUT2 827B AF XOR A 827C D3FE OUT (FE),A 827E C9 RET ; ;INT routine ; 827F DDE5 INT:PUSH IX 8281 E5 PUSH HL 8282 D5 PUSH DE 8283 C5 PUSH BC 8284 F5 PUSH AF 8285 011000 LD BC,$0010 8288 ED78 IN A,(C); 828A 0E0C LD C,0C 828C ED78 IN A,(C);clear TIF0 flag 828E DD21DE82 LD IX,TPRMTOP 8292 3A0B84 LD A,(TRKNO) 8295 4F LD C,A 8296 DD7E01 INT1:LD A,(IX+01) 8299 B7 OR A 829A CAC182 JP Z,INT2 829D DD6E02 LD L,(IX+02) 82A0 DD6603 LD H,(IX+03) 82A3 DD4604 LD B,(IX+04) 82A6 78 LD A,B 82A7 B7 OR A 82A8 CAB482 JP Z,INT12 82AB 7C LD A,H 82AC B5 OR L 82AD C2B482 JP NZ,INT12 82B0 05 DEC B 82B1 DD7004 LD (IX+04),B 82B4 2B INT12:DEC HL 82B5 DD7502 LD (IX+02),L 82B8 DD7403 LD (IX+03),H 82BB 7C LD A,H 82BC B5 OR L 82BD B0 OR B 82BE DD7701 LD (IX+01),A 82C1 0D INT2:DEC C 82C2 CACD82 JP Z,INT3 82C5 110800 LD DE,$0008 82C8 DD19 ADD IX,DE 82CA C39682 JP INT1 82CD F1 INT3:POP AF 82CE C1 POP BC 82CF D1 POP DE 82D0 E1 POP HL 82D1 DDE1 POP IX 82D3 FB EI 82D4 ED4D RETI ; ; 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 ; ....... ; ;end ; BPQN =840C CNTR =82DC CODEF0 =8153 CODEF0_2 =8158 CODEFF =8107 CXOUT =80F5 DATATOP =8400 DEWK =82D8 DIVHLDE =81B5 DIVHLDE2 =81BC ENDCK =82DD ERROR =8162 HLWK =82DA INT =827F INT1 =8296 INT12 =82B4 INT2 =82C1 INT3 =82CD IX =0866 MIDIAOUT =8265 MIDIAOUT1 =8266 MIDIAOUT2 =8274 MIDIEND =8166 MIDIOUT =824B MIDIOUT2 =8259 MTRK =8211 NEXT =8137 NEXT2 =8149 NEXTDT =8118 RUNSTS =80FE SEARCH =81EB SEARCH1 =81F3 SEARCH2 =81FB SEARCH3 =81FC SEARCH4 =820E SEARCHE =820D SFTDE =818C SFTDE2 =819A SFTHL =819F SFTHL2 =81AD ST0LP =803D ST1LP =80A1 ST1LP1 =80B6 ST1LP2 =80C3 START =8006 START1 =8093 START10 =808A TIMEDT =82D6 TMPSB =8182 TMPSET =8170 TMSB =81D3 TPRMTOP =82DE TRKEND =8133 TRKNO =840B VLREAD =8216 VLREAD1 =823E VLREAD2 =8246 ZB3ENTRY =1033 |