2022-12-19 21:04 — asano
カテゴリー:
Z8001を動かすで非セグメントモードで動くことがわかりました。動作する石も複数確保できましたので、本来のセグメントモードで動かすことにします。
Z8000ファミリにはセグメントモードでも動作するZ8001(とZ8003)と非セグメントモード専用のZ8002(とZ8004)があります。両者はリセット時のPC, PSWの初期値を格納する形式が異なる上にアドレスが重なるので同一バイナリで両方に対応することはできません。
Z8001(とZ8003)はセグメントモードでも非セグメントモードでも動作させることができます。これは同一バイナリで両対応するのは可能ですが、ほぼすべてのルーチンを2つ持つようなことになってしまいます。
結局3種類のバイナリを作ることになります。
- セグメント対応CPUをセグメントモードで使うもの
- セグメント対応CPUを非セグメントモードで使うもの
- セグメント非対応CPU用のもの
2.と3.はリセット時のPC, PSW初期値とPSA(Program Status Area)の形式が異なります。
2.を実際には使うことはないと思います。1.のセグメントモードで動作しているモニタから非セグメントモードのユーザプログラムを実行することは可能ですから。ただ開発中に非セグメントモードの動作を壊していないか確認するのにデバイスを挿し替えずにできて便利なので残しておきます。
これらを同一のソースから生成したいので以下の変数を用意して条件アセンブルすることにします。
SEG_CPU
:Z8001, Z8003用の場合に1にしますSEG_MODE
:セグメントモードで動作させる場合に1にします
これだけですとソースがIF
~ELSE
~ENDIF
だらけになってしまいますので次のような工夫をしています。
まずPSAのエントリは以下のようにマクロを切り替えています。
IF SEG_CPU
SPAENT MACRO PC,FCW=0C000H
DW 0 ; Dummy
DW FCW
DW segment(PC) << 8
DW offset(PC)
ENDM
ELSE ; !SEG_CPU
SPAENT MACRO PC,FCW=4000H
DW FCW
DW PC
ENDM
ENDIF
ちなみに使っているアセンブラASではセグメントとオフセットをつなげた23ビットのアドレスとして扱いますが、実際のCPUは32ビットのロングワードのビット30~24にセグメントを入れます。8ビットのシフトがあるのはこの変換のためです。
もう一つ厄介なのはレジスタ間接に使うレジスタです。非セグメントモードでは16ビットのレジスタ(R1など)を使いますが、セグメントモードでは32ビットのロングワードレジスタ(RR2など)を使います。これは頻出するので以下のように切り替えています。
IF SEG_MODE
AR1 REG RR0
AR3 REG RR2
AR5 REG RR4
AR7 REG RR6
AR9 REG RR8
AR11 REG RR10
AR13 REG RR12
AR15 REG RR14
ASP REG RR14
ELSE
AR1 REG R1
AR3 REG R3
AR5 REG R5
AR7 REG R7
AR9 REG R9
AR11 REG R11
AR13 REG R13
AR15 REG R15
ASP REG R15
ENDIF
AR0ではなくAR1としているのはオフセットをインクリメントなどするときにINC R1
などとするのでそれに合わせているためです。
(続く)
コメントを追加