SNOBOL言語で8080アセンブラ
2018年4月、歴史的に貴重なDEC社 TOPS-20のSNOBOL言語で8080アセンブラ(ASM80.SNO)を作成しました。このブログでは、ASM80.SNOのテスト編を書きます。
ASM80.SNOの設計編とコード編は、下記ブログを参照してください。
8080の命令コード
昔 TK-80トレーニングキットで趣味のプログラミングしていた頃、命令コード表を見ながらハンドアセンブルしていました。
8080命令セットは、下記ブログを参照してください。
以下、8080の命令コード(16進数)を示します。
8ビット転送命令
MOV命令、MVI命令、LDAX命令、STAX命令、LDA命令、STA命令の機械語命令コードを示します。
16ビット転送命令
LXI命令、MVI命令、LDLD命令、SHLD命令、SPHL命令の機械語命令コードを示します。
スタック操作命令
PUSH命令、POP命令、XTHL命令の機械語命令コードを示します。
レジスタ交換命令
XCHG命令の機械語命令コードを示します。
8ビット算術演算命令
ADD命令、ADC命令、SUB命令、SBB命令、ADI命令、ACI命令、SUI命令、SBI命令の機械語命令コードを示します。
8ビット論理演算命令
ANA命令、ORA命令、XRA命令、CMP命令、ANI命令、ORI命令、XRI命令、CPI命令の機械語命令コードを示します。
8ビット増減演算命令
INR命令、DCR命令の機械語命令コードを示します。
その他演算命令
DAA命令、CMA命令、CMC命令、STC命令の機械語命令コードを示します。
CPU制御命令
NOP命令、HLT命令、DI命令、EI命令の機械語命令コードを示します。
16ビット算術演算命令
DAD命令、INX命令、DCX命令の機械語命令コードを示します。
シフト、ローテイト命令
RLC命令、RAL命令、RRC命令、RAR命令の機械語命令コードを示します。
分岐命令
JMP命令、Jccc命令、PCHL命令の機械語命令コードを示します。
コール、リターン命令
CALL命令、Cccc命令、RET命令、Rcc命令、RST命令の機械語命令コードを示します。
入出力命令
IN命令、OUT命令の機械語命令コードを示します。
ASM80.SNOの実行
Altair 8800 simulatorでCP/Mを実行したときに使用した8080サンプルコードをASM80.SNOでアセンブルしてみます。
テスト用のサンプルコードを下記に示します。
@TYPE KEYCODE.ASM BDOS EQU 0005h ; ;--------------------------------- ORG 0100h START: MVI A,10 STA COUNT LOOP: CALL CONINP ; CON Input PUSH PSW LXI D,MSGKEY CALL STROUT ; String Out POP PSW ; LXI H,OUTBUF CALL CV8BIT ; LXI D,OUTBUF CALL STROUT ; String Out ; LDA COUNT DCR A STA COUNT JNZ LOOP ; RET ; return CP/M ;---------------------------------------- COUNT: DB 0 ; MSGKEY: ; ' KEY -> $' DB 20h DB 4Bh DB 45h DB 59h DB 20h DB 2Dh DB 3Eh DB 20h DB 24h OUTBUF: ; 'XX',0Dh,0Ah,'$' DB 58h DB 58h DB 0Dh DB 0Ah DB 24h ; ;======================================== ; Convert A-REG Value(00-FF) to HEX Char ; (IN) A : 00-FF ; (IN) HL : Store Address ;---------------------------------------- CV8BIT: MOV B,A ; A is CODE RRC RRC RRC RRC ANI 00Fh ; A is Up 4bit CALL CV4BIT MOV M,A INX H MOV A,B ; A is CODE ANI 00Fh ; A is Lo 4bit CALL CV4BIT MOV M,A RET ;======================================== ; Convert A-REG Value(0-F) to HEX Char ; (IN) A : Low 4bit 0-F ; (OUT) A : HEX Char ;---------------------------------------- CV4BIT: CPI 0Ah JM CNVH10 ADI 07h CNVH10: ADI 30h ; A is '0'-'9' 'A'-'F' RET ;======================================== ; CONSOLE INPUT To A-REG ; (OUT) A : Console Input Char ;---------------------------------------- CONINP: MVI C,01H CALL BDOS RET ;======================================== ; CONSOLE OUTPUT From A-REG ; (IN) A : Console Output Char ;---------------------------------------- CONOUT: MVI C,02H MOV E,A CALL BDOS RET ;======================================== ; CONSOLE STRING OUTPUT From (DE) ; (IN) DE : String Address ;---------------------------------------- STROUT: MVI C,09H CALL BDOS RET ;================================ END
ASM80.SNOでアセンブルします。
@SNONBOL ASM80.SNO Input i8080 ASM Source ? KEYCODE.ASM i8080 Assembler START KEYCODE.ASM ---> KEYCODE.LST i8080 Assembler END.. KEYCODE.ASM ---> KEYCODE.LST EXIT @
アセンブル結果の.LSTを確認します。
@TYPE KEYCODE.LST BDOS EQU 0005h ; ;--------------------------------- ORG 0100h START: 0100 3E0A MVI A,10 0102 322701 STA COUNT LOOP: 0105 CD5401 CALL CONINP ; CON Input 0108 F5 PUSH PSW 0109 112801 LXI D,MSGKEY 010C CD6101 CALL STROUT ; String Out 010F F1 POP PSW ; 0110 213101 LXI H,OUTBUF 0113 CD3601 CALL CV8BIT ; 0116 113101 LXI D,OUTBUF 0119 CD6101 CALL STROUT ; String Out ; 011C 3A2701 LDA COUNT 011F 3D DCR A 0120 322701 STA COUNT 0123 C20501 JNZ LOOP ; 0126 C9 RET ; return CP/M ;---------------------------------------- 0127 00 COUNT: DB 0 ; MSGKEY: ; ' KEY -> $' 0128 20 DB 20h 0129 4B DB 4Bh 012A 45 DB 45h 012B 59 DB 59h 012C 20 DB 20h 012D 2D DB 2Dh 012E 3E DB 3Eh 012F 20 DB 20h 0130 24 DB 24h OUTBUF: ; 'XX',0Dh,0Ah,'$' 0131 58 DB 58h 0132 58 DB 58h 0133 0D DB 0Dh 0134 0A DB 0Ah 0135 24 DB 24h ; ;======================================== ; Convert A-REG Value(00-FF) to HEX Char ; (IN) A : 00-FF ; (IN) HL : Store Address ;---------------------------------------- CV8BIT: 0136 47 MOV B,A ; A is CODE 0137 0F RRC 0138 0F RRC 0139 0F RRC 013A 0F RRC 013B E60F ANI 00Fh ; A is Up 4bit 013D CD4A01 CALL CV4BIT 0140 77 MOV M,A 0141 23 INX H 0142 78 MOV A,B ; A is CODE 0143 E60F ANI 00Fh ; A is Lo 4bit 0145 CD4A01 CALL CV4BIT 0148 77 MOV M,A 0149 C9 RET ;======================================== ; Convert A-REG Value(0-F) to HEX Char ; (IN) A : Low 4bit 0-F ; (OUT) A : HEX Char ;---------------------------------------- CV4BIT: 014A FE0A CPI 0Ah 014C FA5101 JM CNVH10 014F C607 ADI 07h CNVH10: 0151 C630 ADI 30h ; A is '0'-'9' 'A'-'F' 0153 C9 RET ;======================================== ; CONSOLE INPUT To A-REG ; (OUT) A : Console Input Char ;---------------------------------------- CONINP: 0154 0E01 MVI C,01H 0156 CD0500 CALL BDOS 0159 C9 RET ;======================================== ; CONSOLE OUTPUT From A-REG ; (IN) A : Console Output Char ;---------------------------------------- CONOUT: 015A 0E02 MVI C,02H 015C 5F MOV E,A 015D CD0500 CALL BDOS 0160 C9 RET ;======================================== ; CONSOLE STRING OUTPUT From (DE) ; (IN) DE : String Address ;---------------------------------------- STROUT: 0161 0E09 MVI C,09H 0163 CD0500 CALL BDOS 0166 C9 RET ;================================ END @
オブジェクトのヘキサ表示を確認すると CP/Mでアセンブルしたものと一致しています。トイプログラムレベルですが、十分に実用的だと思います。
ASM80.SNOのテスト
8080のすべての命令コードを正しくアセンブルできるか確認しました。
テスト用のコードを T.ASMに作成して、ASM80.SNOでアセンブルしました。
@SNOBOL ASM80.SNO Input i8080 ASM Source ? T.ASM i8080 Assembler START T.ASM ---> T.LST 24 MOV B,X ; Error! Registor 34 MOV C,X ; Error! Registor 44 MOV D,X ; Error! Registor 54 MOV E,X ; Error! Registor 64 MOV H,X ; Error! Registor 74 MOV L,X ; Error! Registor 82 MOV M,M ; Error! Registor 84 MOV M,X ; Error! Registor 94 MOV A,X ; Error! Registor 104 MVI X,19 ; Error! Registor 105 MVI A,100h ; Error! Immediate 108 COUNT1: DB 0 ; Error! Duplication LABEL 113 LDAX H ; Error! Registor 116 STAX H ; Error! Registor 123 LXI X,4567H ; Error! Registor 136 PUSH S ; Error! Registor 141 POP S ; Error! Registor 154 ADD X ; Error! Registor 164 ADC X ; Error! Registor 174 SUB X ; Error! Registor 184 SBB X ; Error! Registor 203 ANA X ; Error! Registor 213 ORA X ; Error! Registor 223 XRA X ; Error! Registor 233 CMP X ; Error! Registor 252 INR X ; Error! Registor 262 DCR X ; Error! Registor 278 DAD X ; Error! Registor 284 INX X ; Error! Registor 339 RST 8 ; Error! Vec (0..7) 343 IN 100H ; Error! IO Port 344 OUT 101H ; Error! IO Port i8080 Assembler END.. T.ASM ---> T.LST EXIT @
エラーのソースコード部分を指摘するエラーメッセージを表示しました。
リストファイルで確認します。
@TYPE T.LST ; STACKSZ EQU 100h LL1 EQU 01h LL2 EQU 02h LLA EQU 0Ah LLF EQU 0Fh ;--------------------------------- ORG 0100h STKBGN: 0100 ?????? DS STACKSZ STKEND: ;* START: 0200 310002 LXI SP,STKEND ;* 0203 40 MOV B,B 0204 41 MOV B,C 0205 42 MOV B,D 0206 43 MOV B,E 0207 44 MOV B,H 0208 45 MOV B,L 0209 46 MOV B,M 020A 47 MOV B,A MOV B,X ; Error! Registor ;* 020B 48 MOV C,B 020C 49 MOV C,C 020D 4A MOV C,D 020E 4B MOV C,E 020F 4C MOV C,H 0210 4D MOV C,L 0211 4E MOV C,M 0212 4F MOV C,A MOV C,X ; Error! Registor ;* 0213 50 MOV D,B 0214 51 MOV D,C 0215 52 MOV D,D 0216 53 MOV D,E 0217 54 MOV D,H 0218 55 MOV D,L 0219 56 MOV D,M 021A 57 MOV D,A MOV D,X ; Error! Registor ;* 021B 58 MOV E,B 021C 59 MOV E,C 021D 5A MOV E,D 021E 5B MOV E,E 021F 5C MOV E,H 0220 5D MOV E,L 0221 5E MOV E,M 0222 5F MOV E,A MOV E,X ; Error! Registor ;* 0223 60 MOV H,B 0224 61 MOV H,C 0225 62 MOV H,D 0226 63 MOV H,E 0227 64 MOV H,H 0228 65 MOV H,L 0229 66 MOV H,M 022A 67 MOV H,A MOV H,X ; Error! Registor ;* 022B 68 MOV L,B 022C 69 MOV L,C 022D 6A MOV L,D 022E 6B MOV L,E 022F 6C MOV L,H 0230 6D MOV L,L 0231 6E MOV L,M 0232 6F MOV L,A MOV L,X ; Error! Registor ;* 0233 70 MOV M,B 0234 71 MOV M,C 0235 72 MOV M,D 0236 73 MOV M,E 0237 74 MOV M,H 0238 75 MOV M,L MOV M,M ; Error! Registor 0239 77 MOV M,A MOV M,X ; Error! Registor ;* 023A 78 MOV A,B 023B 79 MOV A,C 023C 7A MOV A,D 023D 7B MOV A,E 023E 7C MOV A,H 023F 7D MOV A,L 0240 7E MOV A,M 0241 7F MOV A,A MOV A,X ; Error! Registor ;* 0242 0601 MVI B,LL1 0244 0E02 MVI C,LL2 0246 160A MVI D,LLA 0248 1E0F MVI E,LLF 024A 260F MVI H,15 024C 2E10 MVI L,16 024E 3611 MVI M,17 0250 3E12 MVI A,18 MVI X,19 ; Error! Registor MVI A,100h ; Error! Immediate ;* 0252 00 COUNT1: DB 0 COUNT1: DB 0 ; Error! Duplication LABEL 0253 00 COUNT2: DB 0 ;* 0254 0A LDAX B 0255 1A LDAX D LDAX H ; Error! Registor 0256 02 STAX B 0257 12 STAX D STAX H ; Error! Registor 0258 3A5202 LDA COUNT1 025B 325302 STA COUNT2 ;* 025E 012301 LXI B,0123H 0261 113412 LXI D,1234H 0264 214523 LXI H,2345H LXI X,4567H ; Error! Registor 0267 310002 LXI SP,STKEND ;* 026A 3412 ADR1: DW 1234h 026C 0000 ADR2: DW 0 026E 2A6A02 LHLD ADR1 0271 226C02 SHLD ADR2 0274 F9 SPHL ;* 0275 C5 PUSH B 0276 D5 PUSH D 0277 E5 PUSH H 0278 F5 PUSH PSW PUSH S ; Error! Registor 0279 C1 POP B 027A D1 POP D 027B E1 POP H 027C F1 POP PSW POP S ; Error! Registor 027D E3 XTHL ;* 027E EB XCHG ;* 027F 87 ADD B 0280 87 ADD C 0281 87 ADD D 0282 87 ADD E 0283 87 ADD H 0284 87 ADD L 0285 87 ADD M 0286 87 ADD A ADD X ; Error! Registor ;* 0287 8F ADC B 0288 8F ADC C 0289 8F ADC D 028A 8F ADC E 028B 8F ADC H 028C 8F ADC L 028D 8F ADC M 028E 8F ADC A ADC X ; Error! Registor ;* 028F 97 SUB B 0290 97 SUB C 0291 97 SUB D 0292 97 SUB E 0293 97 SUB H 0294 97 SUB L 0295 97 SUB M 0296 97 SUB A SUB X ; Error! Registor ;* 0297 9F SBB B 0298 9F SBB C 0299 9F SBB D 029A 9F SBB E 029B 9F SBB H 029C 9F SBB L 029D 9F SBB M 029E 9F SBB A SBB X ; Error! Registor ;* 029F C6AF ADI AFH 02A1 CEAE ACI AEH 02A3 D6AD SUI ADH 02A5 DEAC SBI ACH 02A7 C608 ADI 1000B 02A9 CE09 ACI 1001B 02AB D60A SUI 1010B 02AD DE0B SBI 1011B ;* 02AF A7 ANA B 02B0 A7 ANA C 02B1 A7 ANA D 02B2 A7 ANA E 02B3 A7 ANA H 02B4 A7 ANA L 02B5 A7 ANA M 02B6 A7 ANA A ANA X ; Error! Registor ;* 02B7 B7 ORA B 02B8 B7 ORA C 02B9 B7 ORA D 02BA B7 ORA E 02BB B7 ORA H 02BC B7 ORA L 02BD B7 ORA M 02BE B7 ORA A ORA X ; Error! Registor ;* 02BF AF XRA B 02C0 AF XRA C 02C1 AF XRA D 02C2 AF XRA E 02C3 AF XRA H 02C4 AF XRA L 02C5 AF XRA M 02C6 AF XRA A XRA X ; Error! Registor ;* 02C7 BF CMP B 02C8 BF CMP C 02C9 BF CMP D 02CA BF CMP E 02CB BF CMP H 02CC BF CMP L 02CD BF CMP M 02CE BF CMP A CMP X ; Error! Registor ;* 02CF E6AB ANI ABH 02D1 F6A9 ORI A9H 02D3 EEAA XRI AAH 02D5 FEA8 CPI A8H 02D7 E60C ANI 1100B 02D9 F60E ORI 1110B 02DB EE0D XRI 1101B 02DD FE0F CPI 1111B ;* 02DF 3C INR B 02E0 3C INR C 02E1 3C INR D 02E2 3C INR E 02E3 3C INR H 02E4 3C INR L 02E5 3C INR M 02E6 3C INR A INR X ; Error! Registor ;* 02E7 3D DCR B 02E8 3D DCR C 02E9 3D DCR D 02EA 3D DCR E 02EB 3D DCR H 02EC 3D DCR L 02ED 3D DCR M 02EE 3D DCR A DCR X ; Error! Registor ;* 02EF 27 DAA 02F0 2F CMA 02F1 3F CMC 02F2 37 STC ;* 02F3 00 NOP 02F4 76 HLT 02F5 F3 DI 02F6 FB EI ;* 02F7 09 DAD B 02F8 19 DAD D 02F9 29 DAD H 02FA 39 DAD SP DAD X ; Error! Registor ;* 02FB 03 INX B 02FC 13 INX D 02FD 23 INX H 02FE 33 INX SP INX X ; Error! Registor ;* 02FF 0B DCX B 0300 1B DCX D 0301 2B DCX H 0302 3B DCX SP ;* 0303 07 RLC 0304 17 RAL 0305 0F RRC 0306 1F RAR ;* LOOP1: 0307 E9 PCHL LOOP2: ;* 0308 C30703 JMP LOOP1 030B C20803 JNZ LOOP2 030E CA2303 JZ NEXT 0311 D2A304 JNC 04A3H 0314 DAA405 JC 05A4H 0317 E2A506 JPO 06A5H 031A EAA607 JPE 07A6H 031D F2A708 JP 08A7H 0320 FAA809 JM 09A8H ;* NEXT: 0323 CDA90A CALL 0AA9H 0326 C4AA0B CNZ 0BAAH 0329 CCAB0C CZ 0CABH 032C D4AC0D CNC 0DACH 032F DCAD0E CC 0EADH 0332 E4AE0F CPO 0FAEH 0335 ECAF10 CPE 10AFH 0338 F4B011 CP 11B0H 033B FCB112 CM 12B1H ;* 033E C9 RET 033F C0 RNZ 0340 C8 RZ 0341 D0 RNC 0342 D8 RC 0343 E0 RPO 0344 E8 RPE 0345 F0 RP 0346 F8 RM ;* 0347 C7 RST 0 0348 CF RST 1 0349 D7 RST 2 034A DF RST 3 034B E7 RST 4 034C EF RST 5 034D F7 RST 6 034E FF RST 7 RST 8 ; Error! Vec (0..7) ;* 034F DBF0 IN F0H 0351 D3FF OUT FFH IN 100H ; Error! IO Port OUT 101H ; Error! IO Port ;* ;* 0353 00 CNT_Z: DB 0 0354 ?????? DS FFh 0453 0D DB 0Dh 0454 ???? DS 2 ; 0456 0D DB 0Dh 0457 0A DB 0Ah END ;====================================== @
命令コード表と見比べて、正しくアセンブルしていることを確認しました。
まとめ
SNOBOL言語で8080アセンブラ(ASM80.SNO)を作成しました。大学4回生のときにSNOBOLでプログラミングしてから、約41年ぶりにSNOBOLでプログラミングしました。約400ステップ規模のSNOBOLでアセンブラを記述できたのは、SNOBOLの強力なパターンマッチの威力です。