あれから作者の方と連絡とって質問したり、ID番号もらったり...
軽い気持ちで始めたのですが、ここまできたら本家への追加を目指そうかな。
code***.cを参考に推測・試行錯誤した結果です。全体を理解して書いているわけではないので、間違っていたり作者の意図しない使い方をしたりしているかもしれません。ご了承ください。
前回厄介と書いたメモリに関係する L, ST, B, BAL, IMS, DMS の各命令も使えるようになりました。これらをデコードする DecodeAdr は長いのでゼロページ間接インデックス(MN1610で一番複雑)を例にみてみます。
l = strlen(ArgStr[idx].Str);
if (l >= 6 &&
ArgStr[idx].Str[ 0] == '(' &&
ArgStr[idx].Str[l - 5] == ')' &&
ArgStr[idx].Str[l - 4] == '(' &&
ArgStr[idx].Str[l - 1] == ')')
{ /* (zadr)(X0) or (zadr)(X1) */
tStrComp Left, Right;
Word preg;
StrCompSplitRef(&Left, &Right, &ArgStr[idx], ArgStr[idx].Str + l - 4);
StrCompShorten(&Right, 1);
l = strlen(Left.Str);
StrCompCopySub(&Inner, &Left, 1, l - 2);
disp = EvalStrIntExpression(&Inner, Int8, &OK);
if (disp < 0 || disp > 0xff)
{
WrError(ErrNum_OverRange);
return;
}
if (!Reg(Right.Str, &preg)) return;
switch (preg) {
case 3:
mode = 0x6;
break;
case 4:
mode = 0x7;
break;
default:
WrError(ErrNum_InvRegisterPointer);
return;
}
}
L, ST 命令では第1オペランドはレジスタなのでアドレッシングは第2オペランド、残りの命令では第1オペランドがアドレッシングなので idx で切り替えています。
最初の if 文では(???...)(??)という形式を検出しています。ここちゃんとパースしたいところなのですが式評価の EvalStrIntExpression() 関数を使う関係でやむを得ずこうしています。この関数とても便利なのですが途中でエラーを検出すると、エラー位置を取得できない、エラーを勝手に報告してしまう、という問題があるからです。
(A+1)*(B-1)(X1))によっては誤認します。Z80などではこの誤認問題は起きないのでやり方があるとは思うのですが、時間がかかりそうなので今後の課題ということで今はこれで妥協しています。
StrCompSplitRef と StrCompShorten で左右に分割し、Left には (???...)、Right には括弧がはずされた ?? が入ります。
Left はさらに括弧をはずしてから EvalStrIntExpression() で値を取り出します。これはゼロページのアドレスなのでレンジチェックも必要です。
Right は前回説明したReg() でレジスタ番号を取り出し、このアドレッシングモードでは X0 か X1 しか使えないので他はエラーとします。
他のアドレッシングも同様に処理します。
もう一つ困ったのがメモリに定数を置く DC 擬似命令でした。
これ MC680x0系と同じでいけると思って DecodeMoto16Pseudo(eSymbolSize16Bit, True) とかしてみたのですが正しいコードを生成しません。後ろに余計な0データが付いてしまいます。問い合わせたところワードアドレスには対応していないそうです。
これを修正するにはいくつかの方法があります。
motpseudo.cのDecodeMoto16Pseudo()を修正する
バイトアドレスでの動作に影響を与えないようにする必要があります。今後他のCPUでも利用できます。panapseudo.cのようなファイルを追加して新規に書く
今後他のCPUでも利用できます。codemn1610.cでCPU命令と同様に扱う(新規に書く)
もっとも簡単ですが、他のCPUに流用はできません。
今回は3.を採りました。
AddInstTable(InstTable, "DC", 0, DecodeDC);
CPU命令と同様に登録し、デコードします。
バイト単位の文字列処理がちょっと面倒なくらいでそう難しくはありません。
今回このMN1610対応を始めてからちょうど1週間、とりあえず実用になるところまでは漕ぎ着けたかと思います。しばらくはMN1613拡張命令の追加は保留して、Universal Monitorの移植をしつつテストと修正を行なうつもりです。
最後に今回追加・変更したファイルの一覧を載せておきます。
codemn1610.c
新規:MN1610固有の初期設定や命令デコーダなど。codemn1610.h
新規:プロトタイプ宣言makedefs.src
変更:makeでcodemn1610.cをコンパイルされるように。as.c
変更:codemn1610.cのcodemn1610_init()を登録。asmpars.c
変更:2, 8, 10, 16進定数の表記としてConstModeWeirdを選択しますが、そのままでは単純な10進定数が使えなくなるので修正。headids.c
変更:MN161xのIDを登録。
手元の暫定パッチ
手元で作業していた内容を 一旦 https://osdn.net/projects/software-for-losttechnology/releases/71940
に置きました。ラベルの処理がうまく行かない、というか EvalIntExpression が想定通り動いてくれない。このへんどうなっているのか分かりませんか?
なお、mn1613 の命令は一応一通りあるはずです。
Re: 手元の暫定パッチ
ここまで進めている方がいたとは...
ラベルの処理がうまくいかないとはどういう状況ですか?
こちらは最低限アセンブル可能(MN1610命令のみ・間接アドレッシングのパーサも手抜き)になったところでアセンブラは中断して、現在はモニタの方を書いています。もうちょっとでメモリダンプが動きそう。
Re; ラベルの件
添付したテスト用のソースで、2番目に指定したラベルが参照できないように見えます。locparse のようなやり方で呼ぶのが悪いのか、なにか初期化や後始末が必要なのかなと思います。いまCコンパイラの方を考え中なので今週末にでも見るつもり。それと、現状 L/ST は怪しいです。
また、まだハードウェア側は考え中。9900 用の ALTMEM を使うと0ページは普通にROMなので、最初の256B だけCPUボード側でRAMに差し替えようかと。モニタだけじゃなく、とりあえずなにかベンチを走らせてみたいのでなにか環境をポートしたいです。
Re: ラベルの件
関係ありそうなところを摘み読みしただけですが、StrComp関係が怪しいかもしれません。生ストリングの取り出しはともかく、初期化や設定は専用関数に任せたほうが... StrCompAlloc()とかStrCompSplitRef()とか便利な関数がstrcomp.cにいろいろあります。
あとオペランドの書式は何を参考にされました?
MN1613のハードウェア
出自のせいかROMとRAMのエリアを分離しにくいですよね。
ゼロページをRAMにするのは良いのですが、別の記事にも少し書いたように定数テーブルを置きたいこともあるので悩ましいところです。うちはRAMオンリーにしてプログラムは外部からロードしています。
コメントを追加