// DDRtest_tb.v //`default_nettype none //Mar.4.2008 Tak.Sugawara marseeさんのテストベンチTOPをRegressionTestがしやすいように書き換えた。 //Mar.4.2008 Test方法追加修正 //Mar.5.2008 Random W/R with burst access 追加 //Mar.6.2008 lfsr22バグ修正 burst_wordsをランダムにするテスト追加 //Mar.6.2008 sim_clockをclk_outに統一 Timeout Check追加 //Mar.7.2008 random routine w/random butst lengthをタスク化 //Mar.9.2008 FIFO待ちバグ修正 //TODO burst read/write test with random pending time `timescale 1ps / 1ps module DDRtest_tb; `include "ddr_parameters.vh" wire [DQ_BITS-1:0] dq; wire [DQS_BITS-1:0] dqs; reg async_reset; wire [DQS_BITS-1:0] ddr_dqs_fpga, ddr_dqs_sdram; wire [DQ_BITS-1:0] ddr_dq_fpga, ddr_dq_sdram; reg [DQS_BITS-1:0] ddr_dqs_fpgan, ddr_dqs_sdramn; reg [DQ_BITS-1:0] ddr_dq_fpgan, ddr_dq_sdramn; wire ddr_clk, ddr_clkb; wire ddr_cke, ddr_csb, ddr_rasb, ddr_casb, ddr_web; wire [DM_BITS-1:0] ddr_dm; wire [1:0] ddr_ba; wire [ADDR_BITS-1:0] ddr_address; wire reset_b; reg enable_o; wire [2:0] cmd; reg sdram_clk; reg sdram_clkb; reg [12:0] sdram_address; reg [1:0] sdram_ba; reg sdram_cke; reg sdram_csb, sdram_rasb, sdram_casb, sdram_web; reg [1:0] sdram_dm; wire ddr_clk_fb; parameter DELAY_TIME = 1500; parameter CLK_PERIOD = 20000; assign cmd = {ddr_rasb, ddr_casb, ddr_web}; always @(posedge ddr_clk, posedge async_reset) if (async_reset) enable_o <= 1'b0; else if (cmd==3'b100) enable_o <= 1'b0; else if (cmd==3'b101) enable_o <= 1'b1; always @ * if (enable_o == 1'b1) ddr_dqs_fpgan <= #DELAY_TIME ddr_dqs_sdram; else ddr_dqs_fpgan <= #DELAY_TIME {DQS_BITS{1'bz}}; always @ * if (enable_o == 1'b1) ddr_dq_fpgan <= #DELAY_TIME ddr_dq_sdram; else ddr_dq_fpgan <= #DELAY_TIME {DQ_BITS{1'bz}}; always @ * if (enable_o == 1'b0) ddr_dqs_sdramn <= #DELAY_TIME ddr_dqs_fpga; else ddr_dqs_sdramn <= #DELAY_TIME {DQS_BITS{1'bz}}; always @ * if (enable_o == 1'b0) ddr_dq_sdramn <= #DELAY_TIME ddr_dq_fpga; else ddr_dq_sdramn <= #DELAY_TIME {DQ_BITS{1'bz}}; assign ddr_dqs_fpga = ddr_dqs_fpgan; assign ddr_dq_fpga = ddr_dq_fpgan; assign ddr_dqs_sdram = ddr_dqs_sdramn; assign ddr_dq_sdram = ddr_dq_sdramn; always @ * begin sdram_clk <= #DELAY_TIME ddr_clk; sdram_clkb <= #DELAY_TIME ddr_clkb; sdram_address <= #DELAY_TIME ddr_address; sdram_ba <= #DELAY_TIME ddr_ba; sdram_cke <= #DELAY_TIME ddr_cke; sdram_csb <= #DELAY_TIME ddr_csb; sdram_rasb <= #DELAY_TIME ddr_rasb; sdram_casb <= #DELAY_TIME ddr_casb; sdram_web <= #DELAY_TIME ddr_web; sdram_dm <= #DELAY_TIME ddr_dm; end //Host IF reg clk_fm_host=0; reg [31:0] address_fm_host=0,input_data_fm_host=0; reg read_fm_host=0,write_fm_host=0; reg [3:0] byte_enable_fm_host=4'hf;//書き込みバイトEnable wire [31:0] output_data_fm_controller; wire fifo_full_fm_controller;//address full または Write Fifo Full wire read_valid_fm_controller; wire initialize_end_fm_controller; wire clk_out; ddr_controller hardware_top( //非同期リセット .async_reset(async_reset), //Host->コントローラ .clk_fm_host(clk_fm_host), .input_address_fm_host(address_fm_host), .input_data_fm_host(input_data_fm_host), .read_fm_host(read_fm_host), .write_fm_host(write_fm_host), .byte_enable_fm_host(byte_enable_fm_host),//書き込みバイトEnable //コントローラ-> Host .clk_out(clk_out), .output_data_fm_controller(output_data_fm_controller), .fifo_full_fm_controller(fifo_full_fm_controller),//address full または Write Fifo Full .read_valid_fm_controller(read_valid_fm_controller), .initialize_end_fm_controller(initialize_end_fm_controller), .sd_a(ddr_address), .sd_dq(ddr_dq_fpga), .sd_ba(ddr_ba), .sd_ras(ddr_rasb), .sd_cas(ddr_casb), .sd_we(ddr_web), .sd_udm(ddr_dm[1]), .sd_ldm(ddr_dm[0]), .sd_udqs(ddr_dqs_fpga[1]), .sd_ldqs(ddr_dqs_fpga[0]), .sd_cs(ddr_csb), .sd_cke(ddr_cke), .sd_ck_n(ddr_clkb), .sd_ck_p(ddr_clk), .sd_ck_fb(ddr_clk_fb) ); assign ddr_clk_fb = ddr_clk; ddr MT46V16M16_inst( .Dq(ddr_dq_sdram), .Dqs(ddr_dqs_sdram), .Addr(sdram_address), .Ba(sdram_ba), .Clk(sdram_clk), .Clk_n(sdram_clkb), .Cke(sdram_cke), .Cs_n(sdram_csb), .Ras_n(sdram_rasb), .Cas_n(sdram_casb), .We_n(sdram_web), .Dm(sdram_dm) ); initial begin async_reset = 1'b0; #1000 async_reset = 1'b1; #20000 async_reset = 1'b0; end always begin #(CLK_PERIOD/2) clk_fm_host = 1'b1 ; #(CLK_PERIOD/2) clk_fm_host = 1'b0 ; end reg [31:0] read_fifo [0: 2**23-1];//24bit fifo //テストメインループ initial begin $timeformat(-9,1,"nsec",8); //準備ができるまで待つ initial_wait; //シングルライト/リード check_random_single_write_read(10); //インクリメンタルチェック check_incremental_single_write_read(10); //バースト ライト/リード 固定アドレス burst_check_fixed_pattern(0,10,32'h5555_5555);// burst_check_fixed_pattern(0,258,32'hAAAA_AAAA);// //バースト ライト/リード ランダムアドレス random_write_read_w_random_bust_length(100000,19);//ループ数 ,最大パースト長+1をセット Mar.7.2009 20以上は仕様外?? #1000000 $finish; end task random_write_read_w_random_bust_length(input integer counts,max_words); reg [23:0] seed_address,write_temp_address,read_temp_address; integer seed_data,write_temp_data,read_temp_data; integer burst_words,burst_words_seed; integer test_counter; begin seed_address=1<<2; seed_data=1; write_temp_address=seed_address; write_temp_data=seed_data; read_temp_address=seed_address; read_temp_data=seed_data; burst_words_seed=1; burst_words=burst_words_seed; test_counter=0; repeat(counts) begin $display("Start burst write random burst_words=%d %t",burst_words,$time); burst_write_random(write_temp_address,write_temp_data,burst_words); //$display("Start burst read random %t",$time); burst_read_random(read_temp_address,burst_words); burst_read_check_random(read_temp_data ,burst_words); test_counter=test_counter+1; if (test_counter%100==0) $display("Pass %d",test_counter); burst_words_seed=lfsr8(burst_words_seed); if(burst_words_seed> max_words) begin burst_words=burst_words_seed% max_words; if (!burst_words) burst_words=1; end end end endtask task initial_wait; begin #10; wait(initialize_end_fm_controller); end endtask task check_random_single_write_read(input integer counts); integer address,write_data,read_data; begin $display("Start check_random_single_write_read %t",$time); repeat(counts) begin address=$random; write_data=$random; single_write(address,write_data); single_read(address,read_data); if (write_data !==read_data) begin $display("In check_random_single_write_read. Error Detected address=%h wd=%h rd=%h",address,write_data,read_data); $stop; end end end endtask task check_incremental_single_write_read(input integer counts); integer address,write_data,read_data; begin $display("Start check_inc_single_write_read %t",$time); address=0; write_data=0; repeat(counts) begin single_write(address,write_data); single_read(address,read_data); if (write_data !==read_data) begin $display("In check_inc_single_write_read. Error Detected address=%h wd=%h rd=%h",address,write_data,read_data); $stop; end address=address+4; write_data=write_data+1; end end endtask task single_write(input integer address,data); begin wait(!fifo_full_fm_controller); @(negedge clk_out); write_fm_host=1; input_data_fm_host=data; address_fm_host=address; @(negedge clk_out); write_fm_host=0; input_data_fm_host=data; end endtask task single_read(input integer address, output [31:0] data); begin wait(!fifo_full_fm_controller );//コントローラがBusyなら待つ @(negedge clk_out);//Here we go! リードコマンド書き込み//Mar.6.2008 clk_outに変更 read_fm_host=1; address_fm_host=address; @(negedge clk_out);//Mar.6.2008 clk_outに変更 read_fm_host=0; wait(read_valid_fm_controller);//データが来るのを待つ @(negedge clk_out);//着た data=output_data_fm_controller;//読み込み end endtask task burst_check_fixed_pattern(input integer address,counts,data); begin burst_write_fixed(address,counts,data); burst_read(address,counts); burst_read_check_fixed(address,counts); end endtask function [21:0] lfsr22 (input [21:0] data); reg lsb; //M系列タップ値は、以下から頂きました。 //http://www.madlabo.com/mad/edat/mathematic/M/index.htm#SEC5 //200001 //0010_0000_0000_0000_0000_0011 begin lsb=data[21] ^ data[1]^data[0]; lfsr22={data[20:0],lsb};//MSB 方向にシフト end endfunction function [7:0] lfsr8 (input [7:0] data); reg lsb; //CD polynominal //1001_1101 begin lsb=data[7] ^ data[4]^data[3] ^data[2]^data[0]; lfsr8={data[6:0],lsb};//MSB 方向にシフト end endfunction //24ビットのダブらないランダムアドレスを得る  //4bytes boundary 0は、不可 function [23:0] get_next_random_address ( input [23:0] old_address); //assert( !old_address); get_next_random_address=lfsr22(old_address >>2) <<2; endfunction task burst_write_random(inout integer seed_address,seed_data ,input integer counts); integer counter; begin //assert(read_fm_host==0); //ライトコマンドをcounts分送出 counter=0; repeat(counts) begin @(negedge clk_out); if (fifo_full_fm_controller) begin write_fm_host=0; wait(!fifo_full_fm_controller); @(negedge clk_out); end write_fm_host=1; input_data_fm_host=seed_data; address_fm_host =seed_address; seed_address=get_next_random_address(seed_address); seed_data=$random(seed_data); counter=counter+1; end @(negedge clk_out); write_fm_host=0; //ライトコマンド送出終わり end endtask task burst_write_fixed(input integer address,counts,data); integer counter; begin //assert(read_fm_host==0); //ライトコマンドをcounts分送出 counter=0; repeat(counts) begin @(negedge clk_out);//Mar.6.2008 clk_outに変更 if (fifo_full_fm_controller) begin write_fm_host=0; wait(!fifo_full_fm_controller); @(negedge clk_out); end write_fm_host=1; input_data_fm_host=data; address_fm_host=address+(counter<<2); counter=counter+1; end @(negedge clk_out); write_fm_host=0; //ライトコマンド送出終わり end endtask `define TIMEOUT_CLKS 50 //*10ns* burst_words task time_out_check_fifo(input integer counts); begin :time_out_exit repeat(`TIMEOUT_CLKS*counts ) begin if (fifo_full_fm_controller) begin//Mar.9.2008 @(negedge clk_out); end else begin @(negedge clk_out); disable time_out_exit;//repeat ループを抜ける end end //`TIME_COUT_COUNT CLK 経ってもFIFO BUSYならエラ-だ。 $display("Time Out Error Please Check H/W Logic %t",$time); $stop; end endtask task time_out_check_read_valid(input integer counts); begin :time_out_exit repeat(`TIMEOUT_CLKS *counts) begin if (!read_valid_fm_controller) begin @(negedge clk_out); end else begin //@(negedge clk_out); disable time_out_exit;//repeat ループを抜ける end end //`TIME_COUT_COUNT CLK 経ってもFIFO BUSYならエラ-だ。 $display("Time Out Error Please Check H/W Logic %t",$time); $stop; end endtask task burst_read(input integer address,counts); integer send_counter,read_counter; begin send_counter=0;//Mar.6.2008 //assert(read_fm_host==0); //リードコマンドをcounts分送出 //assert(!read_valid_fm_controller); fork//コマンドを送っている間にもReadValidは来るので送信と受信は、平行プロセスでなければならない。 begin repeat(counts) begin @(negedge clk_out);//Mar.6.2008 clk_outに変更 if (fifo_full_fm_controller) begin read_fm_host=0; time_out_check_fifo(counts);//Mar.6.2008 タイムアウトチェック追加 //wait(!fifo_full_fm_controller); //@(negedge clk_out); end read_fm_host=1; address_fm_host=address+(send_counter<<2); send_counter=send_counter+1; end @(negedge clk_out); read_fm_host=0; //リードコマンド送出終わり end //リードデータをcounts分読み込む begin read_counter=0; wait(send_counter !==0);//Mar.6.2008 Timeout Check のため repeat(counts) begin @(negedge clk_out);//Read 読み込みは、100MHzで来るので100MHzで受ける if (!read_valid_fm_controller) begin time_out_check_read_valid(counts);//Mar.6.2008タイムアウトチェック追加 //wait(read_valid_fm_controller); //@(negedge clk_out);//Read 読み込みは、100MHzで来るので100MHzで受ける end read_fifo[read_counter]=output_data_fm_controller; read_counter=read_counter+1; end end join end endtask task burst_read_check_fixed(input integer counts,data); integer counter; begin counter=0; repeat(counts) begin if (read_fifo[counter] !==data) begin $display("Error Detected burst_read_check_fixed %t",$time); $stop; end counter=counter+1; end end endtask task burst_read_check_random(inout integer seed_data,input integer counts); integer counter; begin counter=0; repeat(counts) begin if (read_fifo[counter] !==seed_data) begin $display("Error Detected burst_read_check_random %t %h %h ",$time,read_fifo[counter],seed_data); $stop; end counter=counter+1; seed_data=$random(seed_data); end end endtask task burst_read_random(inout integer seed_address,input integer counts); integer send_counter,read_counter; begin send_counter=0; //assert(read_fm_host==0); //リードコマンドをcounts分送出 //assert(!read_valid_fm_controller); fork//コマンドを送っている間にもReadValidは来るので送信と受信は、平行プロセスでなければならない。 begin repeat(counts) begin @(negedge clk_out);//Mar.6.2008 clk_outに変更 if (fifo_full_fm_controller) begin read_fm_host=0; wait(!fifo_full_fm_controller); @(negedge clk_out); end read_fm_host=1; address_fm_host=seed_address; seed_address=get_next_random_address(seed_address); send_counter=send_counter+1; end @(negedge clk_out); read_fm_host=0; //リードコマンド送出終わり end //リードデータをcounts分読み込む begin read_counter=0; wait(send_counter !==0);//Mar.6.2008 Timeout Check のため repeat(counts) begin @(negedge clk_out);//Read 読み込みは、100MHzで来るので100MHzで受ける if (!read_valid_fm_controller) begin time_out_check_read_valid(counts);//Mar.6.2008 タイムアウトチェック追加 //wait(read_valid_fm_controller); //@(negedge clk_out);//Read 読み込みは、100MHzで来るので100MHzで受ける end read_fifo[read_counter]=output_data_fm_controller; read_counter=read_counter+1; end end join end endtask endmodule