CPU実験室

誰も見向きもしない古いCPUをいじって動かしてみようというプロジェクトです

メモリマップ

IDT79R3081は32bitマルチプレクスバスでハードウェア構成としてはNS32032IMST805とほぼ同等なので評価ボード回路も一部コピペでもってこれます。制御信号線もCPLDに突っ込んでおいてあとからロジック設計をすればいいのですが、直近でMC68030ボードで失敗したようにアドレス空間のデコードは前もって十分考えておかなければなりません

MIPSプロセッサに関する資料は比較的潤沢にありここのところIDT社のRISC MICROPROCESSOR COMPONENTS & SUBSYSTEMS DATA BOOK、The IDT79R3081™  RISController™Hardware User's Manualをつらつら読み解いています

この頃のデータブックはキラキラしてて未来への希望を感じさせます

さてRISC本体、R3000Aコアのメモリマップはこのようになってるようです。32bitの仮想アドレス空間が同じ32bitの物理アドレス空間へ写像されています

なぜ仮想アドレスと物理アドレスが同じ大きさなのか、マッピング先が固定なのか?

普通に考えるとはるかに大きい仮想空間の一部へ物理空間をマップするものと思ってましたが、ここでの使い方は例えば0x8000_0000から始まるkseg0セグメントと0xa000_0000から始まるkseg1セグメントを0x0000_0000から存在する物理メモリに重複して割り付けるとプログラムから仮想アドレスでどちらにアクセスするかでキャッシュ有無が切り替えられるということになります。さらに3081EではMMUも内蔵しておりマップ先を可変できるようです

次にリセット動作を確認します。マニュアルにはリセットは例外処理の1種として扱われておりそのベクタは仮想アドレスで0xBFC0_0000,物理アドレスで0x1FC0_000になっています

ということは物理アドレス上の0x1FC0_0000~にブートROM、0x0000_0000~にSRAMを配置すれば良さそうです。さらにI/OとしてシリアルコントローラSCC、タイマ、パラレルをつなぐのでこれらを区別するには最低A24-A21の4bitのアドレス線のデコードでいけます

 

16bitデバイス

IDT79R3081ボードを100×100mmの基板に押込む予定ですが実装密度を上げるために16bit幅デバイスを用意しています。PLCC44pinのUVEPROM、HN27C4096ACCとSOJ44pinのSRAM、IDT71016は使用実績があるのでこれで決定。

下段は16bitバスバッファ74FCT16245と16bitバスラッチ74ACT16373でともにSSOP48パッケージで初めて使う形状です。事前にデータシートで調べてはいたのですがこれがちょっと曲者。どうもピンピッチが0.635mm(インチ系)と0.5mm(ミリ系)の両方のパッケージが存在するようです。

うっかりパタンを作ってから乗っからないなんてミスが無いよう、パタン設計を保留していましたが現物を入手してみると両方とも0.635mmパッケージでした

実装する部品形状が確定したので基板に想定される部品を全て載せてみました

バスバッファとラッチは基板裏面に実装します

 

7セグデコード

TBLR/TBLW命令が間接アドレッシングで引くテーブル本体は任意の場所に置けるわけではなく、これもSARM上の0xF80-0xFFF番地に固定されているので配列変数は1組(TABLE[0..15])しか持てないということです。これを含めたSRAMの割付けはこのようになりました

この命令を使ったテストプロを書いてみました。例題はカウンタ変数0~15でTBLR命令を使い7セグフォントデータを表引きしLEDに「0」~「F」表示するという動作です。フォントデータの初期化部分はTBLW命令でアクセスするまでもなく配列TABLE[0..15]それぞれにTBL000-TBL015のエイリアスがあるのでこれに即値代入でいけます

この単純な処理は上記のようにマクロ言語で29行で済みます。ところがこれをプリプロセッサで展開するとアセンブラソースで918行、さらにアセンブラにかけるとバイナリで2726byteにもなり全プログラム領域の2/3を消費してしまいます

見た目の動きはこれと同じですがあちらはフォントデータを直接出力するなんちゃってカウンタなのに対し、こちらはちゃんと「数」をカウントして7セグデコードするまっとうなプログラムです

間接アドレッシングふたたび

MC14500でもう1つ問題になるのが間接アドレッシングができないということです。これは同様にハーバードアーキテクチャに依りデータをコードに反映できないからで以前にも検討したとおり二分木探索で目的の値を拾ってくる、という処理になります。これを一般化した命令をつくりました

