4.2.3 デュアルポートRAM
YACC プロジェクトで使用を予定しているので、動作を調べておきましょう。
次の記述をしてBlock RAMが一個使われることを確認したかったのですが、合成してみると使用数が2となってしまいます。(なにがいけなかったのでしょう?)
//Xilinx Block RAM module ram8x512(clk,b_datain,a_addr,b_addr,we,a_out,b_out,write_address); parameter AWIDTH=9; parameter DWIDTH=8; input clk; input [DWIDTH-1:0] b_datain; input [AWIDTH-1:0] a_addr,b_addr,write_address; input we; output [DWIDTH-1:0] a_out,b_out; reg [DWIDTH-1:0] mem [0: (1 << AWIDTH)-1]; reg [AWIDTH-1:0] address_latch_a,address_latch_b; always @(posedge clk) begin address_latch_a <=a_addr; end always @(posedge clk) begin address_latch_b<=b_addr; end assign a_out=mem[address_latch_a]; assign b_out=mem[address_latch_b]; always @(posedge clk) begin mem[write_address] <=b_datain; end endmodule |
仕方ないのでUNISIMフォルダにあるRAMB4_S8_S8を使うことにしました。512Wordsx8bitです。これで動作を確認しておきましょう。
合成対象ソース
前章のled.vを流用します。
RAMに counterをアドレスとしてcounterの値を書きます。読み出しは、counter アドレスと ~counterアドレスで読み出します。
//------------------------------------------------------------------- // // This file is automatically generated by VHDL to Verilog Translator. // Ver.1.08 Build Mar.6.2004 // www.sugawara-systems.com // tech-support@sugawara-systems.com // See Original Copyright Notice for property of the file .( somewhere in this file.) // //-------------------------------------------------------------------- //-------------------------------------------- // NP1003 SDRAM & USB template source file // (C) Copyright 2003 Nahitafu Nahitech // http://www.nahitech.com //-------------------------------------------- `timescale 1ns/1ns `define ns 1 `define us (1000*`ns) `define ms (1000*`us) `define sec (1000*`ms) module main ( clk0, clk1, clk2, clk3, user, sd_d, sd_a, sd_bs1, sd_bs0, sd_ldqm, sd_udqm, sd_wen, sd_ras, sd_cas, sd_clk, sd_cke, sd_cs, usb_d, usb_wr, usb_rd, usb_txe, usb_rxf, usb_pwren, usb_rsto ); input clk0; input clk1; input clk2; input clk3; inout [36:0] user ; inout [15:0] sd_d ; output [12:0] sd_a ; output sd_bs1; output sd_bs0; output sd_ldqm; output sd_udqm; output sd_wen; output sd_ras; output sd_cas; output sd_clk; output sd_cke; output sd_cs; inout [7:0] usb_d ; output usb_wr; output usb_rd; input usb_txe; input usb_rxf; input usb_pwren; input usb_rsto; wire clk; wire logich; wire logicl; integer usb_state; wire usb_rxf_node; wire usb_txe_node; wire usb_rx_ready; wire usb_tx_ready; wire usb_received; wire usb_transmitted; wire [7:0] usb_tx_data; wire [7:0] usb_rx_data; wire usb_wr_node; wire usb_rd_node; reg /* conflict */[36:0] user_;//TAK Jun.12.2004 =37'bz; wire /* conflict */[36:0] user; wire [15:0] sd_d; wire [12:0] sd_a; wire sd_bs1; wire sd_bs0; wire sd_ldqm; wire sd_udqm; wire sd_wen; wire sd_ras; wire sd_cas; wire sd_clk; wire sd_cke; wire sd_cs; wire [7:0] usb_d; wire usb_wr; wire usb_rd; reg [25:0] counter; wire [7:0] a_out,b_out; assign {clk}=clk0; assign {logich}=1'b1; assign {logicl}=1'b0; assign {sd_clk}=~ (clk); assign {sd_cs}=1'b1; assign {sd_ras}=1'b1; assign {sd_cas}=1'b1; assign {sd_cke}=1'b0; assign {sd_wen}=1'b1; assign {sd_d}={(15-0+1- 0){1'bz}}; assign {sd_a}={(12-0+1- 0){1'b0}}; assign {sd_bs1}=1'b0; assign {sd_bs0}=1'b0; assign {sd_ldqm}=1'b0; assign {sd_udqm}=1'b0; assign {usb_rd_node}=logich; assign {usb_wr_node}=logicl; assign {usb_rd}=usb_rd_node; assign {usb_wr}=usb_wr_node; assign {usb_d}={(7-0+1- 0){1'bz}}; // TAK Jun.12.2004 assign {user[35:0]}={(35-0+1- 0){1'b0}}; always @(posedge clk) begin if (!usb_rsto) counter <=0; else counter <=counter+1; end always @ (posedge clk ) begin user_[36] <= (usb_txe & usb_rxf); end //always // assign user = user_;//Added for Conflict reslover. assign user[3:0]=counter[25:22]; assign user[36:4]={a_out,b_out,counter[16:0]}; //ram8x512 ram0(.clk(clk),.b_datain(counter[7:0]),.a_addr(counter[8:0]),.b_addr(counter[9:1]),.we(1'b1),.a_out(a_out),.b_out(b_out),.write_address(counter[8:0])); RAMB4_S8_S8 ram0(.DOA(a_out), .DOB(b_out), .ADDRA(counter[8:0]), .ADDRB(~counter[8:0]), .CLKA(clk), .CLKB(clk), .DIA(counter[7:0]), .DIB(counter[7:0]), .ENA(1'b1), .ENB(1'b1), .RSTA(1'b0), .RSTB(1'b0), .WEA(1'b0), .WEB(1'b1)); endmodule |
テストベンチ
前章のLEDプロジェクトを流用します。RTLでは、`define RTLをイネーブルしVCDに結果を書き込みます。
`timescale 1ns/1ps `define CYCLE (10) //(6.522/2) `define RTL module led_test; reg clk0=0; reg clk1; reg clk2; reg clk3; wire [36:0] user ; wire [15:0] sd_d ; wire [12:0] sd_a ; wire sd_bs1; wire sd_bs0; wire sd_ldqm; wire sd_udqm; wire sd_wen; wire sd_ras; wire sd_cas; wire sd_clk; wire sd_cke; wire sd_cs; wire [7:0] usb_d ; wire usb_wr; wire usb_rd; reg usb_txe=0; reg usb_rxf=0; reg usb_pwren=0; reg usb_rsto=0; wire [16:0] counter; wire [7:0] a_out,b_out; main led( .clk0(clk0), .clk1(clk1), .clk2(clk2), .clk3(clk3), .user(user), .sd_d(sd_d), .sd_a(sd_a), .sd_bs1(sd_bs1), .sd_bs0(sd_bs0), .sd_ldqm(sd_ldqm), .sd_udqm(sd_udqm), .sd_wen(sd_wen), .sd_ras(sd_ras), .sd_cas(sd_cas), .sd_clk(sd_clk), .sd_cke(sd_cke), .sd_cs(sd_cs), .usb_d(usb_d), .usb_wr(usb_wr), .usb_rd(usb_rd), .usb_txe(usb_txe), .usb_rxf(usb_rxf), .usb_pwren(usb_pwren), .usb_rsto(usb_rsto) ); always #(`CYCLE) clk0=~clk0; assign a_out=user[36:29]; assign b_out=user[28:21]; assign counter=user[20:4]; initial begin `ifdef RTL $dumpfile("led_rtl.vcd"); $dumpvars(0, led_test); `endif #150; @(negedge clk0); usb_rsto=1; #100000; $finish; end endmodule |
RTLプロジェクト
前章と違うのは、UNISIMのソースを使ったのでそれを追加しています。
遅延シミュレーション
プロジェクトは、前章の遅延シミュレーションと同じです。
前章と同じように合成します。led_test.vだけ`define RTLをコメントアウトして走らせます。
下図は、遅延シミュレーション波形です。最初のクロックエッジで発生しているタイミングエラーは、シミュレータの電源Onからの過渡状態
によるものですから無視してください。
RTLシミュレーションで、VCDで保存した波形が 青い文字になっています。波形を見ればお分かりの通り、RTLシミュレーションでは、時間0
の遅延ですから、クロックの立ち上がりエッジで変化しています。一方遅延シミュレーションでは、クロックエッジから遅れている様子が分かります。counter
は、約10ns、RAMのRead出力であるa_out,b_outは、counter出力よりもさらに遅くカーソル間では、15.293nsかかっている様子が分かります。このようにRTLと比較することで、合成結果の妥当性を簡単に検証することができませす。ちなみに、Xilinxの遅延シミュレーションではRAMが入っていても、Alteraと違ってかなり快適に走るようです。(ネットリストの生成方法がまったく違うことに起因します。)
残念ながら、RAMの動作としては、AlteraとXilinxでは違うようです。Read出力に関してAddress Regで一旦受けるのは変わらないのですが、Write入力に関しては、Xilinxでは、Address Regで受けていないようです。従って、XilinxのRAMはRegisterファイルとしてもなんら問題ありません。