2.アーキテクチャ

仕様の第一目標がDWM誌の付録基板に載ることです。Web Editionで開発可能、かつ高性能なデバイスを下記に示します。 

CYLONE 全機種
付録は、59901ビットRAM
STRATIX EP1S10 920,448ビットのRAM
STRATIXU EP2S15 419,328ビットRAM

そこで、STRATIXにすれば、32KBのアドレス空間は取れそうです。付録のデバイスも7KB強ありますから、4KBを内臓RAMに残りをマイクロプログラムにうまくいけば割り当てられそうです。割り当てられないと最初から本プロジェクトは破綻してしまうので、まずこの検証からはいることにします。 

2.1 4KBRAM+マイクロプログラムRAMがDWM付録デバイスに入るか?

実際にサンプルを記述してみて論理合成してみれば分かるでしょう。
合成さえできればいいので、中身は意味のないものですが、最適化でマージされないように記述します。
2-3度のCut&Tryを行って次の記述で利用可能なRAMを最大限に活用する記述になりました。

 

//May.16.2004
//ramが入いるか検証
//M-RAMは、MAX13個 4KBitx13=53248が実質の上限になる。
//3port では、256では、OKだが、512になると13個以上要ると言われNG

module h8_ram_module(clock,address,in_data,out_data_a,out_data_b,xout,wren,maddress,aclr);
        input clock;
        input [8:0] address,maddress;
        input [7:0] in_data;
        output [7:0] out_data_a,out_data_b;
      output xout;
        input wren;
        input aclr;

        wire [7:0] qa0,qa1,qa2,qa3,qa4,qa5,qa6,qa7;
        wire [7:0] qb0,qb1,qb2,qb3,qb4,qb5,qb6,qb7;
        wire [39:0] xq,data_w;
        

ram512x8  u0(.data_a(in_data),.data_b(in_data+1),.address_a(address),.address_b(address+1),
        .wren_a(wren),.wren_b(!wren),.clock(clock),.q_a(qa0),.q_b(qb0));
ram512x8  u1(.data_a(in_data),.data_b(in_data+1),.address_a(address+1),.address_b(address+2),
        .wren_a(wren),.wren_b(!wren),.clock(clock),.q_a(qa1),.q_b(qb1));
ram512x8  u2(.data_a(in_data),.data_b(in_data+1),.address_a(address+2),.address_b(address+3),
        .wren_a(wren),.wren_b(!wren),.clock(clock),.q_a(qa2),.q_b(qb2));
ram512x8  u3(.data_a(in_data),.data_b(in_data+1),.address_a(address+3),.address_b(address+4),
        .wren_a(wren),.wren_b(!wren),.clock(clock),.q_a(qa3),.q_b(qb3));
ram512x8  u4(.data_a(in_data),.data_b(in_data+1),.address_a(address+4),.address_b(address+5),
        .wren_a(wren),.wren_b(!wren),.clock(clock),.q_a(qa4),.q_b(qb4));
ram512x8  u5(.data_a(in_data),.data_b(in_data+1),.address_a(address+5),.address_b(address+6),
        .wren_a(wren),.wren_b(!wren),.clock(clock),.q_a(qa5),.q_b(qb5));
ram512x8  u6(.data_a(in_data),.data_b(in_data+1),.address_a(address+6),.address_b(address+7),
        .wren_a(wren),.wren_b(!wren),.clock(clock),.q_a(qa6),.q_b(qb6));
ram512x8  u7(.data_a(in_data),.data_b(in_data+1),.address_a(address+7),.address_b(address+8),
        .wren_a(wren),.wren_b(!wren),.clock(clock),.q_a(qa7),.q_b(qb7));


 ram512x40 u8(.address(maddress),.clock(clock),.data(data_w),.wren(wren),.q(xq),.aclr(aclr));
 

      assign data_w={in_data,in_data,in_data,in_data,in_data};
        assign xout=^xq;


        assign out_data_a=address%8==0 ? qa0 : 
                                    address%8==1 ? qa1 :
                                    address%8==2 ? qa2 :
                                    address%8==3 ? qa3 :
                                    address%8==4 ? qa4 :
                                    address%8==5 ? qa5 :
                                    address%8==7 ? qa6 : qa7;

        assign out_data_b=address%8==0 ? qb0 : 
                                    address%8==1 ? qb1 :
                                    address%8==2 ? qb2 :
                                    address%8==3 ? qb3 :
                                    address%8==4 ? qb4 :
                                    address%8==5 ? qb5 :
                                    address%8==7 ? qb6 : qb7;                       


