2018.5.29
前へ
次へ
ホームページトップへ戻る


16ビットマイコンボードの製作

〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
いつか使ってみるつもりで入手してそのまま置いてあった16ビットCPUのことを思い出しました。
AMD社のAM188です。
その名の通り、CPUコアは80188互換の16ビットCPUです。
そのAM188を使った16ビットマイコンボードの製作記事です。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜

[第27回]



●RETF(2)

8086のアセンブラではセグメントを理解することが肝要です。
もっともWindowsマシンのコマンドプロンプトの中で、データとプログラムをあわせて64KB以内のプログラムを書いている分にはセグメントの概念は不要といえます。
ただ今回のようにROMとRAMを搭載したシステムになると、どうしてもセグメントを避けて通るわけにはいきません。
なかなかに厄介なものです。
なに。
理解してしまえばそれほど難しいものではありません。
扱いがちょっと面倒だというだけです。

もう一度セグメントについておさらいをします。
プログラムのマシン語コードが書かれるメモリエリアがコードセグメントです。
そのコードセグメントのベースアドレスを入れるのがCSレジスタです。
8086がアクセスできるメモリアドレスは24bitなのですがCSも次に説明するDSも16ビットですから、24ビットのアドレスは入れられません。
そこでセグメントアドレスの上位16ビットを格納します。
たとえば10000からはじまる64KBのメモリ範囲ならCS=1000になります。
そして先回も書きましたように、普通にワークメモリとして使うメモリ範囲はすべてデータ領域ですから、それはデータセグメントになります。
そのベースアドレスをDSレジスタに入れます。
ESとSSについては今は考えません。
ES=SS=DSにしておけば通常は支障はありません。

CS=DSにすればとりあえずはよいのですが、そこがROMの場合にはデータエリアがリードオンリーになってしまいます(ROMですから)。
これは特殊な目的のために必要になります。
さて、CS=DSをRAMに設定した場合には、そこにプログラムを書けば、とりあえずは支障なく実行できます。
しかし、そのプログラムからはROMに書かれているシステムサブルーチンを呼び出すことはできません。
おお。
そういうことでした。
たとえばTK−80の場合、ROMに書かれたキー入力ルーチンやLED表示ルーチンなどをユーザープログラム内でコールして利用することができました。
しかし8086では簡単にはできません。
できないことはありませんがちょいとしかけが必要です。
そのことについてはうっかりしておりました。
そのようにできる仕組みは考えることにいたします。

今はそれについては置くことにしまして。
前回書きました、システムROMのプログラムからRAMのユーザ−プログラムにジャンプする方法と、ユーザープログラムからROMのシステムプログラムに戻る方法について考えます。
ここでRETF(セグメント間リターン)を使います。
下はROMのシステムプログラムのJP命令の部分です。

[00715] 1CD5  B800F0        JPIN1:MOV AX,F000;return CS
[00716] 1CD8  50                PUSH AX
[00717] 1CD9  B83310            MOV AX,1033;return entry
[00718] 1CDC  50                PUSH AX
[00719] 1CDD  B80000            MOV AX,0000;ram CS
[00720] 1CE0  50                PUSH AX
[00721] 1CE1  52                PUSH DX;user program address
[00722] 1CE2  CB                RETF;jmp user program

ほかにもJMPFやCALLFを使う方法も考えられますが、扱いが面倒です。
RETFは命令コードが1バイト(CB)だけで済むので扱いが楽です。
ここで何をやっているかといいますと。
まずはROMのセグメントベースアドレス(F0000の上位16ビット、F000)と、ユーザープログラムから戻ってきたときのシステムのリエントリアドレス(1033)をスタックにPUSHします。
次にRAMのベースセグメントアドレスの上位16ビット(0000)をスタックにUPします。
その次にユーザープログラムアドレス(この前の処理でDXに入っています)をスタックにPUSHします。
そして最後にRETFを実行します。
RETFはスタックからPCとCSの値をPOPしたあと、CSで示されるセグメントベースの、PCで示されるアドレス「に戻って」、そこから実行を再開します。
JP命令なので本当はユーザープログラムへのジャンプなのですが、CSを操作する必要から、ここではリターン(RETF)を使っていますが実質的にはジャンプと同じことです。

さて、前回に書きましたユーザプログラムの最後がなぜRETFなのかという答えがここにあります。
ユーザプログラムの最後のRETFが実行されると、PCには1033が入り、CSにはF000がはいります。
結果としてシステムのリエントリポイントに制御が戻ることになります。

あ。
まあ、ユーザーとしては、こんな面倒なことは忘れていただいて構いません。
Z80や8080と同じ要領でプログラムを書いていただいて、ただしプログラムの終わりにはRETF(コードCB)を忘れないようにしていただければそれで十分です。
今回書きましたことは、私自身のための、いわば裏方としての考え方です。

16ビットマイコンボードの製作[第27回]
2018.5.29upload

前へ
次へ
ホームページトップへ戻る