カテゴリー
2回にわたりサブルーチンについて書きましたが、他にもプログラミング上厄介な点はあります。
まず特定のレジスタ・スクラッチパッドを要求されることが多い点です。
- 演算や値の移動ではいくつか例外はあるもののアキュムレータ
A相手にしか出来ません - スクラッチパッドの16以降へのアクセスには
ISAR間接しか使えません - 外部メモリへのアクセスには
DC0しか使えません DC0と値のやり取りが出来るのはDC1との交換・即値代入を除くとH,Qのみです- プログラムカウンタ
PC0に代入出来るのはJMP,PI命令による絶対アドレスの他はK,Qのみです PC1と値のやり取りが出来るのはKのみです- ステータス
Wと値のやり取りが出来るのはJのみです
ここでJ, H, K, Qはスクラッチパッド上の決まった場所です。
その1でも書きましたが、JMPなどでもAが破壊されます。
これは
JMP命令の実行を追ってみるとわかります。まずPC0のアドレスからオペコードを読んで(直後にPC0を+1、以下同様)JMP命令であることがわかります。次に1進んだPC0から飛び先の上位バイトを読みます。これは最終的にはPC0の上位に代入しますが、ここでPC0を変更してしまうと3バイト目の下位アドレスの読み込みが出来なくなってしまうのでどこかに保存しておく必要があります。この保存場所をケチってAで代用していると思われます。
その他なにをするにしてもAを必要とするので何らかの値を入れたままにしておくことが出来ません。
そういうわけでZ80などでレジスタに割り当てていたものはスクラッチパッドの0~15に、入力バッファ(他の用途にも流用していますが)は16~31に、その他ワークエリアは32~に配置しました。DコマンドのアドレスのようにDC0とのやり取りが発生するものを優先的にHなどに割り当てています。
ISAR, DC0も原則として短期使用として必要に応じてスクラッチパッド(0~15)に退避するようにしています。
コンソール用の8251にアクセスするところは例外で、XDC命令でDC1に退避します。これは頻繁に使われるのでメインルーチンの負担を増やさないためです。
他にも細かな不便な点はいろいろあります。
CI(Compare Immediate)命令が逆
(A- imm ) なプロセッサが多い中これは逆なので境界条件バグを多発させてしまいました。CS(Compare Scratchpad)に相当する命令がない
DPBルーチンでは一致判定だったのでXS(XOR Scratchpad)で代用しています。INCはあるのにDECが無い- 加算命令はあるのに減算命令がない
Universal Monitorでは即値ばかりなので2の補数の加算で済みました。 - Z80の
OR Aに相当する命令が無い?
最初は素直に次のように書いていました。LR A,8 CI 0途中からはちょっと短く速く改めています。
CLR AS 8 LM,STで外部メモリにアクセスするとDC0が勝手にインクリメントされる
デクリメントするのは結構面倒なのでHかQに保存しておくほうが良いでしょう。デクリメントするにも一旦どちらかに転送しないと出来ませんし。ISARのポストインクリメント・デクリメント
ISARはスクラッチパッドのアクセス後に+1することも-1することも不変も可能ですが、下3ビットのみです。このことを失念していてASCIIダンプのバグを出してしまいました。結局一旦Aに移してINCしています。逆順にしていればBR7が使えたのかもしれません。IN/OUTには短縮命令INS/OUTSがあるが...
完全に互換ではないので注意が必要です。例えばF3850内蔵のポート0,1にはINS/OUTSでしかアクセスできません。
逆に便利だと思った点もあります。
LNK命令
キャリーのみ加算する命令で16ビットのINCの上位バイトに使いました。
そんなこんなでD,S,G,L,I,Oの各コマンドが使えるところまで実装できています。
コメントを追加