DEC社 TOPS-20のSNOBOL言語で8080アセンブラを作成(テスト編)

SNOBOL

SNOBOL

SNOBOL言語で8080アセンブラ

2018年4月、歴史的に貴重なDEC社 TOPS-20のSNOBOL言語で8080アセンブラ(ASM80.SNO)を作成しました。このブログでは、ASM80.SNOのテスト編を書きます。

ASM80 By SNOBOL

ASM80 By SNOBOL

ASM80.SNOの設計編とコード編は、下記ブログを参照してください。

DEC社 TOPS-20のSNOBOL言語で8080アセンブラを作成(設計編)

DEC社 TOPS-20のSNOBOL言語で8080アセンブラを作成(コード編)

8080の命令コード

昔 TK-80トレーニングキットで趣味のプログラミングしていた頃、命令コード表を見ながらハンドアセンブルしていました。

TK-80トレーニングキットで趣味のプログラミング

8080命令セットは、下記ブログを参照してください。

懐かしいインテル8080命令セットのメモ

以下、8080の命令コード(16進数)を示します。

 

8ビット転送命令

MOV命令、MVI命令、LDAX命令、STAX命令、LDA命令、STA命令の機械語命令コードを示します。

8080命令コード (1)

8080命令コード (1)

16ビット転送命令

LXI命令、MVI命令、LDLD命令、SHLD命令、SPHL命令の機械語命令コードを示します。

8080命令コード (2)

8080命令コード (2)

スタック操作命令

PUSH命令、POP命令、XTHL命令の機械語命令コードを示します。

8080命令コード (3)

8080命令コード (3)

レジスタ交換命令

XCHG命令の機械語命令コードを示します。

8080命令コード (4)

8080命令コード (4)

8ビット算術演算命令

ADD命令、ADC命令、SUB命令、SBB命令、ADI命令、ACI命令、SUI命令、SBI命令の機械語命令コードを示します。

8080命令コード (5)

8080命令コード (5)

8ビット論理演算命令

ANA命令、ORA命令、XRA命令、CMP命令、ANI命令、ORI命令、XRI命令、CPI命令の機械語命令コードを示します。

8080命令コード (6)

8080命令コード (6)

8ビット増減演算命令

INR命令、DCR命令の機械語命令コードを示します。

8080命令コード (7)

8080命令コード (7)

その他演算命令

DAA命令、CMA命令、CMC命令、STC命令の機械語命令コードを示します。

8080命令コード (8)

8080命令コード (8)

CPU制御命令

NOP命令、HLT命令、DI命令、EI命令の機械語命令コードを示します。

8080命令コード (9)

8080命令コード (9)

16ビット算術演算命令

DAD命令、INX命令、DCX命令の機械語命令コードを示します。

8080命令コード (10)

8080命令コード (10)

シフト、ローテイト命令

RLC命令、RAL命令、RRC命令、RAR命令の機械語命令コードを示します。

8080命令コード (11)

8080命令コード (11)

分岐命令

JMP命令、Jccc命令、PCHL命令の機械語命令コードを示します。

8080命令コード (12)

8080命令コード (12)

コール、リターン命令

CALL命令、Cccc命令、RET命令、Rcc命令、RST命令の機械語命令コードを示します。

8080命令コード (13)

8080命令コード (13)

入出力命令

IN命令、OUT命令の機械語命令コードを示します。

8080命令コード (14)

8080命令コード (14)

ASM80.SNOの実行

Altair 8800 simulatorでCP/Mを実行したときに使用した8080サンプルコードをASM80.SNOでアセンブルしてみます。

CP/Mシミュレータで懐かしのインテル8080アセンブラを使う

テスト用のサンプルコードを下記に示します。

@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の強力なパターンマッチの威力です。