これもMC14500のインストラクションに展開するとサイズが大きくなるのでライブラリTABLE.LIBに記述してサブルーチンコールになります。

サイズの見積もりはこうなります。

分岐なし(判定bit数n=0)のとき、8bit変数をテーブルからコピーしてきてリタンするのに8×2+1=17word必要になります

indexの最下位bitで2分岐(判定bit数n=1)の場合、分岐判定に3word、分岐先での変数コピーに17wordづつ。合計3+17×2=37word要することになります

判定するビットが1つ増えるごとにこの構造が入れ子になるのでnbitで判定する場合必要なサイズXの漸化式はX(n+1)=X(n)×2+3,X(0)=17。一般項ではX(n)=20×(2^n)-3になるので

n=1 分岐2      X(1)=37
n=2 分岐4      X(2)=77
n=3 分岐8      X(3)=157
n=4 分岐16    X(4)=317
n=5 分岐32    X(5)=637
n=6 分岐64    X(6)=1277
n=7 分岐128  X(7)=2557
n=8 分岐256  X(8)=5117  ・・とサイズはどんどん増えますがそもそもプログラム空間が4096wordしかないのでインデックス変数をフル探索するn=8はまったく無理。しかもテーブル書込みと読出しに同じ処理が2組いるので最大はn=6になりますがそれでプログラム空間の半分以上がつぶれるのも何なのと切りが良いところでn=4(分岐16)で我慢しておきました

 

 

 

 

マクロ展開プリプロセッサ

いま用意している命令をつかったマクロ言語でテストプログラムを書いてみました。内容は例によってインクリメントデータをパラレルポートに出力するLEDチカチカで見た目は8085かZ80のアセンブラ風です

各行はMC14500のインストラクションに展開されますがサイズが大きくなる算術演算処理はライブラリ化(ARITH.LIB)して先頭で使用宣言するようにしてあります

これを展開するプリプロセッサcmpl.exeも作成しました。

これを通すとマクロ4桁は展開され97行のアセンブラコードになります。ハーバードアーキテクチャのMC14500ではデータをコードに埋込みができないので即値ロードMVI(reg,imm8)はちょっと工夫が必要です

以下はプリプロセッサ内でMVI命令を展開する部分ですが引数のビット状態からSTO/STOCインストラクションを発生させていてコーディング段階で構造的に埋込んでいるということです

INC(reg)の処理は仮引数tempにコピーしてarith.lib内のINCルーチンをコールします

さらにこのアセンブラソースをPROASMにかけるとバイナリコードが生成されますがarith.libも展開されるのでコードサイズは0x32A=810ワードに膨れ上がります

                :

                :

 

言語仕様(2)

2個の変数の大小比較処理は双方の上位bit側から比較を行い内部フラグZF,GT,LTの更新を行います

プログラムの流れを制御するJMP,CALL,RETはMC14500のインストラクションに直接変換、条件付きジャンプはCMP()を実行した直後の内部フラグZF,GT,LTの状態からジャンプするかどうかを決定します

代入、論理演算、比較について即値を引数とする専用命令を用意しています

その他の命令は先ずはこの程度です



 

言語仕様

MC14500を簡単に動かせるプログラム言語を考えています。

Cのような構造化言語はメモリ構造、容量から厳しいのでマクロ言語記述を展開してアセンブリコードに変換することから始めてみました。PROASMにかける前のプリプロセッサという位置づけになります

MC14500のデータ幅は1bitで数値を扱うのが難しいというのが最初に突き当たる問題です。これは以前もやってますが複数ビットを束ねれば数値の扱いも可能です。

8bit幅の変数Aを A={a0,a1,a2,a3,a4,a5,a6,a7}とベクタ表現で保持して変数名はAからZとしました。宣言して生成するものではなくあらかじめSRAMの固定番地に確保された静的変数で、変数名は実アドレス値のエイリアスにすぎません。これで8×26=208bit消費します

 

変数間のコピー、論理演算はビット命令を8回繰り返せば容易に実現できます。ただし高級言語のような代数的表現では式の解析が面倒なので関数手続き型にしてあります

シフト、ローテーションはコピーするビットをずらすだけでいけます

算術演算は少し面倒。ビット間加算器とキャリ伝搬のロジックに展開する必要がありこれも以前につくったルーチンを汎用化したものです