8080マイコンをつくろう!(TK−80完全復活!)
なんと8080です!
もちろん、BASICからCP/Mまで、できます!
36年の時を経ていまよみがえる8080CPUマイコン組立キット!
なんたってはるか昔の生産中止品を集めて作る組立キットです。
生産前から堂々予告です。
入手できなくなったら即生産終了!売り切れ御免!
[第43回]
●インベーダーゲームプログラム
このところ「マイコン独立大作戦」システムのプログラム作成に没頭しております。
もうあと一息というところまできているのですが、なにしろ入力と出力というコンピュータシステムとしては根幹の部分をひっくり返してしまうわけですので、ちょいとしたバグのせいで丸っと一日つぶれてしまうことなどがあって、なかなかに大変です。
そのため早朝から深夜までバグ捜しに没頭することとなってしまい、ホームページの更新にまで手が回りません。
あともう少しですので、気長にお付き合いいただきますようお願いいたします。
さて今回は久しぶりのND8080です。
ND8080につきましてはましては最後に書きましたのが昨年6月ですから、それからもう半年以上が経ってしまいました。
幸いお蔭様にてND8080組立キットは予想外にご好評をいただきまして、その後は一時ほどではありませんが、時々ご注文をいただきずっと提供を続けております。
8080も8224も8228もなんとか手当てしてきましたがいつまでも続けられるものではありませんので、もしご興味がおありでしたら、入手不能になります前にぜひご購入いただきますようお勧めいたします。
前振りが長くなってしまいました。
つい一週間ほど前にND8080組立キットをご購入いただいたお客様からメールをいただきました。
もう組み立ててしまって、さっそくゲームプログラムを作られたとのことで、メールに添付してお送りいただきました。
えっ。
お届けして、まだ一週間も経っていませんのに…。
さっそく拝見させていただきましたら、なんと、これはすごい。
せっかくお送りいただきましたので、しばし「マイコン独立大作戦」のプログラム開発作業の手を休めまして、ゲームプログラムを入力し、さっそく実行させていただきました。
いただいたメールには「カシオのプログラム電卓で数字を使ったインベーダーゲーム」と説明されていますので、もとはカシオの電卓用のゲームだったということでしょうか。
なかなかによくできていると思います。
8000番地からプログラムを実行すると左端から数字インベーダーが右端の陣地めがけて進軍してきます。
[3]のキーを押すと右端の陣地の数字がカウントアップします。
敵の先頭の数値に合わせて(上の写真では2)、そこで[WRITE INC]を押すとその数字が敵をめがけて発射され、先頭の敵を破壊します。
まごまごしていると敵はどんどん数を増して陣地に近づいてきます。
右端の陣地まで敵に攻め込まれたらそこでゲームオーバーです。
GAMEOVERの文字が点滅するとともに、やっつけた敵の数が表示されます。
ちょいと慣れてきたので、26匹もやっつけました。
メールにはバイナリファイルだけではなくてソースプログラムも添付されていました。
ソースプログラムには丁寧にプログラムの説明まで入っておりました。
これは8080プログラムを学ぼうとされる方にとって、とてもよい参考プログラムになると思いましたので、プログラムの公開をお願いしましたところ、ご快諾いただきました。
随分長いプログラムです。
これだけのものを数日間で書き上げられたとは、とても思えません。
メールには8080のアセンブラは初めてです、と書いてありました。
もう、脱帽です。
マシン語のプログラムはソースリストよりもアドレスとマシン語があわせて出力されたアセンブルリストのほうが理解しやすいと思いますので、先にアセンブルリストを掲載します。
ND8080組立キットに付属の8080アセンブラで出力されたリストです。
2017/2/5 18: INVDER.ASM END=98A9 ORG $8000 DP1=$83F8 WAIT27=$02EF INKEY=$0223 INPUT=$0216 SCR00=$9000 SCR01=$9001 SCR02=$9002 SCR03=$9003 SCR04=$9004 SCR05=$9005 SCR06=$9006 SCR07=$9007 WAITCNT=$9010 CNT1=$9011 WAITENEMY_CNT=$9012 WAITENEMY_MAX=$9013 RAND256=$9014 ENEMY_MAX=$9015 WAITMISL_CNT=$9016 WAITMISL_MAX=$9017 MISL_POS=$9018 MISL_CHR=$9019 SCORE=$901A DISP_CNT=$901B 8000 00 START: NOP ;スタックの初期化 8001 21FFFF LXI H,$FFFF 8004 F9 SPHL ;画面エリアの初期化 8005 3E08 MVI A,08 ;Screen Clear 8007 210090 LXI H,SCR00 ;SCR(1-8)=SP 800A 3620 START1: MVI M,20 800C 23 INX H 800D 3D DCR A 800E C20A80 JNZ START1 ;自機の初期化 8011 210790 LXI H,SCR07 ;SCR(7)='0' 8014 3630 MVI M,30 ;敵の移動速度の初期化 8016 211290 LXI H,WAITENEMY_CNT ;WAITENEMY_CNT=0 8019 3600 MVI M,00 801B 211390 LXI H,WAITENEMY_MAX ;WAITENEMY_MAX=80 801E 36F0 MVI M,F0 ;敵の前線位置の初期化 8020 211590 LXI H,ENEMY_MAX ;ENEMY_MAX=0 8023 3600 MVI M,00 ;ミサイルの移動速度の初期化 8025 211690 LXI H,WAITMISL_CNT 8028 3600 MVI M,00 802A 211790 LXI H,WAITMISL_MAX 802D 3610 MVI M,10 ;ミサイルの位置の初期化 802F 211890 LXI H,MISL_POS 8032 3600 MVI M,00 ;スコア 8034 211A90 LXI H,SCORE 8037 3600 MVI M,00 ;------ ;メイン ;------ 8039 00 MAIN: NOP 803A CD4980 CALL MISL 803D CDCC80 CALL ENEMY 8040 CD5581 CALL KEYINP 8043 CDB282 CALL DISPALL 8046 C33980 JMP MAIN ;------------------ ;ミサイルの移動処理 ;------------------ 8049 00 MISL: NOP ;ミサイルが発射されたか 804A 3A1890 LDA MISL_POS ;IF MISL_POS=0 THEN MISL_END 804D B7 ORA A 804E CACB80 JZ MISL_END ;待ち時間内か調べる 8051 211790 LXI H,WAITMISL_MAX 8054 3A1690 LDA WAITMISL_CNT 8057 3C INR A 8058 BE CMP M 8059 321690 STA WAITMISL_CNT 805C CA6280 JZ MISL_CHK ;IF WAITMISL_CNT = WAITMISL_MAX THEN MISL_END 805F C3CB80 JMP MISL_END 8062 00 MISL_CHK: NOP ;初期化 8063 3E00 MVI A,00 8065 321690 STA WAITMISL_CNT ;ミサイル表示を消す 8068 3A1890 LDA MISL_POS 806B FE08 CPI 08 806D CA7B80 JZ MISL_CHK1 8070 010000 LXI B,$0000 ;DSP(POS)=SP 8073 4F MOV C,A 8074 210090 LXI H,SCR00 8077 09 DAD B 8078 2B DCX H 8079 3620 MVI M,20 ;ミサイル移動(仮) 807B 3A1890 MISL_CHK1: LDA MISL_POS ;#A=MISL_POS-1 807E 3D DCR A ;左端でないか 807F B7 ORA A ;IF #A=0 THEN MISL_CLEAR 8080 CAC280 JZ MISL_CLEAR ;移動先に敵がいないか :IF DSP(POS-1)<>ENEMY THEN MISL_MOV 8083 010000 LXI B,$0000 8086 4F MOV C,A 8087 210090 LXI H,SCR00 808A 09 DAD B 808B 2B DCX H 808C 7E MOV A,M 808D FE20 CPI 20 808F CA9580 JZ MISL_MOV 8092 C3AD80 JMP MISL_EXPL ;IF DSP(POS-1)=ENEMY THEN MISL_EXPL 8095 00 MISL_MOV: NOP ;ミサイルを1コマ左移動 8096 3A1890 LDA MISL_POS ;MISL_POS=MISL_POS-1 8099 3D DCR A 809A 321890 STA MISL_POS ;ミサイルの表示 809D 010000 LXI B,$0000 ;DSP(MISL_POS)=MISSILE 80A0 4F MOV C,A 80A1 210090 LXI H,SCR00 80A4 09 DAD B 80A5 2B DCX H 80A6 3A1990 LDA MISL_CHR 80A9 77 MOV M,A ;処理終了 80AA C3CB80 JMP MISL_END ;GOTO MISL_END 80AD 00 MISL_EXPL: NOP ;敵爆破 ;画面クリア 80AE 3E20 MVI A,20 80B0 77 MOV M,A ;敵1機消滅 80B1 3A1590 LDA ENEMY_MAX 80B4 3D DCR A 80B5 321590 STA ENEMY_MAX ;得点 80B8 3A1A90 LDA SCORE 80BB 3C INR A 80BC 321A90 STA SCORE ;ミサイルクリア 80BF C3C280 JMP MISL_CLEAR 80C2 00 MISL_CLEAR: NOP ;ミサイルをクリア 80C3 3E00 MVI A,00 ;MISL_POS=0 80C5 321890 STA MISL_POS ;ミサイルをセット ; LDA MISL_CHR ; STA SCR07 ;処理終了 80C8 C3CB80 JMP MISL_END 80CB C9 MISL_END: RET ;------------------ ;敵の発生と移動処理 ;------------------ ;待ち時間内か調べる 80CC 00 ENEMY: NOP 80CD 211390 LXI H,WAITENEMY_MAX 80D0 3A1290 LDA WAITENEMY_CNT 80D3 3C INR A 80D4 BE CMP M 80D5 CADE80 JZ ENEMY_CHK ;IF WAITENEMY_CNT = WAITENEMY_MAX THEN ENEMY_CHK 80D8 321290 STA WAITENEMY_CNT 80DB C35381 JMP ENEMY_END ;敵の勝利確認を行う 80DE 00 ENEMY_CHK: NOP ;初期化 80DF 3E00 MVI A,00 ;WAITENEMY_CNT=0 80E1 321290 STA WAITENEMY_CNT ;早くする 80E4 3A1390 LDA WAITENEMY_MAX 80E7 FE20 CPI 20 80E9 CAF380 JZ ENEMY_CHK1 80EC 3D DCR A 80ED 3D DCR A 80EE 3D DCR A 80EF 3D DCR A 80F0 321390 STA WAITENEMY_MAX 80F3 00 ENEMY_CHK1: NOP ;前線に敵がいる場合は敵の勝ち 80F4 3A1590 LDA ENEMY_MAX ;IF ENEMY_MAX=0 THEN ENEMY_APE 80F7 B7 ORA A 80F8 CA2B81 JZ ENEMY_APE 80FB 3C INR A 80FC CDD682 CALL GETCHR 80FF FE20 CPI 20 ;IF SCR(ENEMY_MAX+1)<>SP THEN ENEMY_VIC 8101 C24781 JNZ ENEMY_VIC ;敵の移動を行う 8104 3A1590 LDA ENEMY_MAX ;FOR I=1 TO 6 8107 B7 ORA A 8108 CA2B81 JZ ENEMY_APE 810B 321190 STA CNT1 810E 210090 LXI H,SCR00 8111 010000 LXI B,$0000 8114 4F MOV C,A 8115 09 DAD B 8116 2B DCX H 8117 44 MOV B,H 8118 4D MOV C,L 8119 23 INX H 811A 0A ENEMY_MOV: LDAX B ; SCR(#HL)=SCR(#BC) 811B 77 MOV M,A 811C 2B DCX H 811D 0B DCX B 811E 3A1190 LDA CNT1 8121 3D DCR A 8122 CA2B81 JZ ENEMY_APE 8125 321190 STA CNT1 8128 C31A81 JMP ENEMY_MOV ;NEXT ;敵発生 812B 00 ENEMY_APE: NOP 812C CDE282 CALL RAND 812F 3A1490 LDA RAND256 8132 E61F ANI 1F 8134 218098 LXI H,RNDTBL 8137 85 ADD L 8138 6F MOV L,A 8139 7E MOV A,M 813A 320090 STA SCR00 ; 813D 3A1590 LDA ENEMY_MAX ;ENEMY_MAX = ENEMY_MAX + 1 8140 3C INR A 8141 321590 STA ENEMY_MAX ; 8144 C35381 JMP ENEMY_END ;敵の勝利処理 8147 00 ENEMY_VIC: NOP 8148 3A1590 LDA ENEMY_MAX 814B FE07 CPI 07 814D C25381 JNZ ENEMY_END 8150 CD0282 CALL GAMEOVER ;敵の処理終了 8153 00 ENEMY_END: NOP 8154 C9 RET ;-------- ;キー入力 ;-------- 8155 00 KEYINP: NOP 8156 CD2302 CALL INKEY ;#A=INKEY 8159 4F MOV C,A ;#C=#A 815A 78 MOV A,B ;IF #B=FF THEN RET 815B FEFF CPI FF 815D C8 RZ 815E 79 MOV A,C ;#A=#C 815F FE03 CPI 03 ;[KEY_3] 8161 CA6A81 JZ KEYINP_UP 8164 FE15 CPI 15 ;[KEY_WRITE_INC] 8166 CA7981 JZ KEYINP_SH 8169 C9 RET ;<[KEY_3]の場合> 816A 00 KEYINP_UP: NOP 816B 210790 LXI H,SCR07 ;SCR(7)=SCR(7)+1 816E 7E MOV A,M 816F 3C INR A 8170 FE3A CPI 3A 8172 C27781 JNZ KEYINP_UP1 8175 3E30 MVI A,30 8177 77 KEYINP_UP1: MOV M,A 8178 C9 RET ;<[KEY_WRITE_INC]の場合> 8179 00 KEYINP_SH: NOP ;ミサイル発射中でないか 817A 3A1890 LDA MISL_POS ;IF MISL_POS<>0 THEN END 817D B7 ORA A 817E C2A881 JNZ KEYINP_END ; 8181 3E07 MVI A,07 8183 321190 STA CNT1 ; 8186 010000 LXI B,$0000 ; 8189 3A1590 LDA ENEMY_MAX 818C 4F MOV C,A 818D 210090 LXI H,SCR00 ;POINT=SCR00+NEMY_MAX-1 8190 09 DAD B 8191 2B DCX H 8192 3A0790 LDA SCR07 8195 BE CMP M 8196 CA9C81 JZ KEYINP_HIT 8199 C3A881 JMP KEYINP_END 819C 00 KEYINP_HIT: NOP ;#A=CHRが記録されている 819D 321990 STA MISL_CHR ;MISL_CHR=CHR番号 ;ミサイルの位置 81A0 3E08 MVI A,08 81A2 321890 STA MISL_POS ; MVI M,20 ;SCR(#HL)=SP ; LDA ENEMY_MAX ;ENEMY_MAX=ENEMY_MAX-1 ; DCR A ; STA ENEMY_MAX 81A5 C3A881 JMP KEYINP_END 81A8 C9 KEYINP_END: RET ; ;[GameOver]表示 ; 81A9 00 DISPGAMEOV: NOP 81AA 210090 LXI H,SCR00 81AD 3618 MVI M,18 ;G 81AF 23 INX H 81B0 3619 MVI M,19 ;A 81B2 23 INX H 81B3 361A MVI M,1A ;M 81B5 23 INX H 81B6 361B MVI M,1B ;E 81B8 23 INX H 81B9 361C MVI M,1C ;O 81BB 23 INX H 81BC 361D MVI M,1D ;V 81BE 23 INX H 81BF 361B MVI M,1B ;E 81C1 23 INX H 81C2 361E MVI M,1E ;R 81C4 23 INX H 81C5 CDB282 CALL DISPALL 81C8 C9 RET ; ;点数表示 ; 81C9 00 POINT: NOP ;スクリーンの初期化 81CA 3E20 MVI A,20 81CC CD6C82 CALL FULLSCR ;10進表示処理 ;[100桁] 81CF 0E30 MVI C,30 81D1 3A1A90 LDA SCORE 81D4 FE64 POINT1: CPI 64 81D6 DADF81 JC POINT2 81D9 0C INR C 81DA D664 SUI 64 81DC C3D481 JMP POINT1 ; 81DF 00 POINT2: NOP ;100桁に表示 81E0 210590 LXI H,SCR05 81E3 71 MOV M,C ; ;[10桁] 81E4 0E30 MVI C,30 81E6 FE0A POINT3: CPI 0A 81E8 DAF181 JC POINT4 81EB 0C INR C 81EC D60A SUI 0A 81EE C3E681 JMP POINT3 ; 81F1 00 POINT4: NOP ;10桁に表示 81F2 210690 LXI H,SCR06 81F5 71 MOV M,C ; ;[1桁] 81F6 0E30 MVI C,30 81F8 81 ADD C 81F9 4F MOV C,A ;1桁に表示 81FA 210790 LXI H,SCR07 81FD 71 MOV M,C 81FE CDB282 POINT_END: CALL DISPALL 8201 C9 RET ; ;GAME OVER 処理 ; 8202 00 GAMEOVER: NOP ;自機破壊表現 8203 3E10 MVI A,10 8205 CD6C82 CALL FULLSCR 8208 CD9C82 CALL WAIT500 820B 3E11 MVI A,11 820D CD6C82 CALL FULLSCR 8210 CD9C82 CALL WAIT500 8213 3E12 MVI A,12 8215 CD6C82 CALL FULLSCR 8218 CD9C82 CALL WAIT500 821B 3E13 MVI A,13 821D CD6C82 CALL FULLSCR 8220 CD9C82 CALL WAIT500 8223 3E05 MVI A,05 8225 00 GAMEOVER1: NOP 8226 F5 PUSH PSW 8227 3E10 MVI A,10 ;_ 8229 CD6C82 CALL FULLSCR 822C CDEF02 CALL WAIT27 822F 3E16 MVI A,16 ;u 8231 CD6C82 CALL FULLSCR 8234 CDEF02 CALL WAIT27 8237 3E17 MVI A,17 ;U 8239 CD6C82 CALL FULLSCR 823C CDEF02 CALL WAIT27 823F 3E16 MVI A,16 ;u 8241 CD6C82 CALL FULLSCR 8244 CDEF02 CALL WAIT27 8247 F1 POP PSW 8248 3D DCR A 8249 C22582 JNZ GAMEOVER1 824C 00 GAMEOVER2: NOP ;[GAME OVER]表示 824D CDA981 CALL DISPGAMEOV ;時間待ち 8250 CD8982 CALL WAIT5000 ;キーチェック 8253 78 MOV A,B 8254 FEFF CPI FF 8256 C26882 JNZ GAMEOVER_END ;点数表示 8259 CDC981 CALL POINT ;時間待ち 825C CD8982 CALL WAIT5000 ;キーチェック 825F 78 MOV A,B 8260 FEFF CPI FF 8262 C26882 JNZ GAMEOVER_END 8265 C34C82 JMP GAMEOVER2 8268 00 GAMEOVER_END:NOP ;何から何までリセット 8269 C30080 JMP $8000 826C 00 FULLSCR: NOP 826D 320090 STA SCR00 8270 320190 STA SCR01 8273 320290 STA SCR02 8276 320390 STA SCR03 8279 320490 STA SCR04 827C 320590 STA SCR05 827F 320690 STA SCR06 8282 320790 STA SCR07 8285 CDB282 CALL DISPALL 8288 C9 RET 8289 00 WAIT5000: NOP 828A 160A MVI D,0A ;#D=10 828C D5 WAIT5000_1: PUSH D ;時間待ち 828D CD9C82 CALL WAIT500 8290 D1 POP D ;キー入力ありか 8291 78 MOV A,B ;IF #B=FF THEN RETURN 8292 FEFF CPI FF 8294 C0 RNZ 8295 15 DCR D ;#D = #D - 1 8296 7A MOV A,D ;IF #D<>0 THEN WAIT5000_1 8297 B7 ORA A 8298 C28C82 JNZ WAIT5000_1 829B C9 RET 829C 00 WAIT500: NOP 829D 160A MVI D,0A ;#D=10 829F D5 WAIT500_1: PUSH D ;時間待ち 82A0 CDEF02 CALL WAIT27 ;キー入力 82A3 CD2302 CALL INKEY 82A6 D1 POP D ;キー入力ありか 82A7 78 MOV A,B ;IF #B=FF THEN RETURN 82A8 FEFF CPI FF 82AA C0 RNZ 82AB 15 DCR D ;#D = #D - 1 82AC 7A MOV A,D ;IF #D<>0 THEN WAIT500_1 82AD B7 ORA A 82AE C29F82 JNZ WAIT500_1 82B1 C9 RET ; ;画面表示を行います ; 82B2 00 DISPALL: NOP 82B3 3E08 MVI A,08 ;CNT1=8 82B5 321190 STA CNT1 82B8 010090 LXI B,SCR00 ;#BC=SCR00 82BB 11F883 LXI D,DP1 ;#DE=DP1 82BE 0A DISPAL1: LDAX B ;#A=SCR00(n) 82BF 210098 LXI H,CHRTBL ;DP1(n) = CHRTBL(chr) 82C2 85 ADD L 82C3 6F MOV L,A 82C4 7E MOV A,M ; LDA DISP_CNT ; ORA A ; JZ DISPAL2 ; MVI A,00 ; STA DISP_CNT ; JMP DISPAL3 82C5 7E DISPAL2: MOV A,M 82C6 12 DISPAL3: STAX D 82C7 03 INX B ;#BC=#BC+1 82C8 13 INX D ;#DE=#DE+1 82C9 3A1190 LDA CNT1 ;CNT1=CNT1+1 82CC 3C INR A 82CD 321190 STA CNT1 82D0 FE00 CPI 00 ;IF CNT1<>0 THEN DISPAL1 82D2 C2BE82 JNZ DISPAL1 82D5 C9 RET ; ;指定位置(#A)のキャラクタを取得(#A)します ; 82D6 00 GETCHR: NOP 82D7 010000 LXI B,$0000 82DA 4F MOV C,A 82DB 210090 LXI H,SCR00 82DE 09 DAD B 82DF 2B DCX H 82E0 7E MOV A,M 82E1 C9 RET ; ;乱数を発生します ; 82E2 00 RAND: NOP 82E3 3A1490 LDA RAND256 82E6 47 MOV B,A 82E7 07 RLC 82E8 E6FE ANI FE 82EA 07 RLC 82EB E6FE ANI FE 82ED 07 RLC 82EE E6FE ANI FE 82F0 80 ADD B 82F1 80 ADD B 82F2 80 ADD B 82F3 80 ADD B 82F4 80 ADD B 82F5 C605 ADI 05 82F7 321490 STA RAND256 82FA C9 RET ;=================== 未作成 START ==================================== ;掛算処理を行います ;※未作成 82FB 00 MULT: NOP ; A x A ; 1010 ; x 1010 ; -------- ; 1010 ; 1010 ; -------- ; 1100100 ; =64h - 100 ; ;#HL = #B x #C 82FC 210000 LXI H,$0000 82FF 110000 LXI D,$0000 ;#DE=#B 8302 58 MOV E,B 8303 00 MULT1: NOP 8304 79 MOV A,C 8305 E601 ANI 01 8307 CA0B83 JZ MULT2 ;IF Bit0=0 THEN MULT2 ; 830A 19 DAD D ;#HL=#HL+#DE ; 830B 00 MULT2: NOP 830C 79 MOV A,C ;#C= 76543210 -> 1Bit 830D 0F RRC 830E 4F MOV C,A 830F B7 ORA A ;IF #C=0 THEN END 8310 E5 PUSH H ;#DE= <- 1Bit 8311 29 DAD H 8312 62 MOV H,D 8313 6B MOV L,E 8314 E1 POP H 8315 C30383 JMP MULT1 ; 8318 00 MULT_END: NOP 8319 C9 RET ;割算の処理を行います ;※未作成 ;#HL=#BC / #A 831A 00 DIV: NOP ; _________ ; 1100) 0111000 ; 831B 210000 LXI H,$0000 831E 67 MOV H,A 831F 00 DIV1: NOP ;HLとBCを比較 8320 00 HLCPBC: NOP 8321 78 MOV A,B 8322 BC CMP H 8323 CA2783 JZ HLCPBC_HS ;IF #H=#B THEN HLCPBC_HS 8326 C9 RET 8327 00 HLCPBC_HS: NOP 8328 79 MOV A,C 8329 BD CMP L 832A C9 RET ;================== 未作成 END ===================================== ORG $9800 ;下位のみの演算しか行ってないので[XX00]なければならない 9800 00 CHRTBL: DB 00;00 9801 00 DB 00;01 9802 00 DB 00;02 9803 00 DB 00;03 9804 00 DB 00;04 9805 00 DB 00;05 9806 00 DB 00;06 9807 00 DB 00;07 9808 00 DB 00;08 9809 00 DB 00;09 980A 00 DB 00;0A 980B 00 DB 00;0B 980C 00 DB 00;0C 980D 00 DB 00;0D 980E 00 DB 00;0E 980F 00 DB 00;0F 9810 08 DB 08;10 _ 9811 5C DB 5C;11 o 9812 7E DB 7E;12 V 9813 3F DB 3F;13 O 9814 5E DB 5E;14 9815 7C DB 7C;15 9816 1C DB 1C;16 u 9817 3E DB 3E;17 U 9818 3D DB 3D;18 G 9819 77 DB 77;19 A 981A 37 DB 37;1A M 981B 79 DB 79;1B E 981C 3F DB 3F;1C O 981D 3E DB 3E;1D V 981E 77 DB 77;1E R 981F 00 DB 00;1F 9820 00 DB 00;20 9821 00 DB 00;21 9822 00 DB 00;22 9823 00 DB 00;23 9824 00 DB 00;24 9825 00 DB 00;25 9826 00 DB 00;26 9827 00 DB 00;27 9828 00 DB 00;28 9829 00 DB 00;29 982A 00 DB 00;2A 982B 00 DB 00;2B 982C 00 DB 00;2C 982D 00 DB 00;2D 982E 00 DB 00;2E 982F 00 DB 00;2F 9830 3F DB 3F;30 '0' 9831 06 DB 06;31 '1' 9832 5B DB 5B;32 '2' 9833 4F DB 4F;33 '3' 9834 66 DB 66;34 '4' 9835 6D DB 6D;35 '5' 9836 7D DB 7D;36 '6' 9837 27 DB 27;37 '7' 9838 7F DB 7F;38 '8' 9839 6F DB 6F;39 '9' 983A 00 DB 00;3A 983B 00 DB 00;3B 983C 00 DB 00;3C 983D 00 DB 00;3D 983E 00 DB 00;3E 983F 00 DB 00;3F 9840 00 DB 00;40 9841 00 DB 00;41 9842 00 DB 00;42 9843 00 DB 00;43 9844 00 DB 00;44 9845 00 DB 00;45 9846 00 DB 00;46 9847 00 DB 00;47 9848 00 DB 00;48 9849 00 DB 00;49 984A 00 DB 00;4A 984B 00 DB 00;4B 984C 00 DB 00;4C 984D 00 DB 00;4D 984E 00 DB 00;4E 984F 00 DB 00;4F 9850 00 DB 00;50 9851 00 DB 00;51 9852 00 DB 00;52 9853 00 DB 00;53 9854 00 DB 00;54 9855 00 DB 00;55 9856 00 DB 00;56 9857 00 DB 00;57 9858 00 DB 00;58 9859 00 DB 00;59 985A 00 DB 00;5A 985B 00 DB 00;5B 985C 00 DB 00;5C 985D 00 DB 00;5D 985E 00 DB 00;5E 985F 00 DB 00;5F 9860 00 DB 00;60 9861 00 DB 00;61 9862 00 DB 00;62 9863 00 DB 00;63 9864 00 DB 00;64 9865 00 DB 00;65 9866 00 DB 00;66 9867 00 DB 00;67 9868 00 DB 00;68 9869 00 DB 00;69 986A 00 DB 00;6A 986B 00 DB 00;6B 986C 00 DB 00;6C 986D 00 DB 00;6D 986E 00 DB 00;6E 986F 00 DB 00;6F 9870 00 DB 00;70 9871 00 DB 00;71 9872 00 DB 00;72 9873 00 DB 00;73 9874 00 DB 00;74 9875 00 DB 00;75 9876 00 DB 00;76 9877 00 DB 00;77 9878 00 DB 00;78 9879 00 DB 00;79 987A 00 DB 00;7A 987B 00 DB 00;7B 987C 00 DB 00;7C 987D 00 DB 00;7D 987E 00 DB 00;7E 987F 00 DB 00;7F 9880 30 RNDTBL: DB 30;00 9881 31 DB 31;01 9882 32 DB 32;02 9883 33 DB 33;03 9884 34 DB 34;04 9885 35 DB 35;05 9886 36 DB 36;06 9887 37 DB 37;07 9888 38 DB 38;08 9889 39 DB 39;09 988A 30 DB 30;10 988B 31 DB 31;11 988C 32 DB 32;12 988D 33 DB 33;13 988E 34 DB 34;14 988F 35 DB 35;15 9890 36 DB 36;16 9891 37 DB 37;17 9892 38 DB 38;18 9893 39 DB 39;19 9894 30 DB 30;10 9895 31 DB 31;11 9896 32 DB 32;12 9897 33 DB 33;13 9898 34 DB 34;14 9899 35 DB 35;15 989A 36 DB 36;16 989B 37 DB 37;17 989C 38 DB 38;18 989D 39 DB 39;19 989E 30 DB 30;20 989F 31 DB 31;21 98A0 32 DB 32;22 98A1 33 DB 33;23 98A2 34 DB 34;24 98A3 35 DB 35;25 98A4 36 DB 36;26 98A5 37 DB 37;27 98A6 38 DB 38;28 98A7 39 DB 39;29 98A8 30 DB 30;30 98A9 31 DB 31;31 ;END CHRTBL =9800 CNT1 =9011 DISPAL1 =82BE DISPAL2 =82C5 DISPAL3 =82C6 DISPALL =82B2 DISPGAMEOV =81A9 DISP_CNT =901B DIV =831A DIV1 =831F DP1 =83F8 ENEMY =80CC ENEMY_APE =812B ENEMY_CHK =80DE ENEMY_CHK1 =80F3 ENEMY_END =8153 ENEMY_MAX =9015 ENEMY_MOV =811A ENEMY_VIC =8147 FULLSCR =826C GAMEOVER =8202 GAMEOVER1 =8225 GAMEOVER2 =824C GAMEOVER_END =8268 GETCHR =82D6 HLCPBC =8320 HLCPBC_HS =8327 INKEY =0223 INPUT =0216 KEYINP =8155 KEYINP_END =81A8 KEYINP_HIT =819C KEYINP_SH =8179 KEYINP_UP =816A KEYINP_UP1 =8177 MAIN =8039 MISL =8049 MISL_CHK =8062 MISL_CHK1 =807B MISL_CHR =9019 MISL_CLEAR =80C2 MISL_END =80CB MISL_EXPL =80AD MISL_MOV =8095 MISL_POS =9018 MULT =82FB MULT1 =8303 MULT2 =830B MULT_END =8318 POINT =81C9 POINT1 =81D4 POINT2 =81DF POINT3 =81E6 POINT4 =81F1 POINT_END =81FE RAND =82E2 RAND256 =9014 RNDTBL =9880 SCORE =901A SCR00 =9000 SCR01 =9001 SCR02 =9002 SCR03 =9003 SCR04 =9004 SCR05 =9005 SCR06 =9006 SCR07 =9007 START =8000 START1 =800A WAIT27 =02EF WAIT500 =829C WAIT5000 =8289 WAIT5000_1 =828C WAIT500_1 =829F WAITCNT =9010 WAITENEMY_CNT=9012 WAITENEMY_MAX=9013 WAITMISL_CNT =9016 WAITMISL_MAX =9017 |
途中「未完成」のコメントがついているところがあります。
なかなかむつかしいとは思いますが、皆様もぜひ挑戦して未完成のところを補完してみられたらいかがでしょうか?
とてもよい勉強になると思います。
下にソースプログラムリストも掲載します。
下のリスト部分をコピーしてテキストエディタに貼り付けて保存したあと、ND8080組立キットやND80Z3.5組立キットに付属の8080アセンブラ(ASM80.COM)でアセンブルすると、ND8080で実行できるマシン語プログラムが作成されます。
Windowsのメモ帳(notepad)は文字化けの可能性があってお勧めできません。
フリーソフトの「TeraPad」がお勧めです。
ND8080だけではなくてND80Z3.5(ND80ZV)でも実行できます。
いずれの場合にも「TK−80モニタ」モードで実行します。
ORG $8000 DP1=$83F8 WAIT27=$02EF INKEY=$0223 INPUT=$0216 SCR00=$9000 SCR01=$9001 SCR02=$9002 SCR03=$9003 SCR04=$9004 SCR05=$9005 SCR06=$9006 SCR07=$9007 WAITCNT=$9010 CNT1=$9011 WAITENEMY_CNT=$9012 WAITENEMY_MAX=$9013 RAND256=$9014 ENEMY_MAX=$9015 WAITMISL_CNT=$9016 WAITMISL_MAX=$9017 MISL_POS=$9018 MISL_CHR=$9019 SCORE=$901A DISP_CNT=$901B START: NOP ;スタックの初期化 LXI H,$FFFF SPHL ;画面エリアの初期化 MVI A,08 ;Screen Clear LXI H,SCR00 ;SCR(1-8)=SP START1: MVI M,20 INX H DCR A JNZ START1 ;自機の初期化 LXI H,SCR07 ;SCR(7)='0' MVI M,30 ;敵の移動速度の初期化 LXI H,WAITENEMY_CNT ;WAITENEMY_CNT=0 MVI M,00 LXI H,WAITENEMY_MAX ;WAITENEMY_MAX=80 MVI M,F0 ;敵の前線位置の初期化 LXI H,ENEMY_MAX ;ENEMY_MAX=0 MVI M,00 ;ミサイルの移動速度の初期化 LXI H,WAITMISL_CNT MVI M,00 LXI H,WAITMISL_MAX MVI M,10 ;ミサイルの位置の初期化 LXI H,MISL_POS MVI M,00 ;スコア LXI H,SCORE MVI M,00 ;------ ;メイン ;------ MAIN: NOP CALL MISL CALL ENEMY CALL KEYINP CALL DISPALL JMP MAIN ;------------------ ;ミサイルの移動処理 ;------------------ MISL: NOP ;ミサイルが発射されたか LDA MISL_POS ;IF MISL_POS=0 THEN MISL_END ORA A JZ MISL_END ;待ち時間内か調べる LXI H,WAITMISL_MAX LDA WAITMISL_CNT INR A CMP M STA WAITMISL_CNT JZ MISL_CHK ;IF WAITMISL_CNT = WAITMISL_MAX THEN MISL_END JMP MISL_END MISL_CHK: NOP ;初期化 MVI A,00 STA WAITMISL_CNT ;ミサイル表示を消す LDA MISL_POS CPI 08 JZ MISL_CHK1 LXI B,$0000 ;DSP(POS)=SP MOV C,A LXI H,SCR00 DAD B DCX H MVI M,20 ;ミサイル移動(仮) MISL_CHK1: LDA MISL_POS ;#A=MISL_POS-1 DCR A ;左端でないか ORA A ;IF #A=0 THEN MISL_CLEAR JZ MISL_CLEAR ;移動先に敵がいないか :IF DSP(POS-1)<>ENEMY THEN MISL_MOV LXI B,$0000 MOV C,A LXI H,SCR00 DAD B DCX H MOV A,M CPI 20 JZ MISL_MOV JMP MISL_EXPL ;IF DSP(POS-1)=ENEMY THEN MISL_EXPL MISL_MOV: NOP ;ミサイルを1コマ左移動 LDA MISL_POS ;MISL_POS=MISL_POS-1 DCR A STA MISL_POS ;ミサイルの表示 LXI B,$0000 ;DSP(MISL_POS)=MISSILE MOV C,A LXI H,SCR00 DAD B DCX H LDA MISL_CHR MOV M,A ;処理終了 JMP MISL_END ;GOTO MISL_END MISL_EXPL: NOP ;敵爆破 ;画面クリア MVI A,20 MOV M,A ;敵1機消滅 LDA ENEMY_MAX DCR A STA ENEMY_MAX ;得点 LDA SCORE INR A STA SCORE ;ミサイルクリア JMP MISL_CLEAR MISL_CLEAR: NOP ;ミサイルをクリア MVI A,00 ;MISL_POS=0 STA MISL_POS ;ミサイルをセット ; LDA MISL_CHR ; STA SCR07 ;処理終了 JMP MISL_END MISL_END: RET ;------------------ ;敵の発生と移動処理 ;------------------ ;待ち時間内か調べる ENEMY: NOP LXI H,WAITENEMY_MAX LDA WAITENEMY_CNT INR A CMP M JZ ENEMY_CHK ;IF WAITENEMY_CNT = WAITENEMY_MAX THEN ENEMY_CHK STA WAITENEMY_CNT JMP ENEMY_END ;敵の勝利確認を行う ENEMY_CHK: NOP ;初期化 MVI A,00 ;WAITENEMY_CNT=0 STA WAITENEMY_CNT ;早くする LDA WAITENEMY_MAX CPI 20 JZ ENEMY_CHK1 DCR A DCR A DCR A DCR A STA WAITENEMY_MAX ENEMY_CHK1: NOP ;前線に敵がいる場合は敵の勝ち LDA ENEMY_MAX ;IF ENEMY_MAX=0 THEN ENEMY_APE ORA A JZ ENEMY_APE INR A CALL GETCHR CPI 20 ;IF SCR(ENEMY_MAX+1)<>SP THEN ENEMY_VIC JNZ ENEMY_VIC ;敵の移動を行う LDA ENEMY_MAX ;FOR I=1 TO 6 ORA A JZ ENEMY_APE STA CNT1 LXI H,SCR00 LXI B,$0000 MOV C,A DAD B DCX H MOV B,H MOV C,L INX H ENEMY_MOV: LDAX B ; SCR(#HL)=SCR(#BC) MOV M,A DCX H DCX B LDA CNT1 DCR A JZ ENEMY_APE STA CNT1 JMP ENEMY_MOV ;NEXT ;敵発生 ENEMY_APE: NOP CALL RAND LDA RAND256 ANI 1F LXI H,RNDTBL ADD L MOV L,A MOV A,M STA SCR00 ; LDA ENEMY_MAX ;ENEMY_MAX = ENEMY_MAX + 1 INR A STA ENEMY_MAX ; JMP ENEMY_END ;敵の勝利処理 ENEMY_VIC: NOP LDA ENEMY_MAX CPI 07 JNZ ENEMY_END CALL GAMEOVER ;敵の処理終了 ENEMY_END: NOP RET ;-------- ;キー入力 ;-------- KEYINP: NOP CALL INKEY ;#A=INKEY MOV C,A ;#C=#A MOV A,B ;IF #B=FF THEN RET CPI FF RZ MOV A,C ;#A=#C CPI 03 ;[KEY_3] JZ KEYINP_UP CPI 15 ;[KEY_WRITE_INC] JZ KEYINP_SH RET ;<[KEY_3]の場合> KEYINP_UP: NOP LXI H,SCR07 ;SCR(7)=SCR(7)+1 MOV A,M INR A CPI 3A JNZ KEYINP_UP1 MVI A,30 KEYINP_UP1: MOV M,A RET ;<[KEY_WRITE_INC]の場合> KEYINP_SH: NOP ;ミサイル発射中でないか LDA MISL_POS ;IF MISL_POS<>0 THEN END ORA A JNZ KEYINP_END ; MVI A,07 STA CNT1 ; LXI B,$0000 ; LDA ENEMY_MAX MOV C,A LXI H,SCR00 ;POINT=SCR00+NEMY_MAX-1 DAD B DCX H LDA SCR07 CMP M JZ KEYINP_HIT JMP KEYINP_END KEYINP_HIT: NOP ;#A=CHRが記録されている STA MISL_CHR ;MISL_CHR=CHR番号 ;ミサイルの位置 MVI A,08 STA MISL_POS ; MVI M,20 ;SCR(#HL)=SP ; LDA ENEMY_MAX ;ENEMY_MAX=ENEMY_MAX-1 ; DCR A ; STA ENEMY_MAX JMP KEYINP_END KEYINP_END: RET ; ;[GameOver]表示 ; DISPGAMEOV: NOP LXI H,SCR00 MVI M,18 ;G INX H MVI M,19 ;A INX H MVI M,1A ;M INX H MVI M,1B ;E INX H MVI M,1C ;O INX H MVI M,1D ;V INX H MVI M,1B ;E INX H MVI M,1E ;R INX H CALL DISPALL RET ; ;点数表示 ; POINT: NOP ;スクリーンの初期化 MVI A,20 CALL FULLSCR ;10進表示処理 ;[100桁] MVI C,30 LDA SCORE POINT1: CPI 64 JC POINT2 INR C SUI 64 JMP POINT1 ; POINT2: NOP ;100桁に表示 LXI H,SCR05 MOV M,C ; ;[10桁] MVI C,30 POINT3: CPI 0A JC POINT4 INR C SUI 0A JMP POINT3 ; POINT4: NOP ;10桁に表示 LXI H,SCR06 MOV M,C ; ;[1桁] MVI C,30 ADD C MOV C,A ;1桁に表示 LXI H,SCR07 MOV M,C POINT_END: CALL DISPALL RET ; ;GAME OVER 処理 ; GAMEOVER: NOP ;自機破壊表現 MVI A,10 CALL FULLSCR CALL WAIT500 MVI A,11 CALL FULLSCR CALL WAIT500 MVI A,12 CALL FULLSCR CALL WAIT500 MVI A,13 CALL FULLSCR CALL WAIT500 MVI A,05 GAMEOVER1: NOP PUSH PSW MVI A,10 ;_ CALL FULLSCR CALL WAIT27 MVI A,16 ;u CALL FULLSCR CALL WAIT27 MVI A,17 ;U CALL FULLSCR CALL WAIT27 MVI A,16 ;u CALL FULLSCR CALL WAIT27 POP PSW DCR A JNZ GAMEOVER1 GAMEOVER2: NOP ;[GAME OVER]表示 CALL DISPGAMEOV ;時間待ち CALL WAIT5000 ;キーチェック MOV A,B CPI FF JNZ GAMEOVER_END ;点数表示 CALL POINT ;時間待ち CALL WAIT5000 ;キーチェック MOV A,B CPI FF JNZ GAMEOVER_END JMP GAMEOVER2 GAMEOVER_END:NOP ;何から何までリセット JMP $8000 FULLSCR: NOP STA SCR00 STA SCR01 STA SCR02 STA SCR03 STA SCR04 STA SCR05 STA SCR06 STA SCR07 CALL DISPALL RET WAIT5000: NOP MVI D,0A ;#D=10 WAIT5000_1: PUSH D ;時間待ち CALL WAIT500 POP D ;キー入力ありか MOV A,B ;IF #B=FF THEN RETURN CPI FF RNZ DCR D ;#D = #D - 1 MOV A,D ;IF #D<>0 THEN WAIT5000_1 ORA A JNZ WAIT5000_1 RET WAIT500: NOP MVI D,0A ;#D=10 WAIT500_1: PUSH D ;時間待ち CALL WAIT27 ;キー入力 CALL INKEY POP D ;キー入力ありか MOV A,B ;IF #B=FF THEN RETURN CPI FF RNZ DCR D ;#D = #D - 1 MOV A,D ;IF #D<>0 THEN WAIT500_1 ORA A JNZ WAIT500_1 RET ; ;画面表示を行います ; DISPALL: NOP MVI A,08 ;CNT1=8 STA CNT1 LXI B,SCR00 ;#BC=SCR00 LXI D,DP1 ;#DE=DP1 DISPAL1: LDAX B ;#A=SCR00(n) LXI H,CHRTBL ;DP1(n) = CHRTBL(chr) ADD L MOV L,A MOV A,M ; LDA DISP_CNT ; ORA A ; JZ DISPAL2 ; MVI A,00 ; STA DISP_CNT ; JMP DISPAL3 DISPAL2: MOV A,M DISPAL3: STAX D INX B ;#BC=#BC+1 INX D ;#DE=#DE+1 LDA CNT1 ;CNT1=CNT1+1 INR A STA CNT1 CPI 00 ;IF CNT1<>0 THEN DISPAL1 JNZ DISPAL1 RET ; ;指定位置(#A)のキャラクタを取得(#A)します ; GETCHR: NOP LXI B,$0000 MOV C,A LXI H,SCR00 DAD B DCX H MOV A,M RET ; ;乱数を発生します ; RAND: NOP LDA RAND256 MOV B,A RLC ANI FE RLC ANI FE RLC ANI FE ADD B ADD B ADD B ADD B ADD B ADI 05 STA RAND256 RET ;=================== 未作成 START ==================================== ;掛算処理を行います ;※未作成 MULT: NOP ; A x A ; 1010 ; x 1010 ; -------- ; 1010 ; 1010 ; -------- ; 1100100 ; =64h - 100 ; ;#HL = #B x #C LXI H,$0000 LXI D,$0000 ;#DE=#B MOV E,B MULT1: NOP MOV A,C ANI 01 JZ MULT2 ;IF Bit0=0 THEN MULT2 ; DAD D ;#HL=#HL+#DE ; MULT2: NOP MOV A,C ;#C= 76543210 -> 1Bit RRC MOV C,A ORA A ;IF #C=0 THEN END PUSH H ;#DE= <- 1Bit DAD H MOV H,D MOV L,E POP H JMP MULT1 ; MULT_END: NOP RET ;割算の処理を行います ;※未作成 ;#HL=#BC / #A DIV: NOP ; _________ ; 1100) 0111000 ; LXI H,$0000 MOV H,A DIV1: NOP ;HLとBCを比較 HLCPBC: NOP MOV A,B CMP H JZ HLCPBC_HS ;IF #H=#B THEN HLCPBC_HS RET HLCPBC_HS: NOP MOV A,C CMP L RET ;================== 未作成 END ===================================== ORG $9800 ;下位のみの演算しか行ってないので[XX00]なければならない CHRTBL: DB 00;00 DB 00;01 DB 00;02 DB 00;03 DB 00;04 DB 00;05 DB 00;06 DB 00;07 DB 00;08 DB 00;09 DB 00;0A DB 00;0B DB 00;0C DB 00;0D DB 00;0E DB 00;0F DB 08;10 _ DB 5C;11 o DB 7E;12 V DB 3F;13 O DB 5E;14 DB 7C;15 DB 1C;16 u DB 3E;17 U DB 3D;18 G DB 77;19 A DB 37;1A M DB 79;1B E DB 3F;1C O DB 3E;1D V DB 77;1E R DB 00;1F DB 00;20 DB 00;21 DB 00;22 DB 00;23 DB 00;24 DB 00;25 DB 00;26 DB 00;27 DB 00;28 DB 00;29 DB 00;2A DB 00;2B DB 00;2C DB 00;2D DB 00;2E DB 00;2F DB 3F;30 '0' DB 06;31 '1' DB 5B;32 '2' DB 4F;33 '3' DB 66;34 '4' DB 6D;35 '5' DB 7D;36 '6' DB 27;37 '7' DB 7F;38 '8' DB 6F;39 '9' DB 00;3A DB 00;3B DB 00;3C DB 00;3D DB 00;3E DB 00;3F DB 00;40 DB 00;41 DB 00;42 DB 00;43 DB 00;44 DB 00;45 DB 00;46 DB 00;47 DB 00;48 DB 00;49 DB 00;4A DB 00;4B DB 00;4C DB 00;4D DB 00;4E DB 00;4F DB 00;50 DB 00;51 DB 00;52 DB 00;53 DB 00;54 DB 00;55 DB 00;56 DB 00;57 DB 00;58 DB 00;59 DB 00;5A DB 00;5B DB 00;5C DB 00;5D DB 00;5E DB 00;5F DB 00;60 DB 00;61 DB 00;62 DB 00;63 DB 00;64 DB 00;65 DB 00;66 DB 00;67 DB 00;68 DB 00;69 DB 00;6A DB 00;6B DB 00;6C DB 00;6D DB 00;6E DB 00;6F DB 00;70 DB 00;71 DB 00;72 DB 00;73 DB 00;74 DB 00;75 DB 00;76 DB 00;77 DB 00;78 DB 00;79 DB 00;7A DB 00;7B DB 00;7C DB 00;7D DB 00;7E DB 00;7F RNDTBL: DB 30;00 DB 31;01 DB 32;02 DB 33;03 DB 34;04 DB 35;05 DB 36;06 DB 37;07 DB 38;08 DB 39;09 DB 30;10 DB 31;11 DB 32;12 DB 33;13 DB 34;14 DB 35;15 DB 36;16 DB 37;17 DB 38;18 DB 39;19 DB 30;10 DB 31;11 DB 32;12 DB 33;13 DB 34;14 DB 35;15 DB 36;16 DB 37;17 DB 38;18 DB 39;19 DB 30;20 DB 31;21 DB 32;22 DB 33;23 DB 34;24 DB 35;25 DB 36;26 DB 37;27 DB 38;28 DB 39;29 DB 30;30 DB 31;31 ;END |
とても楽しく、参考になるプログラムをお送りいただき、公開をご快諾いただいた、熊本県のK様に厚く御礼申し上げます。
今後ともよろしくお願いいたします。
8080マイコンをつくろう![第43回]
2017.2.6upload
前へ
ホームページトップへ戻る