現在地

ASに新CPU対応を(その3)


あれから作者の方と連絡とって質問したり、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() 関数を使う関係でやむを得ずこうしています。この関数とても便利なのですが途中でエラーを検出すると、エラー位置を取得できない、エラーを勝手に報告してしまう、という問題があるからです。

もし右のカッコ内のレジスタ名が2文字固定でなかったりしたらさらに面倒なことになっていますし、左の式の書き方(例えば(A+1)*(B-1)(X1))によっては誤認します。
Z80などではこの誤認問題は起きないのでやり方があるとは思うのですが、時間がかかりそうなので今後の課題ということで今はこれで妥協しています。

StrCompSplitRefStrCompShorten で左右に分割し、Left には (???...)Right には括弧がはずされた ?? が入ります。

Left はさらに括弧をはずしてから EvalStrIntExpression() で値を取り出します。これはゼロページのアドレスなのでレンジチェックも必要です。

Right は前回説明したReg() でレジスタ番号を取り出し、このアドレッシングモードでは X0X1 しか使えないので他はエラーとします。

他のアドレッシングも同様に処理します。

もう一つ困ったのがメモリに定数を置く DC 擬似命令でした。

これ MC680x0系と同じでいけると思って DecodeMoto16Pseudo(eSymbolSize16Bit, True) とかしてみたのですが正しいコードを生成しません。後ろに余計な0データが付いてしまいます。問い合わせたところワードアドレスには対応していないそうです。

これを修正するにはいくつかの方法があります。

  1. motpseudo.cDecodeMoto16Pseudo() を修正する
    バイトアドレスでの動作に影響を与えないようにする必要があります。今後他のCPUでも利用できます。
  2. panapseudo.c のようなファイルを追加して新規に書く
    今後他のCPUでも利用できます。
  3. 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.ccodemn1610_init() を登録。
  • asmpars.c
    変更:2, 8, 10, 16進定数の表記として ConstModeWeird を選択しますが、そのままでは単純な10進定数が使えなくなるので修正。
  • headids.c
    変更:MN161xのIDを登録。
添付ファイル: 

コメント

ここまで進めている方がいたとは...

ラベルの処理がうまくいかないとはどういう状況ですか?

こちらは最低限アセンブル可能(MN1610命令のみ・間接アドレッシングのパーサも手抜き)になったところでアセンブラは中断して、現在はモニタの方を書いています。もうちょっとでメモリダンプが動きそう。

添付したテスト用のソースで、2番目に指定したラベルが参照できないように見えます。locparse のようなやり方で呼ぶのが悪いのか、なにか初期化や後始末が必要なのかなと思います。いまCコンパイラの方を考え中なので今週末にでも見るつもり。それと、現状 L/ST は怪しいです。
また、まだハードウェア側は考え中。9900 用の ALTMEM を使うと0ページは普通にROMなので、最初の256B だけCPUボード側でRAMに差し替えようかと。モニタだけじゃなく、とりあえずなにかベンチを走らせてみたいのでなにか環境をポートしたいです。

関係ありそうなところを摘み読みしただけですが、StrComp関係が怪しいかもしれません。生ストリングの取り出しはともかく、初期化や設定は専用関数に任せたほうが... StrCompAlloc()とかStrCompSplitRef()とか便利な関数がstrcomp.cにいろいろあります。
あとオペランドの書式は何を参考にされました?

出自のせいかROMとRAMのエリアを分離しにくいですよね。
ゼロページをRAMにするのは良いのですが、別の記事にも少し書いたように定数テーブルを置きたいこともあるので悩ましいところです。うちはRAMオンリーにしてプログラムは外部からロードしています。

コメントを追加

Plain text

  • HTMLタグは利用できません。
  • ウェブページアドレスとメールアドレスは、自動的にハイパーリンクに変換されます。
  • 行と段落は自動的に折り返されます。
※ コメントは原則公開です。個別のご相談などは「ご意見・ご要望」からお願いします。