上一节已经成功地测试了DDR的各个链路以及各个地址的读写操作,这一节就来完成模拟从PC端发出数据经过USB最终给到DDR端口,之前已经实现了DDR的各个链路的验证,同时也实现了数据的读写。先看一下本次实验要实现的链路结构。
框图:
在之前的文章中已经指出,我们所做的实验USB的写入和读出的数据宽度为16bit,但是我们所i设计的DDR的突发长度为64,,两者的数据宽度不一致,如果是直接这样使用的话会导致DDR的高48bit的浪费,所以要先把usb端输出的16bit的数据宽度,通过拼接的方法拼接城64bit 的宽度再发送到DDR中。
USB端数据拼接的时序设计:
USB端数据拼接的代码:
1 // ********************************************************************************* 2 // Project Name : OSXXXX 3 // Author : 李国勇 4 // weixin : li15226499835 5 // Website : https://www.cnblogs.com/lgy-gdeu/ 6 // Create Time : 2019-10-30 7 // File Name : .v 8 // Module Name : 9 // Called By : 10 // Abstract : 11 // 12 // CopyRight(c) 2018, OpenSoc Studio.. 13 // All Rights Reserved 14 // 15 // ********************************************************************************* 16 // Modification History: 17 // Date By Version Change Description 18 // ----------------------------------------------------------------------- 19 // 2019/10/30 李国勇 1.0 Original 20 // 21 // ********************************************************************************* 22 `timescale 1ns/1ns 23 24 module usb_read( 25 // system signals 26 input s_rst_n , 27 // system signals 28 input usb_ifclk , 29 input usb_full , 30 input usb_empty , 31 output wire usb_slcs , 32 output wire usb_slwr , 33 output wire usb_slrd , 34 output wire usb_sloe , 35 output wire [ 1:0] usb_fifoadr , 36 input [15:0] usb_fdata , 37 // User Data 38 output reg usb_wr_en , 39 output reg [63:0] usb_wr_data 40 ); 41 42 //========================================================================\ 43 // =========== Define Parameter and Internal signals =========== 44 //========================================================================/ 45 46 reg usb_slrd_reg ; 47 reg [ 1:0] data_cnt ; 48 49 50 //============================================================================= 51 //************** Main Code ************** 52 //============================================================================= 53 assign usb_slcs = 1'b0; 54 assign usb_slrd = (usb_empty == 1'b1 && usb_slrd_reg == 1'b0) ? 1'b0 : 1'b1; 55 assign usb_slwr = 1'b1; 56 assign usb_sloe = 1'b0; 57 assign usb_fifoadr = 2'b00; // 2,4,6,8 58 59 60 always @(posedge usb_ifclk or negedge s_rst_n) begin 61 if(s_rst_n == 1'b0) 62 usb_slrd_reg <= 1'b1; 63 else if(usb_empty == 1'b1) 64 usb_slrd_reg <= 1'b0; 65 else 66 usb_slrd_reg <= 1'b1; 67 end 68 69 always @(posedge usb_ifclk or negedge s_rst_n) begin 70 if(s_rst_n == 1'b0) 71 usb_wr_data <= 64'h0; 72 else if(usb_slrd == 1'b0) 73 usb_wr_data <= {usb_wr_data[47:0], usb_fdata}; 74 end 75 76 always @(posedge usb_ifclk or negedge s_rst_n) begin 77 if(s_rst_n == 1'b0) 78 data_cnt <= 'd0; 79 else if(usb_slrd == 1'b0) 80 data_cnt <= data_cnt + 1'b1; 81 end 82 83 always @(posedge usb_ifclk or negedge s_rst_n) begin 84 if(s_rst_n == 1'b0) 85 usb_wr_en <= 1'b0; 86 else if(usb_slrd == 1'b0 && data_cnt == 'd3) 87 usb_wr_en <= 1'b1; 88 else 89 usb_wr_en <= 1'b0; 90 end 91 92 endmodule
那么处理完USB端的数据位宽的问题了,接下来就是DDR的驱动端吧,在之前的学习中我们就已经了解到,在DDR开始写入数据的时候,必须已经有数据存在书存储端了,不然一开始就给DDR写数据的命令的话,容易造成对数据的读空。所以还是按照之前的时序来给DDR的系数据命令。
DDR端的时序图:
我在本次实验中准备传递一幅640*480的图片,一个像素点是16bit,
total:480*640=307200
突发次数:307200/4/16=4800
DDR端的数据处理代码:
1 module ddr3_drive( 2 // system signals 3 input wr_clk , 4 input s_rst_n , 5 // DDR3 User Interfaces 6 input p0_wr_en , 7 output reg p0_cmd_en , 8 output wire [ 2:0] p0_cmd_instr , 9 output wire [ 5:0] p0_cmd_bl , 10 output reg [29:0] p0_byte_addr , 11 output wire [ 7:0] p0_wr_mask , 12 output reg p1_cmd_en , 13 output wire [ 2:0] p1_cmd_instr , 14 output wire [ 5:0] p1_cmd_bl , 15 output reg [29:0] p1_byte_addr , 16 output reg p1_rd_en , 17 input [63:0] p1_rd_data 18 ); 19 20 //========================================================================\ 21 // =========== Define Parameter and Internal signals =========== 22 //========================================================================/ 23 localparam BURST_END = 'd10 ; 24 // localparam BURST_END = 4800 ; 25 26 reg [ 3:0] wr_cnt ; 27 reg [15:0] wr_bl_cnt ; 28 29 //============================================================================= 30 //************** Main Code ************** 31 //============================================================================= 32 assign p0_cmd_instr = 3'b000; 33 assign p0_cmd_bl = 'd15; 34 assign p0_wr_mask = 8'h0; 35 assign p1_cmd_instr = 3'b001; 36 assign p1_cmd_bl = 'd15; 37 38 always @(posedge wr_clk or negedge s_rst_n) begin 39 if(s_rst_n == 1'b0) 40 wr_cnt <= 'd0; 41 else if(p0_wr_en == 1'b1) 42 wr_cnt <= wr_cnt + 1'b1; 43 end 44 45 always @(posedge wr_clk or negedge s_rst_n) begin 46 if(s_rst_n == 1'b0) 47 p0_cmd_en <= 1'b0; 48 else if(p0_wr_en == 1'b1 && wr_cnt == 'd15) 49 p0_cmd_en <= 1'b1; 50 else 51 p0_cmd_en <= 1'b0; 52 end 53 54 always @(posedge wr_clk or negedge s_rst_n) begin 55 if(s_rst_n == 1'b0) 56 p0_byte_addr <= 'd0; 57 else if(p0_cmd_en == 1'b1 && wr_bl_cnt >= (BURST_END-1)) 58 p0_byte_addr <= 'd0; 59 else if(p0_cmd_en == 1'b1) 60 p0_byte_addr <= p0_byte_addr + 'd128; 61 end 62 63 always @(posedge wr_clk or negedge s_rst_n) begin 64 if(s_rst_n == 1'b0) 65 wr_bl_cnt <= 'd0; 66 else if(p0_cmd_en == 1'b1 && wr_bl_cnt >= (BURST_END-1)) 67 wr_bl_cnt <= 'd0; 68 else if(p0_cmd_en == 1'b1) 69 wr_bl_cnt <= wr_bl_cnt + 1'b1; 70 end 71 72 endmodule
在联调的时候注意时钟的统一,有问题欢迎微信一起探讨:
总体的代码:
TB:
1 `timescale 1ps/1ps 2 3 module tb_top; 4 5 parameter C3_MEMCLK_PERIOD = 20000; 6 7 8 reg ddr3_ref_clk; 9 reg usb_ifclk; 10 reg ddr3_rst_n; 11 wire c3_calib_done; 12 reg wr_trig; 13 wire usb_slrd; 14 reg [15:0] usb_fdata; 15 16 17 initial begin 18 ddr3_ref_clk = 1; 19 usb_ifclk = 1; 20 ddr3_rst_n <= 0; 21 #20000; 22 ddr3_rst_n <= 1; 23 end 24 25 initial begin 26 wr_trig <= 0; 27 @(posedge c3_calib_done) 28 #100000 29 wr_trig <= 1; 30 #25600 31 wr_trig <= 0; 32 end 33 34 always #(C3_MEMCLK_PERIOD/2) ddr3_ref_clk = ~ddr3_ref_clk; 35 always #(C3_MEMCLK_PERIOD/2) usb_ifclk = ~usb_ifclk; 36 37 always @(posedge usb_ifclk or negedge ddr3_rst_n) begin 38 if(ddr3_rst_n == 1'b0) 39 usb_fdata <= 'd0; 40 else if(usb_slrd == 1'b0) 41 usb_fdata <= usb_fdata + 1'b1; 42 end 43 44 wire [15:0] mcb3_dram_dq ; 45 wire [12:0] mcb3_dram_a ; 46 wire [2:0] mcb3_dram_ba ; 47 wire mcb3_dram_ras_n ; 48 wire mcb3_dram_cas_n ; 49 wire mcb3_dram_we_n ; 50 wire mcb3_dram_odt ; 51 wire mcb3_dram_reset_n ; 52 wire mcb3_dram_cke ; 53 wire mcb3_dram_ck ; 54 wire mcb3_dram_ck_n ; 55 wire mcb3_dram_dm ; 56 wire mcb3_dram_udqs ; 57 wire mcb3_dram_udqs_n ; 58 wire mcb3_dram_dqs ; 59 wire mcb3_dram_dqs_n ; 60 wire mcb3_rzq ; 61 wire mcb3_zio ; 62 wire mcb3_dram_udm ; 63 64 top top_inst( 65 // system signals 66 .c3_sys_clk (ddr3_ref_clk ), 67 .c3_sys_rst_i (ddr3_rst_n ), 68 // DDR3 Interfaces 69 .mcb3_dram_dq (mcb3_dram_dq ), 70 .mcb3_dram_a (mcb3_dram_a ), 71 .mcb3_dram_ba (mcb3_dram_ba ), 72 .mcb3_dram_ras_n (mcb3_dram_ras_n ), 73 .mcb3_dram_cas_n (mcb3_dram_cas_n ), 74 .mcb3_dram_we_n (mcb3_dram_we_n ), 75 .mcb3_dram_odt (mcb3_dram_odt ), 76 .mcb3_dram_reset_n (mcb3_dram_reset_n ), 77 .mcb3_dram_cke (mcb3_dram_cke ), 78 .mcb3_dram_ck (mcb3_dram_ck ), 79 .mcb3_dram_ck_n (mcb3_dram_ck_n ), 80 .mcb3_dram_dm (mcb3_dram_dm ), 81 .mcb3_dram_udqs (mcb3_dram_udqs ), 82 .mcb3_dram_udqs_n (mcb3_dram_udqs_n ), 83 .mcb3_dram_dqs (mcb3_dram_dqs ), 84 .mcb3_dram_dqs_n (mcb3_dram_dqs_n ), 85 .mcb3_rzq (mcb3_rzq ), 86 .mcb3_zio (mcb3_zio ), 87 .mcb3_dram_udm (mcb3_dram_udm ), 88 // USB interfaces 89 .usb_ifclk (usb_ifclk ), 90 .usb_full (), 91 .usb_empty (1'b1 ), 92 .usb_slcs (), 93 .usb_slwr (), 94 .usb_slrd (usb_slrd ), 95 .usb_sloe (), 96 .usb_fifoadr (), 97 .usb_fdata (usb_fdata ) 98 ); 99 /* 100 ddr3_model_c3 u_mem_c3( 101 .ck (mcb3_dram_ck), 102 .ck_n (mcb3_dram_ck_n), 103 .cke (mcb3_dram_cke), 104 .cs_n (1'b0), 105 .ras_n (mcb3_dram_ras_n), 106 .cas_n (mcb3_dram_cas_n), 107 .we_n (mcb3_dram_we_n), 108 .dm_tdqs ({mcb3_dram_udm,mcb3_dram_dm}), 109 .ba (mcb3_dram_ba), 110 .addr (mcb3_dram_a), 111 .dq (mcb3_dram_dq), 112 .dqs ({mcb3_dram_udqs,mcb3_dram_dqs}), 113 .dqs_n ({mcb3_dram_udqs_n,mcb3_dram_dqs_n}), 114 .tdqs_n (), 115 .odt (mcb3_dram_odt), 116 .rst_n (mcb3_dram_reset_n) 117 ); 118 119 PULLDOWN zio_pulldown3 (.O(mcb3_zio)); PULLDOWN rzq_pulldown3 (.O(mcb3_rzq)); 120 */ 121 endmodule
usb_read:
1 // ********************************************************************************* 2 // Project Name : OSXXXX 3 // Author : 李国勇 4 // weixin : li15226499835 5 // Website : https://www.cnblogs.com/lgy-gdeu/ 6 // Create Time : 2019-10-30 7 // File Name : .v 8 // Module Name : 9 // Called By : 10 // Abstract : 11 // 12 // CopyRight(c) 2018, OpenSoc Studio.. 13 // All Rights Reserved 14 // 15 // ********************************************************************************* 16 // Modification History: 17 // Date By Version Change Description 18 // ----------------------------------------------------------------------- 19 // 2019/10/30 李国勇 1.0 Original 20 // 21 // ********************************************************************************* 22 `timescale 1ns/1ns 23 24 module usb_read( 25 // system signals 26 input s_rst_n , 27 // system signals 28 input usb_ifclk , 29 input usb_full , 30 input usb_empty , 31 output wire usb_slcs , 32 output wire usb_slwr , 33 output wire usb_slrd , 34 output wire usb_sloe , 35 output wire [ 1:0] usb_fifoadr , 36 input [15:0] usb_fdata , 37 // User Data 38 output reg usb_wr_en , 39 output reg [63:0] usb_wr_data 40 ); 41 42 //========================================================================\ 43 // =========== Define Parameter and Internal signals =========== 44 //========================================================================/ 45 46 reg usb_slrd_reg ; 47 reg [ 1:0] data_cnt ; 48 49 50 //============================================================================= 51 //************** Main Code ************** 52 //============================================================================= 53 assign usb_slcs = 1'b0; 54 assign usb_slrd = (usb_empty == 1'b1 && usb_slrd_reg == 1'b0) ? 1'b0 : 1'b1; 55 assign usb_slwr = 1'b1; 56 assign usb_sloe = 1'b0; 57 assign usb_fifoadr = 2'b00; // 2,4,6,8 58 59 60 always @(posedge usb_ifclk or negedge s_rst_n) begin 61 if(s_rst_n == 1'b0) 62 usb_slrd_reg <= 1'b1; 63 else if(usb_empty == 1'b1) 64 usb_slrd_reg <= 1'b0; 65 else 66 usb_slrd_reg <= 1'b1; 67 end 68 69 always @(posedge usb_ifclk or negedge s_rst_n) begin 70 if(s_rst_n == 1'b0) 71 usb_wr_data <= 64'h0; 72 else if(usb_slrd == 1'b0) 73 usb_wr_data <= {usb_wr_data[47:0], usb_fdata}; 74 end 75 76 always @(posedge usb_ifclk or negedge s_rst_n) begin 77 if(s_rst_n == 1'b0) 78 data_cnt <= 'd0; 79 else if(usb_slrd == 1'b0) 80 data_cnt <= data_cnt + 1'b1; 81 end 82 83 always @(posedge usb_ifclk or negedge s_rst_n) begin 84 if(s_rst_n == 1'b0) 85 usb_wr_en <= 1'b0; 86 else if(usb_slrd == 1'b0 && data_cnt == 'd3) 87 usb_wr_en <= 1'b1; 88 else 89 usb_wr_en <= 1'b0; 90 end 91 92 endmodule
ddr_drive:
1 module ddr3_drive( 2 // system signals 3 input wr_clk , 4 input s_rst_n , 5 // DDR3 User Interfaces 6 input p0_wr_en , 7 output reg p0_cmd_en , 8 output wire [ 2:0] p0_cmd_instr , 9 output wire [ 5:0] p0_cmd_bl , 10 output reg [29:0] p0_byte_addr , 11 output wire [ 7:0] p0_wr_mask , 12 output reg p1_cmd_en , 13 output wire [ 2:0] p1_cmd_instr , 14 output wire [ 5:0] p1_cmd_bl , 15 output reg [29:0] p1_byte_addr , 16 output reg p1_rd_en , 17 input [63:0] p1_rd_data 18 ); 19 20 //========================================================================\ 21 // =========== Define Parameter and Internal signals =========== 22 //========================================================================/ 23 localparam BURST_END = 'd10 ; 24 // localparam BURST_END = 4800 ; 25 26 reg [ 3:0] wr_cnt ; 27 reg [15:0] wr_bl_cnt ; 28 29 //============================================================================= 30 //************** Main Code ************** 31 //============================================================================= 32 assign p0_cmd_instr = 3'b000; 33 assign p0_cmd_bl = 'd15; 34 assign p0_wr_mask = 8'h0; 35 assign p1_cmd_instr = 3'b001; 36 assign p1_cmd_bl = 'd15; 37 38 always @(posedge wr_clk or negedge s_rst_n) begin 39 if(s_rst_n == 1'b0) 40 wr_cnt <= 'd0; 41 else if(p0_wr_en == 1'b1) 42 wr_cnt <= wr_cnt + 1'b1; 43 end 44 45 always @(posedge wr_clk or negedge s_rst_n) begin 46 if(s_rst_n == 1'b0) 47 p0_cmd_en <= 1'b0; 48 else if(p0_wr_en == 1'b1 && wr_cnt == 'd15) 49 p0_cmd_en <= 1'b1; 50 else 51 p0_cmd_en <= 1'b0; 52 end 53 54 always @(posedge wr_clk or negedge s_rst_n) begin 55 if(s_rst_n == 1'b0) 56 p0_byte_addr <= 'd0; 57 else if(p0_cmd_en == 1'b1 && wr_bl_cnt >= (BURST_END-1)) 58 p0_byte_addr <= 'd0; 59 else if(p0_cmd_en == 1'b1) 60 p0_byte_addr <= p0_byte_addr + 'd128; 61 end 62 63 always @(posedge wr_clk or negedge s_rst_n) begin 64 if(s_rst_n == 1'b0) 65 wr_bl_cnt <= 'd0; 66 else if(p0_cmd_en == 1'b1 && wr_bl_cnt >= (BURST_END-1)) 67 wr_bl_cnt <= 'd0; 68 else if(p0_cmd_en == 1'b1) 69 wr_bl_cnt <= wr_bl_cnt + 1'b1; 70 end 71 72 endmodule