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ファイルとしてもなんら問題ありません。
