16ビットマイコンボードの製作
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
いつか使ってみるつもりで入手してそのまま置いてあった16ビットCPUのことを思い出しました。
AMD社のAM188です。
その名の通り、CPUコアは80188互換の16ビットCPUです。
そのAM188を使った16ビットマイコンボードの製作記事です。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
[第97回]
●システムサブルーチンを直接CALLしたい(2)
前回からの続きです。
前回書いたことの繰り返しですが、マシン語プログラムを直接16進コードで入力することが前提のND80KL/86ボードのマシン語モニタでシステムサブルーチンをコールするのにINT xx方式はなんとなく面白くありませんし、またシステムプログラムを作るうえでもちょっと作りづらい面があります。
なんとかシステムサブルーチンを直接コールしたいものだと思案しました。
というところで前回は終わってしまいました。
さてそのなんとかする方法なのですが。
そのヒントについては[第48回]に書いておりました。
問題はユーザープログラムがRAMにあって、CSも一時的にRAMになっているのにシステムプログラムはROMにあるので、ユーザープログラムからはROMのシステムプログラムがコールできない、というただ一点の問題でした。
システムプログラムをRAMにコピーしてしまえば問題は解消してしまうのでした。
思いついてしまえばなんてこともない簡単なことでした。
ROMからRAMへのコピーですが、マシン語モニタプログラムだけでしたら0100〜09FFまでのわずか2KB余りですから、起動時に実行すればほとんど瞬時に終ってしまいます。
どうせコピーするのでしたら、マシン語モニタプログラムだけではなくて、[第71回]、[第82回]で書きましたBASICのシステムサブルーチンも一緒にコピーしてしまえばさらに使い勝手がよくなります。
その場合には0100〜1FFFの8KBほどをコピーすることになりますが、AM188にはMOVSBという便利な命令がありますから、わずか数行のプログラムを追加するだけで済んでしまいます。
ということで、86モニタプログラムの起動部分にシステムコピープログラムを追加しました。
[00083] ; copy 0100-1fff to ram [00084] 0135 BE0001 MOV SI,100 [00085] 0138 BF0001 MOV DI,100 [00086] 013B B90020 MOV CX,2000 [00087] 013E FC CLD [00088] 013F F3 REPZ [00089] 0140 2E CS: [00090] 0141 A4 MOVSB |
あ。
今気が付きました。
0100〜1FFFならCX=1F00でした。
CX=2000では20FFまでコピーしてしまいます。
ま。
特に問題になることではありませんが、あとで直しておくことにいたしましょう。
MOVSBはDS:SIで示すメモリ内容をES:DIで示すメモリにコピーしたあと、SI、DIをそれぞれ+1する命令です(それより前にCLDが実行されていたとき)。
それより前にSTDが実行されているとSI、DIは−1されます。
REPZはそれに続くMOVSB/MOVSWなどのストリング命令をCX=0になるまで繰り返すプリフィクス(前置)命令です。
ここではCSのプログラムをコピーすることが目的ですからCS:プリフィクスをMOVSBの前に置いてDS:SIをCS:SIに一時的に置き換えています。
なおMOVSB/MOVSWなどのストリング命令の前にセグメント変更プリフィクスを置いた場合に置き換えられるセグメントは第一項のDS:でES:を置き換えることはできません。
●INT 2Aに変更しました
[第85回]でINT 22からINT B0に変更したシステムサブルーチンコールですが、今回のシステムプログラムのコピーを受けて、INT 2Aに再度変更しました。
INT B0の場合INTテーブルはRAMの002C0〜002C3に置かれます。
そこは今回のシステムプログラムのコピーによってシステムプログラムに占有されてしまうので、INT B0は使えなくなってしまいます。
使えるのは00000〜000FFの256バイトだけになりますから、INT 0〜INT 3Fに限定されます。
その中でMSDOSでは使っていないらしいbニしてINT 2Aを選びました。
今回のシステムプログラムのコピーによって、INT 2Aを使うほかにシステムサブルーチンのアドレスを直接指定してコールすることも可能になりますから、INT 2Aしか方法がないというところから選択肢が増えたことになります。
システムプログラムをRAMにコピーした効果を実際に試してみました。
今回のシステムプログラムコピーの本来の目的は86モニタのマシン語サブルーチンをコールすることだったのですが、7セグメントを使ったマシン語プログラムでそれを試すよりは、86BASICシステムを起動して、そこでマシン語プログラムを使って試すほうが楽ですので、まずはそのようにしてみました。
まずは今回変更したINT 2Aを試してみました。
下はテストプログラムINT2AT1のプログラムリストです。
[第85回]で使ったINTB0T1のINT B0をINT 2Aに変更しただけでほかは変更していません。
2018/10/8 20:26 int2at1.LST [00001] ;;; int 22 test [00002] ;18/9/7 10/8 [00003] ORG=8000 [00004] 8000 B041 MOV AL,41 [00005] 8002 B11A MOV CL,1A [00006] 8004 B407 MOV AH,07 [00007] 8006 50 LOOP:PUSH AX [00008] 8007 CD2A INT 2A [00009] 8009 58 POP AX [00010] 800A FEC0 INC AL [00011] 800C FEC9 DEC CL [00012] 800E 75F6 JNZ LOOP <8006> [00013] 8010 B409 MOV AH,09 [00014] 8012 CD2A INT 2A [00015] 8014 CB RETF [00016] ; LOOP =8006 |
こちらがログです。
logfile nd80klog\10090919.txt open nd80kl/86 2018.9.22 by Chunichidenko version no. bs861f ND80KL/86に接続しました 0001 001E - z 0003 0339 - *** nd80kl/86(am188) basic **** >/ld int2at1.com,8000 loading INT2AT1.COM ...0015(21)bytes loaded,from 8000 to 8014 >jp 8000 ABCDEFGHIJKLMNOPQRSTUVWXYZ > |
問題なく実行できました。
それではいよいよアドレスを直接指定してのシステムプログラムコールのテストです。
下はテストプログラム86SUBT1のプログラムリストです。
2018/10/9 8:51 86subt1.LST [00001] ;;; system sobroutine call test [00002] ;18/9/7 10/8 [00003] ORG=8000 [00004] ADISP=1015 [00005] CRLF=101B [00006] REENT=1033 [00007] ; [00008] 8000 B041 MOV AL,41 [00009] 8002 B11A MOV CL,1A [00010] 8004 50 LOOP:PUSH AX [00011] 8005 E80D90 CALL ADISP <1015> [00012] 8008 58 POP AX [00013] 8009 FEC0 INC AL [00014] 800B FEC9 DEC CL [00015] 800D 75F5 JNZ LOOP <8004> [00016] 800F E80990 CALL CRLF <101B> [00017] 8012 E91E90 JMP REENT <1033> [00018] ; ADISP =1015 CRLF =101B LOOP =8004 REENT =1033 |
8086は8080やZ80と違ってJMP、CALL命令のアドレス指定は相対アドレス指定です。
この方式はプログラムをどのアドレスに置いても実行可能(リロケータブル)という利点がありますが、16進コードでのプログラミングは極めて困難になります。
簡単なテストプログラム程度ならともかく、少しまとまったプログラムは86アセンブラに依らざるを得ないでしょう。
上のプログラムリストでCALL ADISP、CALL CRLF、JMP REENTはシステムサブルーチンのアドレスを直接指定していますが、マシン語コードのアドレスは相対アドレス(指定アドレスからその命令の次のアドレスを引いた値)になっています。
それはともかくとして、果たしてうまくシステムサブルーチンがコールできましたでしょうか。
下が実行結果です。
>/ld 86subt1.com,8000 loading 86SUBT1.COM ...0015(21)bytes loaded,from 8000 to 8014 >jp 8000 ABCDEFGHIJKLMNOPQRSTUVWXYZ > |
正しく実行できました。
テストとしてはこれでよいのですが、念のためにもう少しテストを続けてみました。
今度はシステムプログラムの先頭にブレークポイントを設定しました。
ブレークポイントはRAMにしか設定できません。
8080、Z80で命令をFFで置き換えることでRST7を利用しているのと同じように、コードCC(INT 3)で置き換えてブレーク処理を行ないますからRAM上のプログラムにしか使えません。
>bp 1015 >jp 8000 AX BX CX DX SP PC SI DI BP FR ODITSZ A P C 0041 8000 001A 8000 F7F6 1015 0C24 F007 0000 F046 1111000001000110 > |
実行した結果はアドレス1015でブレークしました。
これでシステムプログラムが間違いなくRAMにあることが確認できました。
なおシステムがROMにあってRAMにコピーされていない場合ブレークできないだけではなくて、上のプログラムでは暴走してしまいます。
暴走してしまうのでログは取れていませんがそのことは実際に確認済みです。
さてもうひとつ念のために同じことをINT 2Aを使ったプログラムでも試してみました。
同じように1015にブレークポイントを設定してさきほどのINT2AT1を実行してみました。
>/ld int2at1.com,8000 loading INT2AT1.COM ...0015(21)bytes loaded,from 8000 to 8014 >bp 1015 >jp 8000 ABCDEFGHIJKLMNOPQRSTUVWXYZ >bp d 1015 >bp 0 >/exit 0003 037C - リモート接続を終了しました logfile closed at Tue Oct 09 09:49:07 2018 |
こんどはブレークしないで、プログラムが普通に実行終了してしまいました。
BP Dで確認したところまだ(RAMの)1015にブレークポイントが設定されたままになっていました。
INT 2Aの実行ではRAMではなくてROMのシステムプログラムが実行された結果です(INT 2Aはそのように働くようにプログラムしてあります)。
16ビットマイコンボードの製作[第97回]
2018.10.14upload
前へ
次へ
ホームページトップへ戻る