その時に、rtavr 同士が通信できるモジュールとして FIFO モジュールを検討してみた。
- 『XAPP256』
に書いてあるのだが、このインターフェイスを参考に 一般の Verilog で記述してみた。
実装方式として、Dual Port 分散RAM による方式(以下 DPORT) と シフトレジスタによる方式(以下 SHIFT) の 2 つを考えた。
DPORT 方式は、Dual Port 分散RAM をサポートしている FPGA なら素直に記述すれば、推論してくれるはず。SHIFT 方式は、generate を使って二重ループという .. なんだか複雑な記述になってしまった。成功すれば、DPORT 方式より コンパクトになるが、失敗すると 全部 FF にされて 規模が増えてしまう。
突然こういうことをやり出したのには、理由がある。それについては別記事にする。
FIFO モジュールの説明は、

これは、シミュレーション結果。
// Target Device: xc3s200a-4ft256
// Product Version: ISE 12.4
// Design Goal: Balanced
// SHIFT DPORT
// Number of Slice Flip Flops: 12 19
// Number of 4 input LUTs: 20 39
// Number used as Shift registers: 8 -
// Number used for Dual Port RAMs: - 16
// Number of occupied Slices: 14 26
// Number of bonded IOBs: 26 26
// Number of BUFGMUXs: 1 1
// Post-PAR Static Timing Report
// Maximum frequency(MHz): 114.077 125.691
//
SHIFT 方式だと、14 スライスで済んだ。
最初に作ったのは、9 スライスだったのだが、COUNT 出力を付けたりして使いやすい仕様にした結果 + 5 スライス増えた。
SHIFT 方式について肝心な部分だけ転載すると ..
assign OUT = r_out;
assign EMPTY = ( r_pos == 4'hf );
assign FULL = ( r_pos == 4'he );
wire [3:0] fifo_count = r_pos + 1;
assign COUNT = fifo_count;
always @(posedge CLK)
begin
if (CLR) r_pos <= 4'hf;
else
begin
if (WR & RD)
begin
end
else if (RD)
begin
if (~EMPTY) r_pos <= r_pos - 4'h1;
end
else if (WR)
begin
if (~FULL) r_pos <= r_pos + 4'h1;
end
end
end
always @(negedge CLK)
begin
if (~EMPTY) r_out <= fifo[r_pos];
end
generate
genvar i,j;
for (i=0; i<WIDTH; i = i+1)
begin : data_in
for (j=1; j<16; j = j+1)
begin : data_in_bit
always @(posedge CLK)
begin
if (WR) fifo [j][i] <= fifo[j-1][i];
end
end
always @(posedge CLK)
begin
if (WR) fifo [0][i] <= IN[i];
end
end
endgenerate
なにはともあれ、これはうまくいった。
さて、これを使った、AVR のモジュールの仕様を考えてみる。
- 割り込み
USART などは、3 種類も割り込みを使っている。が、これを 1 つで済ます。
割り込みの意味は、NOTIFY で CPU で IOR に書きこんで発生させる。割り込みを受けた側が スタータスを見てなにをすべきか判断する。
割り込み許可のフラグも必要だから、レジスタを 2 bit 使う。 - データレジスタ
これは、USART の UDR のようにREAD すれば受信データが読めて、WRITE すれば送信データを 書きこむ ことにすれば良さそうだ。 - ステータス
受信データがある
送信中(相手が全部を受け取っていない)
送信が可能(空きがある)
これぐらいは必要そうだ。これで、合計 5 bit 。
あと、送信バッファがどれぐらい空いているのか も知りたい。送信中フラグ と 送信可能フラグをやめて 4 bit の情報にしよう。-- この変更で 合計 7 bit 。 - コントロール
送信データの破棄
NOTIFY 割り込みの送出
ぐらい? あと、NOTIFY 割り込みを相手が受け取ったかどうかの情報が欲しい。これはステータスに入れる。
まず、レジスタや 割り込みをあまり使いたくないという事情がある。空きが少なくて 厳しいのだ。それに複数付けたくなるかも知れない。最低限のリソースで済むようにしないと。
次に、機能は送受信。相手も同じモジュールを使う。で、FIFO をどちら側に付けるか --これは送信側ということにする。
さて、こんな仕様などより悩ましいのは、名前。-- 名前を付けないとファイルも作れない。何にしよう。
機能的には、通信ポート。... CPI(Communication Port Interface) ということにして、モジュール名は rtavr_ior_cpi 。
あとはなんでもかんでも CP を付ける。
レジスタ名は、CPCSR (CP Control and Status Register) , CPDR (CP Data Register)
フラグ名は沢山ある。
Communication Port Interface(CPI):
+-------+-------+-------+-------+-------+-------+-------+-------+
0x09 | CPIR | CPIE | CPIS | CPRXS | CPTXS |
+-------+-------+-------+-------+-------+-------+-------+-------+
+-------+-------+-------+-------+-------+-------+-------+-------+
0x0a | CPDR |
+-------+-------+-------+-------+-------+-------+-------+-------+
CPIR : CP Interrupt Recv. Flag
CPIE : CP Interrupt Enable Flag
CPIS : CP Interrupt Send Flag
CPRXS : CP Recv. Status (1: Recieved)
CPTXS : CP Trans. Status (xxx0 : Empty , 1xxx : Full )
こんな感じか。CPTXS は ちょっと細工。2bit で 詰まり具合が分かるようにする。
Control の方は
- CPTXS[0] に 1 を書くと バッファを破棄。
- CPIS に 1 を書くと 割り込みを送出して、受け取られたら 0 に戻る。
- CPIR / CPIE は、AVR のほかの装置と同じようにする。(詳細未定)
実装完了
// Target Device: xc3s200a-4ft256 , top-level rtavr
// SHRINKED DPORT SHIFT
// Number of Slice Flip Flops: 388 407 403
// Number of 4 input LUTs: 1089 1173 1162
// Number of occupied Slices: 662 710 699
// Number used as a route-thru: 34 35 35
// Number used for Dual Port RAMs: 16 32 16
// Number used as Shift registers: - - 8
// Number of bonded IOBs: 12 36 36
// IOB Flip Flops - - -
// Number of BUFGMUXs 1 1 1
// Number of RAMB16BWEs 3 3 3
// Number of DCMs - - -
// Number of BSCANs - - -
// Post-PAR Static Timing Report
// Maximum frequency(MHz): 46.198 43.459 42.531
SHIFT で +37 スライス / DPORT で +48 スライス。
output [7:0] CPI0_TXD : 送信データ
output CPI0_TX : 送信データあり
input CPI0_TX_ACK : 送信データあり ACK
output CPI0_IXS : 割り込み送信
input CPI0_IXS_ACK : 割り込み送信 ACK
input [7:0] CPI0_RXD : 受信データ
input CPI0_RX : 受信データあり
output CPI0_RX_ACK : 受信データあり ACK
input CPI0_IXR : 割り込み受信
output CPI0_IXR_ACK : 割り込み受信 ACK
信号線は、こんな風に定義した。クロックは共有しているのが前提。
送信/受信は、対称になっていて、上と下をたすきがけ(クロス)で接続する。
データそのもの以外の信号線は、全部ハンドシェークする。ACK は、posedge_CLK_180 で受け取り。
規模は小さいのだが、rtavr に組み込むのは、ものすごく面倒だった。
組み込み方法が 多数あるので、それに対応しないといけないし、接続用の信号も rtavr_fifo - rtavr_ior_cpi - rtavr_ior - rtavr と 3 段もパススルーしないといけない。
それは、ともかく ... これでプロセッサ間通信のしくみが確立できた。次の記事『AVR互換コア(SMP化)』に続く。