CP/Mシミュレータ
2017年5月、Altair 8800 simulatorを使用して懐かしいCP/Mを使うことができました。
懐かしいインテル8080アセンブラを書いてみます。
懐かしのインテル8080アセンブラ
初めてマイクロプロセッサi8080のアセンブラを書いたのは、1976年のことです。ベンチャー企業V社でi8080との衝撃の出会いです。
趣味でも、TK-80トレーニングキットで休日にプログラミングしていました。命令コード表を参照しながらハンドアセンブルして機械語に変換していました。
最後に、8bitマイクロプロセッサZ80でプログラミングしたのは1980年代ですので、35年ぶりぐらいにインテル8080のアセンブラを書いたことになります。
当時は、オブジェクトコードを手で直接パッチを当てることをしていましたので、機械語コードを記憶するほど使い込んでいました。しかし、今では命令セットの記憶も曖昧です。命令セット表を見ながらプログラミングしてみると、なんとなく思い出しました。
プログラム仕様
キーボードから入力したキーコードを16進数で表示する。10回繰り返して終了する。
CP/Mは、ASCIIコードを採用しています。
- 数字の’0′ : 16進数で0x30
- 数字の’1′ : 16進数で0x31
- アルファベットの’A’ : 16進数で0x41
- アルファベットの’O’ : 16進数で0x4F
- アルファベットの’P’ : 16進数で0x50
プログラムコード
キーコードダンプのプログラムを下記に示します。
title 'KEY CODE DUMP' ; BDOS EQU 0005h ; ASCA EQU 'A' ASC0 EQU '0' ;--------------------------------- 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: DB ' KEY -> $' OUTBUF: DB 'XX',0Dh,0Ah,'$' ; ;======================================== ; 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 ASCA-ASC0-10 CNVH10: ADI ASC0 ; 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
キーボード入力と画面表示は、CP/M BDOSファンクションコールを使用します。
【プログラム説明】
CP/Mのプログラムは、0100hから開始します。
- 最初に、繰り返し回数 COUNT ← 10とします。
- ===LOOP===
- | コンソール文字入力(CONINP)で、Aレジスタにキーコードを入力します。
- | コンソールストリング出力(STROUT)で、MSGKEYを表示します。
- | 8bitヘキサ変換(CV8BIT)で、Aレジスタを16進数文字列に変換してOUTBUFに格納します。
- | コンソールストリング出力(STROUT)で、OUTBUFを表示します。
- 繰り返し回数 COUNT をデクリメントして、ゼロになるまで上記を繰り返します。
- 終了して、CP/Mに制御を戻します。
■ 8bitヘキサ変換(CV8BIT) :Aレジスタ[7-0]を16進数文字列変換してHLアドレスから格納
- AレジスタをBレジスタに待避します。
- Aレジスタを4回ローテイトして上位4bitと下位4bitを入れ替えます。
- 0Fhでマスクして、Aレジスタ[7-4]を下位4bitに入れます。
- 4bitヘキサ変換(CV4BIT)で16進文字列に変換して、アドレスHLに格納してHLをインクリメントします。
- AレジスタをBレジスタから元に戻します。
- 0Fhでマスクして、Aレジスタ[3-0]を下位4bitに入れます。
- 4bitヘキサ変換(CV4BIT)で16進文字列に変換して、アドレスHLに格納します。
■ 4bitヘキサ変換(CV4BIT) :Aレジスタ[3-0]を16進数文字列変換
- 00~09のとき、’0’を足します → (‘0’~’9’)
- 0A~0Fのとき、(‘A’-‘0’-10) + ‘0’を足します → (‘A’~’F’)
ASCIIコードの’0’~’9’と’A’~’F’は、連続する文字コードを割り当てていることを利用しています。
プログラムのビルド
CP/Mの8080アセンブラ ASMを使用して、ソースコード KEYCD.ASMをビルドします。拡張子 .ASM は、省略します。
asm KEYCD
ディレクトリをみると .PRNと .HEXを生成しました。
拡張子 .PRN のファイルを確認します。
type KEYCD.PRN
N title 'KEY CODE DUMP' ; 0005 = BDOS EQU 0005h ; 0041 = ASCA EQU 'A' 0030 = ASC0 EQU '0' ;--------------------------------- 0100 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: 0128 204B455920 DB ' KEY -> $' OUTBUF: 0131 58580D0A24 DB 'XX',0Dh,0Ah,'$' ; ;======================================== ; 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 ASCA-ASC0-10 CNVH10: 0151 C630 ADI ASC0 ; 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 ;================================ 0167 END
アドレスと機械語とソースコードを並べたリストファイルです。
拡張子 .HEX のファイルを確認します。
type KEYCD.HEX
:100100003E0A322701CD5401F5112801CD6101F1DC :10011000213101CD3601113101CD61013A27013D77 :10012000322701C20501C900204B4559202D3E2030 :100130002458580D0A24470F0F0F0FE60FCD4A0120 :10014000772378E60FCD4A0177C9FE0AFA5101C636 :1001500007C630C90E01CD0500C90E025FCD0500EE :07016000C90E09CD0500C91D :0000000000
機械語がインテルHEXフォーマットで記録されています。
LOADコマンドで、.HEXファイルを実行形式の .COMに変換します。
load KEYCD
ディレクトリをみると .COMを生成しました。
KEYCD.COMを実行します。
KEYCD
最後に
Altair 8800 simulatorを使用してCP/Mで、久しぶりにインテル8080アセンブラでプログラムを書きました。
大学生から新入社員だったころに、熱中してi8080プログラミングしていたころを思い出しました。
「我が青春の8bitマイコン8080」と、言えるでしょう!