endmodule


結果、次の構成となります。

 2ポートの512x8ビットが8個  =>4KB RAM
 1ポートの512x40ビットが1個 =>マイクロプログラムRAM


2.2 アーキテクチャ検討
 RAMは入ることがわかりました。オブジェクトコードは、H8コンパチなので、あとはどういう形で実現するかです。折角FPGAで実現するのですから、FPGAの特徴を考えましょう。


これをうまく利用したハード構成を考えます。通常のマイクロプロセッサの構成方法は、RAMからデータを得るのに、アドレスレジスタに書く。RAMアクセスタイム後にデータをIRに読み込む、と言った手順を取ります。


これを、Altera同期式RAMにそのまま行うと、タダで遅れてしまうことになり面白くありません。(REG間に入るのは、簡単なデコードロジックだけです。 オープンコアの記述にもアルテラRAMを使用した例がありますが、例外なく、CLOCKのNEG Edgeを利用しています。)
しかし、ARをAltera RAMのAddressラッチ、IRをQREGと考えれば、遅れなくて済みます。しかも、3ポートまで付いていて、LUTを殆ど消費しないので使わない手はありません。リソースの少ないデバイスにおいてLUTの消費を抑えるアイデアは即採用です。


OPコードの最大値は、命令表を見ると10バイトもあります。RISCでは、これを一定になるようにしてパイプラインを構成しやすくするのですが、メモリ効率を重視した時代のCISC仕様となっています。バス幅を10バイトとれば、全オペコードを1サイクルでフェッチできますが、ここでは、8バイト(64ビット)としてデコーダを構成しやすくします。(10バイト命令については、T.B.D.)



命令デコーダの処理にマイクロプログラムを使うのはリソースの消費を抑えることが目的でした。ところで、水平マイクロプログラムのビット幅は、40ビットまでしか上記の検討で入らないことがわかりましたが、40ビットで十分でしょうか?
そこで、マイクロコードをプロト的にEXCELで書いてみました。結果、サブセット仕様においても、54ビット程度必要であることがわかりました。ということで、あえなく、所要RAMが足りないことから、ハードコード方式に変更することにします。従ってDWM誌の付録に載せるという目標は、かなり後退し、極縮小命令仕様(サブセットのサブセット)で実現するものとします。

とりあえず、実用的なサブセット仕様で設計を進めます。ハードコードに変更したので、今度は、規模よりも性能に重点を起きます。

設計目標(変更後)

 仕様 H8300Hのサブセット
 LUT 5000程度
 ステート数 オリジナル以下
 性能比   16MHzオリジナルに対し、3-10倍程度の実行速度(StaratixU)


 速度を3倍以上、ステート数を平均半分以下にすれば、平均性能向上比は、パイプラインなしでも3x2=6になります。とりあえずこの路線で進めることにしましょう。




ロジックデザインの仕方
 Verilog言語編でも書きましたが、ロジックを設計する前にやらなくてはいけないのが、アルゴリズムです。アルゴリズムは、ロジック設計以前の抽象的な概念です。決定したら、これは、ステートダイアグラムや、PAD,フローチャート、ブロックダイアグラム等で、表現します。

 次に重要なのは、Registerと組み合わせ回路の切り分けです。Registerは、記憶素子です。一般にRegister間は、組み合わせ回路となり、記憶がありません。つまり、入力が決まれば出力は一意に決まります。この組み合わせ回路の複雑度が回路の遅延を決定してしまうので、深すぎるロジックは、Registerを挿入し分割する(パイプライン処理)ことになります。従って、考えなくてはいけないのは、なにをRegisterにするかということです。それが、決まれば、後は、HDLのコーディング作業に集約されます。実は、マイクロコードを書いた時点で、なにをRegisterにするかは、決定済みです。後は、Refine,文書化(ブロックダイアグラム等)と、コーディング、Debugの作業が残っています。(EXCELのマイクロコードは、現在は、筆者だけが理解できるコードとなっていますが、これを書きながら、何をRegisterにするか決定しましたのであえて載せています。)

 
なにをRegisterにするか決まれば、動作的には、決まってしまいます。(実際、Excelを見てもらうと、各命令のステート数まで載っているのが分かると思います。)Registerが決まると後は組み合わせ回路なので、入力に対し一意に決まりますから、それをコーディングしていけばいい訳です。