• FPGA project : sdram


    sdram读写控制器

    实验目标:

    设计并实现一个 SDRAM 数据读写控制器,使用 PC 机通过串口向 SDRAM 写入 10 字
    节数据,并将写入的 10 字节数据读出,通过串口回传至 PC 机,在串口助手上位机上打印
    显示回传数据。

    框图设计:

    第一部分:

    sdram基本操作实的实现sdram_ctrl

    要实现数据的读写,还要有初始化和刷新操作。所以该模块要有分别产生这四条指令的模块。

    由于时序冲突问题,刷新,和读写指令存在优先级的问题。所以还应有仲裁模块。

    如下:

    指令产生模块应该有指令端口,bank地址端口,行列地址端口,结束标志信号。

    刷新模块的请求信号传向仲裁模块,反馈给刷新模块一个使能信号。

     写指令模块的写数据,写地址,写突发长度。必不可少。

     

     

    需要注意的是有几个输入端口是外界给的,有几个输出端口直接输出出去。

    整体:

     

     第二部分:

    sdram控制器sdram_top

    fifo控制模块,实现sdram读写数据的跨时钟域处理。

     

     

     第三部分:

    uart_sdram。uart与sdram的数据交互与最顶层模块设计。

     指令:

    1,取消设备选择:1XXX;

    2,无操作指令:0111;

    3,配置模式指令:0000;+ addr A12~A0

    4,预充电指令:0010;+ addr

    5,自动刷新与自刷新指令:0001;

    6,激活指令:0011;+addr/bank

    7,写指令:0100;+bank/col;

    8,读指令:0101;+bank/col;

    明天完成初始化模块,加油!!!

    这个sdram读写控制器工程确实挺大的。

    代码设计:

    sdram_ctrl:

    sdram_init:

    设计思路:

    1 预充电指令,在写入0010指令+A10 == 1 之前,先等待200us,加载稳定时钟,并传递空操作指令。

    2 写入预充电之后要等待TRP = 2  ,并传递空操作指令0111。

    3 TRP时间结束后,写入自动刷新指令0001,并等待TRC = 7 ,并传递空操作指令。

    4 TRC时间结束后,再次刷新指令。

    5 TRC时间结束后,模式配置寄存器指令0000。+A11~A0;并等待TMRD = 时间,并传递空操作。

    6 等待TMRD结束后,完成初始化。

    时序图:
    代码: 
    1. // 初始化模块,产生控指令时序,预充电时序,刷新时序,模式配置时序。sys_clk == 100mHz
    2. module sdram_init(
    3. input wire sys_clk ,
    4. input wire sys_rst_n ,
    5. output reg [3:0] init_cmd ,
    6. output reg [1:0] init_ba ,
    7. output reg [12:0] init_addr ,
    8. output reg init_end
    9. );
    10. // parameter
    11. parameter T_POWER = 200_00 , // 等待时钟稳定。200us。
    12. T_RP = 2 , // 2个时钟周期的预充电时间。
    13. T_RFC = 7 , // 7个时钟周期的刷新时间。
    14. T_MRD = 3 , // 3个时钟周期的模式配置时间。
    15. MAX_CNT_AR= 8 ; // 刷新次数。
    16. localparam INIT_NOP = 4'b0111 , // 空指令
    17. INIT_PREC = 4'b0010 , // 预充电
    18. INIT_REF = 4'b0001 , // 自动刷新
    19. INIT_MOD = 4'b0000 ; // 模式配置
    20. localparam INIT_IDLE = 8'b0000_0001 ,
    21. INIT_PRE = 8'b0000_0010 , // 预充电
    22. INIT_TRP = 8'b0000_0100 ,
    23. INIT_AR = 8'b0000_1000 , // 刷新
    24. INIT_TFR = 8'b0001_0000 ,
    25. INIT_MRS = 8'b0010_0000 , // 模式配置
    26. INIT_TMRD = 8'b0100_0000 ,
    27. INIT_ENDS = 8'b1000_0000 ; // 完成
    28. // reg signal define
    29. reg [7:0] state_c ;
    30. reg [7:0] state_n ;
    31. reg [15:0] cnt_init ;
    32. reg [3:0] cnt_ar ; // 记录刷新次数,以产生状态跳转条件。
    33. // wire signal define
    34. wire INIT_IDLEtoINIT_PRE ;
    35. wire INIT_TRPtoINIT_AR ;
    36. wire INIT_TFRtoINIT_MRS ;
    37. wire INIT_TFRtoINIT_AR ;
    38. wire INIT_TMRDtoINIT_ENDS;
    39. /************************************************************************/
    40. // reg [7:0] state_c ;
    41. always @(posedge sys_clk or negedge sys_rst_n) begin
    42. if(~sys_rst_n)
    43. state_c <= INIT_IDLE ;
    44. else
    45. state_c <= state_n ;
    46. end
    47. // reg [7:0] state_n ;
    48. always @(*) begin
    49. case(state_c)
    50. INIT_IDLE : if(INIT_IDLEtoINIT_PRE)
    51. state_n = INIT_PRE ;
    52. else
    53. state_n = INIT_IDLE ;
    54. INIT_PRE : state_n = INIT_TRP ;
    55. INIT_TRP : if(INIT_TRPtoINIT_AR)
    56. state_n = INIT_AR ;
    57. else
    58. state_n = INIT_TRP ;
    59. INIT_AR : state_n = INIT_TFR ;
    60. INIT_TFR : if(INIT_TFRtoINIT_MRS)
    61. state_n = INIT_MRS ;
    62. else if(INIT_TFRtoINIT_AR) // 没有达到规定的刷新次数,回到刷新指令。
    63. state_n = INIT_AR ;
    64. else
    65. state_n = INIT_TFR ;
    66. INIT_MRS : state_n = INIT_TMRD ;
    67. INIT_TMRD : if(INIT_TMRDtoINIT_ENDS)
    68. state_n = INIT_ENDS ;
    69. else
    70. state_n = INIT_TMRD ;
    71. INIT_ENDS : state_n = INIT_ENDS ; // 保持在此状态。
    72. default : state_n = INIT_IDLE ;
    73. endcase
    74. end
    75. assign INIT_IDLEtoINIT_PRE = (state_c == INIT_IDLE) && (cnt_init == T_POWER - 1) ;
    76. assign INIT_TRPtoINIT_AR = (state_c == INIT_TRP ) && (cnt_init == T_RP - 1) ;
    77. assign INIT_TFRtoINIT_MRS = (state_c == INIT_TFR ) && ((cnt_ar == MAX_CNT_AR - 1) && (cnt_init == T_RFC - 1)) ;
    78. assign INIT_TFRtoINIT_AR = (state_c == INIT_TFR ) && ((cnt_ar != MAX_CNT_AR - 1) && (cnt_init == T_RFC - 1)) ;
    79. assign INIT_TMRDtoINIT_ENDS = (state_c == INIT_TMRD) && (cnt_init == T_MRD - 1) ;
    80. // reg [15:0] cnt_init ;
    81. always @(posedge sys_clk or negedge sys_rst_n) begin
    82. if(~sys_rst_n)
    83. cnt_init <= 16'd0 ;
    84. else
    85. case (state_c)
    86. INIT_IDLE : if(cnt_init == T_POWER - 1)
    87. cnt_init <= 16'd0 ;
    88. else
    89. cnt_init <= cnt_init + 1'b1 ;
    90. INIT_PRE : cnt_init <= 16'd0 ;
    91. INIT_TRP : if(cnt_init == T_RP - 1)
    92. cnt_init <= 16'd0 ;
    93. else
    94. cnt_init <= cnt_init + 1'b1 ;
    95. INIT_AR : cnt_init <= 16'd0 ;
    96. INIT_TFR : if(cnt_init == T_RFC - 1)
    97. cnt_init <= 16'd0 ;
    98. else
    99. cnt_init <= cnt_init + 1'b1 ;
    100. INIT_MRS : cnt_init <= 16'd0 ;
    101. INIT_TMRD : if(cnt_init == T_MRD - 1)
    102. cnt_init <= 16'd0 ;
    103. else
    104. cnt_init <= cnt_init + 1'b1 ;
    105. INIT_ENDS : cnt_init <= 16'd0 ;
    106. default : cnt_init <= 16'd0 ;
    107. endcase
    108. end
    109. // reg [3:0] cnt_ar ;
    110. always @(posedge sys_clk or negedge sys_rst_n) begin
    111. if(~sys_rst_n)
    112. cnt_ar <= 4'd0 ;
    113. else if((state_c == INIT_TFR) && (cnt_init == T_RFC - 1) && (cnt_ar == MAX_CNT_AR - 1))
    114. cnt_ar <= 4'd0 ;
    115. else if((state_c == INIT_TFR) && (cnt_init == T_RFC - 1))
    116. cnt_ar <= cnt_ar + 1'b1 ;
    117. else
    118. cnt_ar <= cnt_ar ;
    119. end
    120. // reg [3:0] init_cmd ,
    121. always @(posedge sys_clk or negedge sys_rst_n) begin
    122. if(~sys_rst_n)
    123. init_cmd <= INIT_NOP ;
    124. else
    125. case (state_c)
    126. INIT_IDLE : init_cmd <= INIT_NOP ;
    127. INIT_PRE : init_cmd <= INIT_PREC;
    128. INIT_TRP : init_cmd <= INIT_NOP ;
    129. INIT_AR : init_cmd <= INIT_REF ;
    130. INIT_TFR : init_cmd <= INIT_NOP ;
    131. INIT_MRS : init_cmd <= INIT_MOD ;
    132. INIT_TMRD : init_cmd <= INIT_NOP ;
    133. INIT_ENDS : init_cmd <= INIT_NOP ;
    134. default : init_cmd <= INIT_NOP ;
    135. endcase
    136. end
    137. // reg [1:0] init_ba ,
    138. // reg [12:0] init_addr ,
    139. always @(posedge sys_clk or negedge sys_rst_n) begin
    140. if(~sys_rst_n) begin
    141. init_ba <= 2'b11 ;
    142. init_addr <= 13'h1FFF ;
    143. end
    144. else if(state_c == INIT_MRS) begin
    145. init_ba <= 2'b00 ;
    146. init_addr <= 13'b000_0_00_011_0_111 ;
    147. end
    148. else begin
    149. init_ba <= 2'b11 ;
    150. init_addr <= 13'h1FFF ;
    151. end
    152. end
    153. // reg init_end
    154. always @(posedge sys_clk or negedge sys_rst_n) begin
    155. if(~sys_rst_n)
    156. init_end <= 1'b0 ;
    157. else if(state_c == INIT_ENDS)
    158. init_end <= 1'b1 ;
    159. else
    160. init_end <= init_end ;
    161. end
    162. endmodule
    仿真: 
    1. `timescale 1ns/1ns
    2. module test_sdram_init ();
    3. reg sys_clk ; // 100mHz
    4. reg sys_rst_n ;
    5. wire [3:0] init_cmd ;
    6. wire [1:0] init_ba ;
    7. wire [12:0] init_addr ;
    8. wire init_end ;
    9. sdram_init sdram_init_inst(
    10. .sys_clk ( sys_clk ) ,
    11. .sys_rst_n ( sys_rst_n) ,
    12. .init_cmd ( init_cmd ) ,
    13. .init_ba ( init_ba ) ,
    14. .init_addr ( init_addr) ,
    15. .init_end ( init_end )
    16. );
    17. parameter CYCLE = 10 ; // 10ns
    18. initial begin
    19. sys_clk = 1'b1 ;
    20. sys_rst_n <= 1'b0 ;
    21. #(CYCLE) ;
    22. sys_rst_n <= 1'b1 ;
    23. #(CYCLE * 250_00) ;
    24. $stop ;
    25. end
    26. always #(CYCLE / 2) sys_clk = ~sys_clk ;
    27. endmodule

    sdram_aref:

    设计思路: 

    分析时序图可知,刷新模块要做的是先传预充电时序,然后传刷新时序>=2次。简化版的初始化。

    自动刷新周期为7.5us。设参数MAX_CNT_REF = 750.

    在初始化结束信号拉高后,cnt_750us开始计数,计满后aref_req拉高,等待仲裁模块给出aref_en拉高,开始进行刷新状态机跳转。当跳转到预充电命令时,说明已经开始刷新了,aref_req拉低。

    根据时序,绘制状态跳转。

    当进入结束状态时,发出一个周期的aref_end==1信号,仲裁模块把aref_en拉低。完成一次刷新。

    cnt_750us计数器是在init_end==1后循环计数的。

    cnt_ar记录刷新次数,要刷新两次才可以。

    时序图:

     代码:
    1. // 模块说明:刷新模块,在初始化完成后,以750us为周期进行刷新时序的输出(要受仲裁模块控制),但刷新周期不会大于750us。
    2. module sdram_aref(
    3. input wire sys_clk ,
    4. input wire sys_rst_n ,
    5. input wire init_end ,
    6. input wire aref_en ,
    7. output reg aref_req ,
    8. output reg [3:0] aref_cmd ,
    9. output wire [1:0] aref_ba ,
    10. output wire [12:0] aref_addr ,
    11. output wire aref_end
    12. );
    13. // parameter
    14. parameter MAX_CNT_750US = 750 ;
    15. // localparam
    16. localparam T_RP = 2 , // 2个时钟周期的预充电时间。
    17. T_RFC = 7 , // 7个时钟周期的刷新时间。
    18. MAX_CNT_AR = 2 , // 刷新次数。
    19. AREF_NOP = 4'b0111 , // 空指令
    20. AREF_PREC = 4'b0010 , // 预充电
    21. AREF_REFC = 4'b0001 ; // 自动刷新,指令与状态机命名冲突了,后面加个C。
    22. localparam AREF_IDLE = 6'b00_0001 ,
    23. AREF_PCHA = 6'b00_0010 ,
    24. AREF_TRP = 6'b00_0100 ,
    25. AREF_REF = 6'b00_1000 ,
    26. AREF_TRF = 6'b01_0000 ,
    27. AREF_END = 6'b10_0000 ;
    28. // reg signal define
    29. reg [5:0] state_c ;
    30. reg [5:0] state_n ;
    31. reg [9:0] cnt_750us ;
    32. reg [3:0] cnt_aref ;
    33. reg cnt_ar ;
    34. // wire signal define
    35. wire AREF_IDLEtoAREF_PCHA;
    36. wire AREF_TRPtoAREF_REF ;
    37. wire AREF_TRFtoAREF_REF ;
    38. wire AREF_TRFtoAREF_END ;
    39. /*************************************************************/
    40. // reg [5:0] state_c ;
    41. always @(posedge sys_clk or negedge sys_rst_n) begin
    42. if(~sys_rst_n)
    43. state_c <= AREF_IDLE ;
    44. else
    45. state_c <= state_n ;
    46. end
    47. // reg [5:0] state_n ;
    48. always @(*) begin
    49. case(state_c)
    50. AREF_IDLE : if(AREF_IDLEtoAREF_PCHA)
    51. state_n = AREF_PCHA ;
    52. else
    53. state_n = AREF_IDLE ;
    54. AREF_PCHA : state_n = AREF_TRP ;
    55. AREF_TRP : if(AREF_TRPtoAREF_REF)
    56. state_n = AREF_REF ;
    57. else
    58. state_n = AREF_TRP ;
    59. AREF_REF : state_n = AREF_TRF ;
    60. AREF_TRF : if(AREF_TRFtoAREF_END)
    61. state_n = AREF_END ;
    62. else if(AREF_TRFtoAREF_REF)
    63. state_n = AREF_REF ;
    64. else
    65. state_n = AREF_TRF ;
    66. AREF_END : state_n = AREF_IDLE ;
    67. default : state_n = AREF_IDLE ;
    68. endcase
    69. end
    70. assign AREF_IDLEtoAREF_PCHA = (state_c == AREF_IDLE) && ( aref_en ) ;
    71. assign AREF_TRPtoAREF_REF = (state_c == AREF_TRP ) && ( cnt_aref ) ;
    72. assign AREF_TRFtoAREF_REF = (state_c == AREF_TRF ) && ( cnt_aref == 6 && ~cnt_ar ) ;
    73. assign AREF_TRFtoAREF_END = (state_c == AREF_TRF ) && ( cnt_aref == 6 && cnt_ar ) ;
    74. // reg [9:0] cnt_750us ;
    75. always @(posedge sys_clk or negedge sys_rst_n) begin
    76. if(~sys_rst_n)
    77. cnt_750us <= 10'd0 ;
    78. else if(init_end)
    79. begin
    80. if(cnt_750us == MAX_CNT_750US - 1)
    81. cnt_750us <= 10'd0 ;
    82. else
    83. cnt_750us <= cnt_750us + 1'b1 ;
    84. end
    85. else
    86. cnt_750us <= 10'd0 ;
    87. end
    88. // reg [3:0] cnt_aref ;
    89. always @(posedge sys_clk or negedge sys_rst_n) begin
    90. if(~sys_rst_n)
    91. cnt_aref <= 4'd0 ;
    92. else
    93. case (state_c)
    94. AREF_IDLE : cnt_aref <= 4'd0 ;
    95. AREF_PCHA : cnt_aref <= 4'd0 ;
    96. AREF_TRP : if(cnt_aref == T_RP -1)
    97. cnt_aref <= 4'd0 ;
    98. else
    99. cnt_aref <= cnt_aref + 1'b1 ;
    100. AREF_REF : cnt_aref <= 4'd0 ;
    101. AREF_TRF : if(cnt_aref == T_RFC - 1)
    102. cnt_aref <= 4'd0 ;
    103. else
    104. cnt_aref <= cnt_aref + 1'b1 ;
    105. AREF_END : cnt_aref <= 4'd0 ;
    106. default : cnt_aref <= 4'd0 ;
    107. endcase
    108. end
    109. // reg cnt_ar ;
    110. always @(posedge sys_clk or negedge sys_rst_n) begin
    111. if(~sys_rst_n)
    112. cnt_ar <= 1'b0 ;
    113. else if(state_c == AREF_TRF && cnt_aref == T_RFC - 1) // 由于是一位宽的,就不用写归零情况了。
    114. cnt_ar <= cnt_ar + 1'b1 ;
    115. else
    116. cnt_ar <= cnt_ar ;
    117. end
    118. // output signal describe
    119. // reg aref_req ;
    120. always @(posedge sys_clk or negedge sys_rst_n) begin
    121. if(~sys_rst_n)
    122. aref_req <= 1'b0 ;
    123. else if(cnt_750us == MAX_CNT_750US - 1)
    124. aref_req <= 1'b1 ;
    125. else if(state_c == AREF_PCHA)
    126. aref_req <= 1'b0 ;
    127. else
    128. aref_req <= aref_req ;
    129. end
    130. // reg [3:0] aref_cmd ;
    131. always @(posedge sys_clk or negedge sys_rst_n) begin
    132. if(~sys_rst_n)
    133. aref_cmd <= 4'd0 ;
    134. else
    135. case (state_c)
    136. AREF_IDLE : aref_cmd <= AREF_NOP ;
    137. AREF_PCHA : aref_cmd <= AREF_PREC;
    138. AREF_TRP : aref_cmd <= AREF_NOP ;
    139. AREF_REF : aref_cmd <= AREF_REFC;
    140. AREF_TRF : aref_cmd <= AREF_NOP ;
    141. AREF_END : aref_cmd <= AREF_NOP ;
    142. default : aref_cmd <= AREF_NOP ;
    143. endcase
    144. end
    145. // wire [1:0] aref_ba ;
    146. assign aref_ba = 2'b11 ;
    147. // reg [12:0] aref_addr ;
    148. assign aref_addr = 13'h1FFF ;
    149. // wire aref_end ;
    150. assign aref_end = (state_c == AREF_END) ? 1'b1 : 1'b0 ;
    151. endmodule
    仿真:

    在仿真代码中模拟了一小部分仲裁。

    1. `timescale 1ns/1ns
    2. module test_sdram_aref ();
    3. reg sys_clk ; // 50mHz
    4. reg sys_rst_n ;
    5. reg aref_en ; // 自刷新模块的输入,应该是仲裁模块传出。
    6. wire [3:0] init_cmd ; // 初始化模块的输出。
    7. wire [1:0] init_ba ;
    8. wire [12:0] init_addr ;
    9. wire init_end ;
    10. wire aref_req ; // 自刷新模块输出
    11. wire [3:0] aref_cmd ;
    12. wire [1:0] aref_ba ;
    13. wire [12:0] aref_addr ;
    14. wire aref_end ;
    15. wire [3:0] sdram_cmd ;
    16. wire [1:0] sdram_ba ;
    17. wire [12:0] sdram_addr ;
    18. assign sdram_cmd = (init_end) ? aref_cmd : init_cmd ; // 经过仲裁后的命令与地址。
    19. assign sdram_ba = (init_end) ? aref_ba : init_ba ;
    20. assign sdram_addr = (init_end) ? aref_addr : init_addr ;
    21. wire c0_sig ; // pll的输出。
    22. wire c1_sig ;
    23. wire c2_sig ;
    24. wire locked_sig ;
    25. wire rst_n ; // 全局复位。
    26. assign rst_n = sys_rst_n && (locked_sig) ;
    27. sdram_aref sdram_aref_inst(
    28. .sys_clk ( c1_sig ) ,
    29. .sys_rst_n ( rst_n ) ,
    30. .init_end ( init_end ) ,
    31. .aref_en ( aref_en ) ,
    32. .aref_req ( aref_req ) ,
    33. .aref_cmd ( aref_cmd ) ,
    34. .aref_ba ( aref_ba ) ,
    35. .aref_addr ( aref_addr ) ,
    36. .aref_end ( aref_end )
    37. );
    38. clk_gen clk_gen_inst (
    39. .areset (~sys_rst_n ) ,
    40. .inclk0 ( sys_clk ) ,
    41. .c0 ( c0_sig ) , // 50
    42. .c1 ( c1_sig ) , // 100
    43. .c2 ( c2_sig ) , // 100+shift30
    44. .locked ( locked_sig )
    45. );
    46. sdram_model_plus sdram_model_plus_inst(
    47. .Dq ( ) ,
    48. .Addr ( sdram_addr ) ,
    49. .Ba ( sdram_ba ) ,
    50. .Clk ( c2_sig ) ,
    51. .Cke ( 1'b1 ) ,
    52. .Cs_n ( sdram_cmd[3]) ,
    53. .Ras_n ( sdram_cmd[2]) ,
    54. .Cas_n ( sdram_cmd[1]) ,
    55. .We_n ( sdram_cmd[0]) ,
    56. .Dqm ( 2'b00 ) ,
    57. .Debug ( 1'b1 )
    58. );
    59. sdram_init sdram_init_inst(
    60. .sys_clk ( c1_sig ) ,
    61. .sys_rst_n ( rst_n ) ,
    62. .init_cmd ( init_cmd ) ,
    63. .init_ba ( init_ba ) ,
    64. .init_addr ( init_addr) ,
    65. .init_end ( init_end )
    66. );
    67. parameter CYCLE = 20 ; // 10ns
    68. defparam sdram_model_plus_inst.addr_bits = 13 ;
    69. defparam sdram_model_plus_inst.data_bits = 16 ;
    70. defparam sdram_model_plus_inst.col_bits = 9 ;
    71. defparam sdram_model_plus_inst.mem_sizes = 2*1024*1024 ;
    72. // aref_en 仲裁
    73. always @(posedge c1_sig or negedge sys_rst_n) begin
    74. if(~sys_rst_n)
    75. aref_en <= 1'b0 ;
    76. else if(init_end && aref_req)
    77. aref_en <= 1'b1 ;
    78. else if(aref_end)
    79. aref_en <= 1'b0 ;
    80. else
    81. aref_en <= aref_en ;
    82. end
    83. initial begin
    84. sys_clk = 1'b1 ;
    85. sys_rst_n <= 1'b0 ;
    86. #(CYCLE) ;
    87. sys_rst_n <= 1'b1 ;
    88. #(CYCLE * 250_00) ;
    89. end
    90. always #(CYCLE / 2) sys_clk = ~sys_clk ;
    91. endmodule

     sdram_write:

    设计思路:

     指令:激活指令0011,空指令0111,写指令0100,突发停止指令0110(也就是中止页写的指令)。

    由于使用的模式是突发一页的读写模式,给出列首地址后,会自动生成下一个地址。

    1,传送激活指令+bank地址+列地址,激活特定行。0011

    2,等待tRCD,激活时间。此过程中,传送空指令。0111

    3.tRCD时间结束后,传送写指令,同时A8~A0开始传送列地址(首地址),DQ开始传送要写入的数据。

    4,在最后一个数据写入后的下一个时钟周期写入突发中止指令。

    5,突发中止指令写入后,页写突发操作完成。0110

    但是在设计的时候,在页写突发指令完成后加了预充电指令。

    设计状态机时,把突发中止指令放进了写数据状态的最后。

    一个细节:在写指令传送时,DQ已经开始传递第一个数据了。

    sdram_en用作三态门的写数据使能,输出使能。

    第一部分:状态机。

     第二部分:数据写响应设计。wr_ack。

    第三部分:各输出信号的设计与实现。

    时序图:

    代码:
    1. // 模块说明:写数据模块,在初始化完成后,fifo_ctrl模块产生wr_req信号传给仲裁模块,仲裁模块传回写使能信号,开始写数据是时序传输。
    2. // input wire [23:0] write_addr , // 高两位是bank地址,中间13位为数据写入位置的行地址,后9位为列首地址。
    3. // input wire [9:0] write_burst_len , // 写突发长度由fifo_ctrl模块给出。
    4. // output wire wr_sdram_en , // 用作三态输出使能信号。
    5. // wr_ack 传给fifo_ctrl模块,用来做读数据使能,告知fifo_ctrl模块,已经开始读时序了,请求信号可以拉低了。
    6. // wr_burst_len , // 写突发长度,控制WR_DATA状态下传输数据的个数。每一行有512个存储单元。
    7. module sdram_write(
    8. input wire sys_clk ,
    9. input wire sys_rst_n ,
    10. input wire init_end ,
    11. input wire wr_en ,
    12. input wire [23:0] wr_addr ,
    13. input wire [15:0] wr_data ,
    14. input wire [9:0] wr_burst_len , // 写突发长度,控制WR_DATA状态下传输数据的个数。
    15. output reg [3:0] write_cmd ,
    16. output reg [1:0] write_ba ,
    17. output reg [12:0] write_addr ,
    18. output wire wr_end ,
    19. output wire wr_sdram_en ,
    20. output wire [15:0] wr_sdram_data ,
    21. output wire wr_ack
    22. );
    23. // parameter
    24. parameter TRCD = 2 ,
    25. TRP = 2 ,
    26. NOP = 4'b0111 ,
    27. ACTIVE = 4'b0011 ,
    28. WRITE = 4'b0100 ,
    29. B_STOP = 4'b0110 ,
    30. P_CHARGE = 4'b0010 ;
    31. // localparam
    32. localparam WR_IDLE = 3'b000 ,
    33. WR_ACTIVE = 3'b001 ,
    34. WR_TRCD = 3'b011 ,
    35. WR_WRITE = 3'b010 ,
    36. WR_DATA = 3'b110 ,
    37. WR_PRE = 3'b111 ,
    38. WR_TRP = 3'b101 ,
    39. WR_END = 3'b100 ;
    40. // reg signal define
    41. reg [2:0] state_c ;
    42. reg [2:0] state_n ;
    43. reg [9:0] cnt_wr ; // 位宽注意。
    44. reg cnt_wr_rst ; // 用组合逻辑赋值。
    45. // wire dignal define
    46. wire trcd_end ;
    47. wire twrite_end ;
    48. wire trp_end ;
    49. wire WR_IDLEtoWR_ACTIVE ;
    50. wire WR_TRCDtoWR_WRITE ;
    51. wire WR_DATAtoWR_PRE ;
    52. wire WR_TRPtoWR_END ;
    53. /********************************************************************/
    54. // reg [2:0] state_c ;
    55. always @(posedge sys_clk or negedge sys_rst_n) begin
    56. if(~sys_rst_n)
    57. state_c <= WR_IDLE ;
    58. else
    59. state_c <= state_n ;
    60. end
    61. // reg [2:0] state_n ;
    62. always @(*) begin
    63. case(state_c)
    64. WR_IDLE : if(WR_IDLEtoWR_ACTIVE)
    65. state_n = WR_ACTIVE ;
    66. else
    67. state_n = WR_IDLE ;
    68. WR_ACTIVE : state_n = WR_TRCD ;
    69. WR_TRCD : if(WR_TRCDtoWR_WRITE)
    70. state_n = WR_WRITE ;
    71. else
    72. state_n = WR_TRCD ;
    73. WR_WRITE : state_n = WR_DATA ;
    74. WR_DATA : if(WR_DATAtoWR_PRE)
    75. state_n = WR_PRE ;
    76. else
    77. state_n = WR_DATA ;
    78. WR_PRE : state_n = WR_TRP ;
    79. WR_TRP : if(WR_TRPtoWR_END)
    80. state_n = WR_END ;
    81. else
    82. state_n = WR_TRP ;
    83. WR_END : state_n = WR_IDLE ;
    84. default : state_n = WR_IDLE ;
    85. endcase
    86. end
    87. assign WR_IDLEtoWR_ACTIVE = (state_c == WR_IDLE) && (wr_en ) && (init_end);
    88. assign WR_TRCDtoWR_WRITE = (state_c == WR_TRCD) && (trcd_end ) && (init_end);
    89. assign WR_DATAtoWR_PRE = (state_c == WR_DATA) && (twrite_end) && (init_end);
    90. assign WR_TRPtoWR_END = (state_c == WR_TRP ) && (trp_end ) && (init_end);
    91. // reg [9:0] cnt_wr ;
    92. always @(posedge sys_clk or negedge sys_rst_n) begin
    93. if(~sys_rst_n)
    94. cnt_wr <= 10'd0 ;
    95. else if(cnt_wr_rst)
    96. cnt_wr <= 10'd0 ;
    97. else
    98. cnt_wr <= cnt_wr + 1'b1 ;
    99. end
    100. // reg cnt_wr_rst ;
    101. always @(*) begin
    102. case(state_c)
    103. WR_IDLE : cnt_wr_rst = 1'b1 ;
    104. WR_ACTIVE : cnt_wr_rst = trcd_end ;
    105. WR_TRCD : cnt_wr_rst = trcd_end ;
    106. WR_WRITE : cnt_wr_rst = 1'b1 ;
    107. WR_DATA : cnt_wr_rst = twrite_end ;
    108. WR_PRE : cnt_wr_rst = trp_end ;
    109. WR_TRP : cnt_wr_rst = trp_end ;
    110. WR_END : cnt_wr_rst = 1'b1 ;
    111. default : cnt_wr_rst = 1'b1 ;
    112. endcase
    113. end
    114. // wire trcd_end ;
    115. assign trcd_end = (state_c == WR_TRCD && cnt_wr == TRCD) ? 1'b1 : 1'b0 ;
    116. // wire twrite_end ;
    117. assign twrite_end = (state_c == WR_DATA && cnt_wr == (wr_burst_len - 1)) ? 1'b1 : 1'b0 ;
    118. // wire trp_end ;
    119. assign trp_end = (state_c == WR_TRP && cnt_wr == TRP) ? 1'b1 : 1'b0 ;
    120. // output signal describe
    121. // wire wr_end ,
    122. assign wr_end = (state_c == WR_END) ? 1'b1 : 1'b0 ;
    123. // reg [3:0] write_cmd ,
    124. // reg [1:0] write_ba ,
    125. // reg [12:0] write_addr ,
    126. always @(posedge sys_clk or negedge sys_rst_n) begin
    127. if(~sys_rst_n) begin
    128. write_cmd <= NOP ;
    129. write_ba <= 2'b11 ;
    130. write_addr <= 13'h1FFF ;
    131. end else begin
    132. case (state_c)
    133. WR_IDLE :
    134. begin
    135. write_cmd <= NOP ;
    136. write_ba <= 2'b11 ;
    137. write_addr <= 13'h1FFF ;
    138. end
    139. WR_ACTIVE:
    140. begin
    141. write_cmd <= ACTIVE ;
    142. write_ba <= wr_addr[23:22] ;
    143. write_addr <= wr_addr[21:9 ] ; //wr_addr[23:0]
    144. end
    145. WR_TRCD :
    146. begin
    147. write_cmd <= NOP ;
    148. write_ba <= 2'b11 ;
    149. write_addr <= 13'h1FFF ;
    150. end
    151. WR_WRITE :
    152. begin
    153. write_cmd <= WRITE ;
    154. write_ba <= wr_addr[23:22] ;
    155. write_addr <= {4'b0000,wr_addr[ 8:0 ]} ;
    156. end
    157. WR_DATA :
    158. if(!twrite_end)
    159. begin
    160. write_cmd <= NOP ;
    161. write_ba <= 2'b11 ;
    162. write_addr <= 13'h1FFF ;
    163. end
    164. else
    165. begin
    166. write_cmd <= B_STOP ;
    167. write_ba <= 2'b11 ;
    168. write_addr <= 13'h1FFF ;
    169. end
    170. WR_PRE :
    171. begin
    172. write_cmd <= P_CHARGE ; // 预充电指令,一开始忘记赋值了。
    173. write_ba <= wr_addr[23:22] ;
    174. write_addr <= 13'h0400 ;
    175. end
    176. WR_TRP :
    177. begin
    178. write_cmd <= NOP ;
    179. write_ba <= 2'b11 ;
    180. write_addr <= 13'h1FFF ;
    181. end
    182. WR_END :
    183. begin
    184. write_cmd <= NOP ;
    185. write_ba <= 2'b11 ;
    186. write_addr <= 13'h1FFF ;
    187. end
    188. default :
    189. begin
    190. write_cmd <= NOP ;
    191. write_ba <= 2'b11 ;
    192. write_addr <= 13'h1FFF ;
    193. end
    194. endcase
    195. end
    196. end
    197. // wire wr_sdram_en ,
    198. assign wr_sdram_en = (state_c == WR_DATA) ? 1'b1 : 1'b0 ;
    199. // reg [15:0] wr_sdram_data ,
    200. assign wr_sdram_data = (wr_sdram_en) ? wr_data : 16'd0 ;
    201. // wire wr_ack
    202. assign wr_ack = (((state_c == WR_WRITE) || (state_c == WR_DATA)) && (cnt_wr <= wr_burst_len - 2)) ? 1'b1 : 1'b0 ;
    203. endmodule
    1. `timescale 1ns/1ns
    2. module test_sdram_write ();
    3. reg sys_clk ; // 50mHz
    4. reg sys_rst_n ;
    5. wire [3:0] init_cmd ;
    6. wire [1:0] init_ba ;
    7. wire [12:0] init_addr ;
    8. wire init_end ;
    9. wire [15:0] sdram_data ;
    10. wire [3:0] sdram_cmd ;
    11. wire [1:0] sdram_ba ;
    12. wire [12:0] sdram_addr ;
    13. wire c0_sig ;
    14. wire c1_sig ;
    15. wire c2_sig ;
    16. wire locked_sig ;
    17. wire rst_n ;
    18. assign rst_n = sys_rst_n && (locked_sig) ;
    19. reg wr_en ;
    20. reg [15:0] wr_data ;
    21. wire [3:0] write_cmd ;
    22. wire [1:0] write_ba ;
    23. wire [12:0] write_addr ;
    24. wire wr_end ;
    25. wire wr_sdram_en ;
    26. wire [15:0] wr_sdram_data ;
    27. wire wr_ack ;
    28. reg wr_en_flag ;
    29. always @(posedge c1_sig or negedge sys_rst_n) begin
    30. if(~sys_rst_n)
    31. wr_en_flag <= 1'b0 ;
    32. else if(wr_end)
    33. wr_en_flag <= ~wr_en_flag ;
    34. end
    35. // always @(posedge c1_sig or negedge sys_rst_n) begin
    36. // if(~sys_rst_n)
    37. // wr_en <= 1'b0 ;
    38. // else if(wr_end)
    39. // wr_en <= 1'b0 ;
    40. // else if(init_end && !wr_en_flag)
    41. // wr_en <= 1'b1 ;
    42. // else
    43. // wr_en <= wr_en ;
    44. // end
    45. always @(posedge c1_sig or negedge sys_rst_n) begin
    46. if(~sys_rst_n)
    47. wr_en <= 1'b0 ;
    48. else if(wr_end)
    49. wr_en <= 1'b0 ;
    50. else if(init_end)
    51. wr_en <= 1'b1 ;
    52. else
    53. wr_en <= wr_en ;
    54. end
    55. always @(posedge c1_sig or negedge sys_rst_n) begin
    56. if(~sys_rst_n)
    57. wr_data <= 16'd0 ;
    58. else if(wr_ack == 0)
    59. wr_data <= 16'd0 ;
    60. else
    61. wr_data <= wr_data + 1'b1 ;
    62. end
    63. assign sdram_cmd = (init_end) ? write_cmd : init_cmd ;
    64. assign sdram_ba = (init_end) ? write_ba : init_ba ;
    65. assign sdram_addr = (init_end) ? write_addr : init_addr ;
    66. assign sdram_data = (wr_sdram_en) ? wr_data : 16'hzzzz ;
    67. sdram_write sdram_write_inst(
    68. .sys_clk ( c1_sig ) ,
    69. .sys_rst_n ( rst_n ) ,
    70. .init_end ( init_end ) ,
    71. .wr_en ( wr_en ) ,
    72. .wr_addr ( 24'd0 ) ,
    73. .wr_data ( wr_data ) ,
    74. .wr_burst_len ( 10 ) , // 写突发长度,控制WR_DATA状态下传输数据的个数。
    75. .write_cmd ( write_cmd ) ,
    76. .write_ba ( write_ba ) ,
    77. .write_addr ( write_addr ) ,
    78. .wr_end ( wr_end ) ,
    79. .wr_sdram_en ( wr_sdram_en ) ,
    80. .wr_sdram_data ( wr_sdram_data ) ,
    81. .wr_ack ( wr_ack )
    82. );
    83. clk_gen clk_gen_inst (
    84. .areset (~sys_rst_n ) ,
    85. .inclk0 ( sys_clk ) ,
    86. .c0 ( c0_sig ) , // 50
    87. .c1 ( c1_sig ) , // 100
    88. .c2 ( c2_sig ) , // 100+shift30
    89. .locked ( locked_sig )
    90. );
    91. sdram_model_plus sdram_model_plus_inst(
    92. .Dq ( sdram_data ) ,
    93. .Addr ( sdram_addr ) ,
    94. .Ba ( sdram_ba ) ,
    95. .Clk ( c2_sig ) ,
    96. .Cke ( 1'b1 ) ,
    97. .Cs_n ( sdram_cmd[3]) ,
    98. .Ras_n ( sdram_cmd[2]) ,
    99. .Cas_n ( sdram_cmd[1]) ,
    100. .We_n ( sdram_cmd[0]) ,
    101. .Dqm ( 2'b00 ) ,
    102. .Debug ( 1'b1 )
    103. );
    104. sdram_init sdram_init_inst(
    105. .sys_clk ( c1_sig ) ,
    106. .sys_rst_n ( rst_n ) ,
    107. .init_cmd ( init_cmd ) ,
    108. .init_ba ( init_ba ) ,
    109. .init_addr ( init_addr) ,
    110. .init_end ( init_end )
    111. );
    112. parameter CYCLE = 20 ; // 10ns
    113. defparam sdram_model_plus_inst.addr_bits = 13 ;
    114. defparam sdram_model_plus_inst.data_bits = 16 ;
    115. defparam sdram_model_plus_inst.col_bits = 9 ;
    116. defparam sdram_model_plus_inst.mem_sizes = 2*1024*1024 ;
    117. initial begin
    118. sys_clk = 1'b1 ;
    119. sys_rst_n <= 1'b0 ;
    120. #(CYCLE) ;
    121. sys_rst_n <= 1'b1 ;
    122. #(CYCLE * 250_00) ;
    123. $stop ;
    124. end
    125. always #(CYCLE / 2) sys_clk = ~sys_clk ;
    126. endmodule
    仿真:

    sdram_read:

    设计思路:

     1,传送激活指令(0011),同时传递bank地址与行地址,激活特定行。

    2,然后进入激活等待状态,等待时间tRCD,此过程中传送空指令。

    3, 然后传动读指令,同时A8~A0写入列地址。

    4,然后跳转到潜伏状态,3个clk,结束后,开始读数据。

    5,进入读数据状态。设读取的数据为N。

    6,从读指令周期开始计数,N个周期后,写入突发中止指令。

    7,突发中止指令写入后,DQ继续传送2个周期数据。数据传输完成后,sdram页突发读操作完成。

    8,然后要发预充电命令,进入预充电等待状态,结束后进入读结束状态。

     第一部分状态机;

    第二部分读突发中止指令应该何时写入?

     assign rd_bust_flag = (state_c == RD_DATA && cnt_clk == rd_bust_len - CL - 1).

    提前CL个时钟周期传送中止指令,又因为从零开始计数。

    第三部分输出信号。

    注意,写计数器时,先写归零条件,把它放在最高优先级。

    本模块偏移时钟向前移动和向后移动会造成很大的不同。

    由于我一开始设置的向后移动30,导致潜伏期状态,读数据状态,ack响应信号,与官方教程里的代码很不一样。

    由于时序图是仿照官方画的,和代码有很多不相符合的地方,但是对于代码而言只需改动两个地方。

    tcl_end与rd_bust_flag!!!!!!!!!!!

    时序图:

    代码:
    1. // 读时序产生模块。先传送激活指令,然后传送读指令,然后读突发中止指令,然后预充电指令。
    2. // 注意rd_data的跨时钟域处理。
    3. module sdram_read(
    4. input wire sys_clk ,
    5. input wire sys_rst_n ,
    6. input wire init_end ,
    7. input wire [23:0] rd_addr ,
    8. input wire [15:0] rd_data ,
    9. input wire [9:0] rd_burst_len ,
    10. input wire rd_en ,
    11. output wire rd_end ,
    12. output reg [3:0] read_cmd ,
    13. output reg [1:0] read_ba ,
    14. output reg [12:0] read_addr ,
    15. output wire [15:0] rd_sdram_data ,
    16. output wire rd_ack
    17. );
    18. // parameter
    19. parameter NOP = 4'b0111 , // 空指令
    20. P_CHARGE = 4'b0010 , // 预充电指令
    21. ACTIVE = 4'b0011 , // 激活指令
    22. READ = 4'b0101 , // 读指令
    23. B_STOP = 4'b0110 ; // 读中止指令
    24. parameter T_RCD = 2 , // 激活周等待期
    25. T_CL = 3 , // 列潜伏
    26. T_RP = 2 ; // 预充电
    27. localparam RD_IDLE = 9'b0_0000_0001 , // 空闲状态
    28. RD_ACTIVE = 9'b0_0000_0010 , // 激活状态
    29. RD_TRCD = 9'b0_0000_0100 , // 激活等待状态
    30. RD_READ = 9'b0_0000_1000 , // 传送读指令状态
    31. RD_CL = 9'b0_0001_0000 , // 潜伏状态
    32. RD_DATA = 9'b0_0010_0000 , // 读数据状态
    33. RD_PRE = 9'b0_0100_0000 , // 预充电指令传送状态
    34. RD_TRP = 9'b0_1000_0000 , // 预充电等待状态
    35. RD_END = 9'b1_0000_0000 ; // 读结束
    36. // reg signal define
    37. // reg [15:0] rd_data_reg ;
    38. reg [9:0] state_c ;
    39. reg [9:0] state_n ; // 用的组合逻辑
    40. reg [9:0] cnt_read ;
    41. reg cnt_rd_rst ; // 用的组合逻辑
    42. // wire signal define
    43. wire trcd_end ;
    44. wire tcl_end ;
    45. wire tread_end ;
    46. wire trp_end ;
    47. wire rd_bust_flag;
    48. wire RD_IDLEtoRD_ACTIVE ;
    49. wire RD_TRCDtoRD_READ ;
    50. wire RD_CLtoRD_DATA ;
    51. wire RD_DATAto_RD_PRE ;
    52. wire RD_TRPtoRD_END ;
    53. /****************************************************************************/
    54. // // reg [15:0] rd_data_reg ;
    55. // always @(posedge sys_clk or negedge sys_rst_n) begin
    56. // if(~sys_rst_n)
    57. // rd_data_reg <= 16'd0 ;
    58. // else
    59. // rd_data_reg <= rd_data ;
    60. // end
    61. // reg [9:0] state_c ;
    62. always @(posedge sys_clk or negedge sys_rst_n) begin
    63. if(~sys_rst_n)
    64. state_c <= RD_IDLE ;
    65. else
    66. state_c <= state_n ;
    67. end
    68. // reg [9:0] state_n ;
    69. always @(*) begin
    70. case (state_c)
    71. RD_IDLE : if(RD_IDLEtoRD_ACTIVE)
    72. state_n = RD_ACTIVE ;
    73. else
    74. state_n = RD_IDLE ;
    75. RD_ACTIVE : state_n = RD_TRCD ;
    76. RD_TRCD : if(RD_TRCDtoRD_READ) // 可以写成三元运算符:state_n <= (RD_TRCDtoRD_READ) ? RD_READ : RD_TRCD ;
    77. state_n = RD_READ ;
    78. else
    79. state_n = RD_TRCD ;
    80. RD_READ : state_n = RD_CL ;
    81. RD_CL : if(RD_CLtoRD_DATA)
    82. state_n = RD_DATA ;
    83. else
    84. state_n = RD_CL ;
    85. RD_DATA : if(RD_DATAto_RD_PRE)
    86. state_n = RD_PRE ;
    87. else
    88. state_n = RD_DATA ;
    89. RD_PRE : state_n = RD_TRP ;
    90. RD_TRP : if(RD_TRPtoRD_END)
    91. state_n = RD_END ;
    92. else
    93. state_n = RD_TRP ;
    94. RD_END : state_n = RD_IDLE ;
    95. default : state_n = RD_IDLE ;
    96. endcase
    97. end
    98. assign RD_IDLEtoRD_ACTIVE = ( state_c == RD_IDLE ) && ( rd_en ) && ( init_end ) ;
    99. assign RD_TRCDtoRD_READ = ( state_c == RD_TRCD ) && ( trcd_end ) && ( init_end ) ;
    100. assign RD_CLtoRD_DATA = ( state_c == RD_CL ) && ( tcl_end ) && ( init_end ) ;
    101. assign RD_DATAto_RD_PRE = ( state_c == RD_DATA ) && ( tread_end) && ( init_end ) ;
    102. assign RD_TRPtoRD_END = ( state_c == RD_TRP ) && ( trp_end ) && ( init_end ) ;
    103. // reg [9:0] cnt_read ;
    104. always @(posedge sys_clk or negedge sys_rst_n) begin
    105. if(~sys_rst_n)
    106. cnt_read <= 10'd0 ;
    107. else if(cnt_rd_rst)
    108. cnt_read <= 10'd0 ;
    109. else
    110. cnt_read <= cnt_read + 1'b1 ;
    111. end
    112. // wire cnt_rd_rst ;
    113. always @(*) begin
    114. case(state_c)
    115. RD_IDLE : cnt_rd_rst = 1'b1 ;
    116. RD_ACTIVE : cnt_rd_rst = trcd_end ;
    117. RD_TRCD : cnt_rd_rst = trcd_end ;
    118. RD_READ : cnt_rd_rst = tcl_end ;
    119. RD_CL : cnt_rd_rst = tcl_end ;
    120. RD_DATA : cnt_rd_rst = tread_end ;
    121. RD_PRE : cnt_rd_rst = trp_end ;
    122. RD_TRP : cnt_rd_rst = trp_end ;
    123. RD_END : cnt_rd_rst = 1'b1 ;
    124. default : cnt_rd_rst = 1'b1 ;
    125. endcase
    126. end
    127. // wire trcd_end ;T_RP
    128. assign trcd_end = (state_c == RD_TRCD && cnt_read == T_RCD) ? 1'b1 : 1'b0 ;
    129. // wire tcl_end ;
    130. assign tcl_end = (state_c == RD_CL && cnt_read == T_CL - 1) ? 1'b1 : 1'b0 ; // 注意这里时序图多画了一个时钟周期。要计数到2,而不是3。
    131. // wire tread_end ;
    132. assign tread_end= (state_c == RD_DATA && cnt_read == rd_burst_len) ? 1'b1 : 1'b0 ;
    133. // wire trp_end ;
    134. assign trp_end = (state_c == RD_TRP && cnt_read == T_RP) ? 1'b1 : 1'b0 ;
    135. // wire rd_bust_flag;
    136. assign rd_bust_flag = (state_c == RD_DATA && cnt_read == (rd_burst_len - T_CL)) ? 1'b1 : 1'b0 ;
    137. // // output
    138. // wire rd_end ;
    139. assign rd_end = (state_c == RD_END) ? 1'b1 : 1'b0 ;
    140. // reg [3:0] read_cmd ;
    141. // reg [1:0] read_ba ;
    142. // reg [12:0] read_addr ;
    143. always @(posedge sys_clk or negedge sys_rst_n) begin
    144. if(~sys_rst_n)
    145. begin
    146. read_cmd <= NOP ;
    147. read_ba <= 2'b11 ;
    148. read_addr <= 13'h1FFF ;
    149. end
    150. else
    151. case (state_c)
    152. RD_IDLE :
    153. begin
    154. read_cmd <= NOP ;
    155. read_ba <= 2'b11 ;
    156. read_addr <= 13'h1FFF ;
    157. end
    158. RD_ACTIVE :
    159. begin
    160. read_cmd <= ACTIVE ;
    161. read_ba <= rd_addr[23:22] ;
    162. read_addr <= rd_addr[21:9] ;
    163. end
    164. RD_TRCD :
    165. begin
    166. read_cmd <= NOP ;
    167. read_ba <= 2'b11 ;
    168. read_addr <= 13'h1FFF ;
    169. end
    170. RD_READ :
    171. begin
    172. read_cmd <= READ ;
    173. read_ba <= rd_addr[23:22] ;
    174. read_addr <= rd_addr[8:0] ;
    175. end
    176. RD_CL :
    177. begin
    178. read_cmd <= NOP ;
    179. read_ba <= 2'b11 ;
    180. read_addr <= 13'h1FFF ;
    181. end
    182. RD_DATA :
    183. if(!rd_bust_flag)
    184. begin
    185. read_cmd <= NOP ;
    186. read_ba <= 2'b11 ;
    187. read_addr <= 13'h1FFF ;
    188. end
    189. else
    190. begin
    191. read_cmd <= B_STOP ;
    192. read_ba <= 2'b11 ;
    193. read_addr <= 13'h1FFF ;
    194. end
    195. RD_PRE :
    196. begin
    197. read_cmd <= P_CHARGE ;
    198. read_ba <= rd_addr[23:22] ;
    199. read_addr <= 13'h0400 ; // 辅助预充电,选中所有bank
    200. end
    201. RD_TRP :
    202. begin
    203. read_cmd <= NOP ;
    204. read_ba <= 2'b11 ;
    205. read_addr <= 13'h1FFF ;
    206. end
    207. RD_END :
    208. begin
    209. read_cmd <= NOP ;
    210. read_ba <= 2'b11 ;
    211. read_addr <= 13'h1FFF ;
    212. end
    213. default :
    214. begin
    215. read_cmd <= NOP ;
    216. read_ba <= 2'b11 ;
    217. read_addr <= 13'h1FFF ;
    218. end
    219. endcase
    220. end
    221. // wire [15:0] rd_sdram_data;
    222. assign rd_sdram_data = (rd_ack) ? rd_data : 16'd0 ; // rd_data_reg
    223. // wire rd_ack ;
    224. assign rd_ack = (state_c == RD_DATA && (cnt_read >= 1 && cnt_read <= rd_burst_len)) ? 1'b1 : 1'b0 ;
    225. endmodule
    1. `timescale 1ns/1ns
    2. module test_sdram_read ();
    3. //
    4. reg rd_en ;
    5. wire rd_end ;
    6. wire [3:0] read_cmd ;
    7. wire [1:0] read_ba ;
    8. wire [12:0] read_addr ;
    9. wire [15:0] rd_sdram_data ;
    10. wire rd_ack ;
    11. //
    12. reg sys_clk ; // 50mHz
    13. reg sys_rst_n ;
    14. wire [3:0] init_cmd ;
    15. wire [1:0] init_ba ;
    16. wire [12:0] init_addr ;
    17. wire init_end ;
    18. wire [15:0] sdram_data ;
    19. wire [3:0] sdram_cmd ;
    20. wire [1:0] sdram_ba ;
    21. wire [12:0] sdram_addr ;
    22. wire c0_sig ;
    23. wire c1_sig ;
    24. wire c2_sig ;
    25. wire locked_sig ;
    26. wire rst_n ;
    27. assign rst_n = sys_rst_n && (locked_sig) ;
    28. reg wr_en ;
    29. reg [15:0] wr_data ;
    30. wire [3:0] write_cmd ;
    31. wire [1:0] write_ba ;
    32. wire [12:0] write_addr ;
    33. wire wr_end ;
    34. wire wr_sdram_en ;
    35. wire [15:0] wr_sdram_data ;
    36. wire wr_ack ;
    37. reg wr_en_flag ;
    38. always @(posedge c1_sig or negedge sys_rst_n) begin
    39. if(~sys_rst_n)
    40. wr_en_flag <= 1'b0 ;
    41. else if(wr_end)
    42. wr_en_flag <= ~wr_en_flag ;
    43. end
    44. always @(posedge c1_sig or negedge sys_rst_n) begin
    45. if(~sys_rst_n)
    46. wr_en <= 1'b0 ;
    47. else if(wr_end)
    48. wr_en <= 1'b0 ;
    49. else if(init_end && !wr_en_flag)
    50. wr_en <= 1'b1 ;
    51. else
    52. wr_en <= wr_en ;
    53. end
    54. // always @(posedge c1_sig or negedge sys_rst_n) begin
    55. // if(~sys_rst_n)
    56. // wr_en <= 1'b0 ;
    57. // else if(wr_end)
    58. // wr_en <= 1'b0 ;
    59. // else if(init_end)
    60. // wr_en <= 1'b1 ;
    61. // else
    62. // wr_en <= wr_en ;
    63. // end
    64. reg rd_en_flag ;
    65. always @(posedge c1_sig or negedge sys_rst_n) begin
    66. if(~sys_rst_n)
    67. rd_en_flag <= 1'b0 ;
    68. else if(rd_end)
    69. rd_en_flag <= ~rd_en_flag ;
    70. end
    71. always @(posedge c1_sig or negedge sys_rst_n) begin
    72. if(~sys_rst_n)
    73. rd_en <= 1'b0 ;
    74. else if(rd_end || rd_en_flag)
    75. rd_en <= 1'b0 ;
    76. else if(init_end == 1 && wr_en == 0 && wr_en_flag == 1 && ~rd_en_flag)
    77. rd_en <= 1'b1 ;
    78. else
    79. rd_en <= rd_en ;
    80. end
    81. always @(posedge c1_sig or negedge sys_rst_n) begin
    82. if(~sys_rst_n)
    83. wr_data <= 16'd0 ;
    84. else if(wr_ack == 0)
    85. wr_data <= 16'd0 ;
    86. else
    87. wr_data <= wr_data + 1'b1 ;
    88. end
    89. assign sdram_cmd = (init_end) ? (( wr_en ) ? write_cmd : read_cmd ) : init_cmd ;
    90. assign sdram_ba = (init_end) ? (( wr_en ) ? write_ba : read_ba ) : init_ba ;
    91. assign sdram_addr = (init_end) ? (( wr_en ) ? write_addr : read_addr) : init_addr ;
    92. assign sdram_data = (wr_sdram_en) ? wr_data : 16'hzzzz ;
    93. sdram_read sdram_read_inst(
    94. .sys_clk ( c1_sig ) ,
    95. .sys_rst_n ( rst_n ) ,
    96. .init_end ( init_end ) ,
    97. .rd_addr ( 24'd0 ) ,
    98. .rd_data ( sdram_data ) ,
    99. .rd_burst_len ( 10'd20 ) ,
    100. .rd_en ( rd_en ) ,
    101. .rd_end ( rd_end ) ,
    102. .read_cmd ( read_cmd ) ,
    103. .read_ba ( read_ba ) ,
    104. .read_addr ( read_addr ) ,
    105. .rd_sdram_data ( rd_sdram_data) ,
    106. .rd_ack ( rd_ack )
    107. );
    108. sdram_write sdram_write_inst(
    109. .sys_clk ( c1_sig ) ,
    110. .sys_rst_n ( rst_n ) ,
    111. .init_end ( init_end ) ,
    112. .wr_en ( wr_en ) ,
    113. .wr_addr ( 24'd0 ) ,
    114. .wr_data ( wr_data ) ,
    115. .wr_burst_len ( 10 ) , // 写突发长度,控制WR_DATA状态下传输数据的个数。
    116. .write_cmd ( write_cmd ) ,
    117. .write_ba ( write_ba ) ,
    118. .write_addr ( write_addr ) ,
    119. .wr_end ( wr_end ) ,
    120. .wr_sdram_en ( wr_sdram_en ) ,
    121. .wr_sdram_data ( wr_sdram_data ) ,
    122. .wr_ack ( wr_ack )
    123. );
    124. clk_gen clk_gen_inst (
    125. .areset (~sys_rst_n ) ,
    126. .inclk0 ( sys_clk ) ,
    127. .c0 ( c0_sig ) , // 50
    128. .c1 ( c1_sig ) , // 100
    129. .c2 ( c2_sig ) , // 100+shift30
    130. .locked ( locked_sig )
    131. );
    132. sdram_model_plus sdram_model_plus_inst(
    133. .Dq ( sdram_data ) ,
    134. .Addr ( sdram_addr ) ,
    135. .Ba ( sdram_ba ) ,
    136. .Clk ( c2_sig ) ,
    137. .Cke ( 1'b1 ) ,
    138. .Cs_n ( sdram_cmd[3]) ,
    139. .Ras_n ( sdram_cmd[2]) ,
    140. .Cas_n ( sdram_cmd[1]) ,
    141. .We_n ( sdram_cmd[0]) ,
    142. .Dqm ( 2'b00 ) ,
    143. .Debug ( 1'b1 )
    144. );
    145. sdram_init sdram_init_inst(
    146. .sys_clk ( c1_sig ) ,
    147. .sys_rst_n ( rst_n ) ,
    148. .init_cmd ( init_cmd ) ,
    149. .init_ba ( init_ba ) ,
    150. .init_addr ( init_addr) ,
    151. .init_end ( init_end )
    152. );
    153. parameter CYCLE = 20 ; // 10ns
    154. defparam sdram_model_plus_inst.addr_bits = 13 ;
    155. defparam sdram_model_plus_inst.data_bits = 16 ;
    156. defparam sdram_model_plus_inst.col_bits = 9 ;
    157. defparam sdram_model_plus_inst.mem_sizes = 2*1024*1024 ;
    158. initial begin
    159. sys_clk = 1'b1 ;
    160. sys_rst_n <= 1'b0 ;
    161. #(CYCLE) ;
    162. sys_rst_n <= 1'b1 ;
    163. #(CYCLE * 250_00) ;
    164. $stop ;
    165. end
    166. always #(CYCLE / 2) sys_clk = ~sys_clk ;
    167. endmodule
    仿真:

     sdram_arbit:

    设计思路:

    仲裁模块通过状态机协调各个模块的正常进行,每项操作的实现都需要对sdram写入对应操作指令,且各项操作指令不同,为了方便赋值与准确传输指令,内部声明sdram_cmd信号,用来保存不同状态下对应的指令。

    如状态机所示:

    we_n:写使能有效信号,低电平有效,使能写操作和预充电。

     

    时序图:

    看着状态机与之前画的时序图就能写出来代码。

    代码:
    1. module sdram_arbit(
    2. input wire sys_clk ,
    3. input wire sys_rst_n ,
    4. input wire [3:0] init_cmd ,
    5. input wire [1:0] init_ba ,
    6. input wire [12:0] init_addr ,
    7. input wire init_end ,
    8. input wire aref_req ,
    9. input wire [3:0] aref_cmd ,
    10. input wire [1:0] aref_ba ,
    11. input wire [12:0] aref_addr ,
    12. input wire aref_end ,
    13. input wire read_req ,
    14. input wire [3:0] read_cmd ,
    15. input wire [1:0] read_ba ,
    16. input wire [12:0] read_addr ,
    17. input wire read_end ,
    18. input wire write_req ,
    19. input wire [3:0] write_cmd ,
    20. input wire [1:0] write_ba ,
    21. input wire [12:0] write_addr,
    22. input wire wr_end ,
    23. input wire wr_sdram_en ,
    24. input wire [15:0] wr_sdram_data ,
    25. output wire sdram_cke , // 时钟使能
    26. output wire sdram_csn ,
    27. output wire sdram_ras ,
    28. output wire sdram_cas ,
    29. output wire sdram_wen , // 写使能。
    30. output reg [1:0] sdram_bank,
    31. output reg [12:0] sdram_addr,
    32. inout wire [15:0] sdram_dq ,
    33. output wire aref_en ,
    34. output wire write_en ,
    35. output wire read_en
    36. );
    37. // localparam
    38. localparam NOP = 4'b0111 ;
    39. localparam INIT = 5'b0_0001 ,
    40. ARBIT = 5'b0_0010 , // 仲裁状态
    41. WRITE = 5'b0_0100 ,
    42. READ = 5'b0_1000 ,
    43. AREF = 5'b1_0000 ;
    44. // reg signal define
    45. reg [4:0] state_c ;
    46. reg [4:0] state_n ;
    47. reg [3:0] sdram_cmd ; // 组合逻辑
    48. // wire signal define
    49. wire INITtoARBIT ;
    50. wire ARBITtoAREF ;
    51. wire ARBITtoWRITE;
    52. wire ARBITtoREAD ;
    53. wire WRITEtoARBIT;
    54. wire READtoARBIT ;
    55. wire AREFtoARBIT ;
    56. /****************************************************************/
    57. // reg [4:0] state_c ;
    58. always @(posedge sys_clk or negedge sys_rst_n) begin
    59. if(~sys_rst_n)
    60. state_c <= INIT ;
    61. else
    62. state_c <= state_n ;
    63. end
    64. // reg [4:0] state_n ;
    65. always @(*) begin
    66. case(state_c)
    67. INIT :
    68. if(INITtoARBIT)
    69. state_n = ARBIT ;
    70. else
    71. state_n = INIT ;
    72. ARBIT :
    73. if(ARBITtoAREF)
    74. state_n = AREF ;
    75. else if(ARBITtoWRITE)
    76. state_n = WRITE ;
    77. else if(ARBITtoREAD)
    78. state_n = READ ;
    79. else
    80. state_n = ARBIT ;
    81. WRITE :
    82. if(WRITEtoARBIT)
    83. state_n = ARBIT ;
    84. else
    85. state_n = WRITE ;
    86. READ :
    87. if(READtoARBIT)
    88. state_n = ARBIT ;
    89. else
    90. state_n = READ ;
    91. AREF : if(AREFtoARBIT)
    92. state_n = ARBIT ;
    93. else
    94. state_n = AREF ;
    95. default: state_n = ARBIT ;
    96. endcase
    97. end
    98. assign INITtoARBIT = ( state_c == INIT ) && ( init_end ) ;
    99. assign ARBITtoAREF = ( state_c == ARBIT ) && ( aref_req ) ;
    100. assign ARBITtoWRITE = ( state_c == ARBIT ) && ( write_req ) ;
    101. assign ARBITtoREAD = ( state_c == ARBIT ) && ( read_req ) ;
    102. assign WRITEtoARBIT = ( state_c == WRITE ) && ( wr_end ) ;
    103. assign READtoARBIT = ( state_c == READ ) && ( read_end ) ;
    104. assign AREFtoARBIT = ( state_c == AREF ) && ( aref_end ) ;
    105. // output
    106. // wire sdram_cke ,
    107. assign sdram_cke = 1'b1 ;
    108. // wire sdram_csn ,
    109. // wire sdram_ras ,
    110. // wire sdram_cas ,
    111. // wire sdram_wen ,
    112. assign sdram_csn = sdram_cmd[3] ;
    113. assign sdram_ras = sdram_cmd[2] ;
    114. assign sdram_cas = sdram_cmd[1] ;
    115. assign sdram_wen = sdram_cmd[0] ;
    116. // assign {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = sdram_cmd;
    117. // reg [3:0] sdram_cmd ;
    118. // reg [1:0] sdram_bank,
    119. // reg [12:0] sdram_addr,
    120. always @(*) begin
    121. case (state_c)
    122. INIT :
    123. begin
    124. sdram_cmd = init_cmd ;
    125. sdram_bank = init_ba ;
    126. sdram_addr = init_addr ;
    127. end
    128. ARBIT :
    129. begin
    130. sdram_cmd = NOP ;
    131. sdram_bank = 2'b11 ;
    132. sdram_addr = 13'h1FFF ;
    133. end
    134. WRITE :
    135. begin
    136. sdram_cmd = write_cmd ;
    137. sdram_bank = write_ba ;
    138. sdram_addr = write_addr ;
    139. end
    140. READ :
    141. begin
    142. sdram_cmd = read_cmd ;
    143. sdram_bank = read_ba ;
    144. sdram_addr = read_addr ;
    145. end
    146. AREF :
    147. begin
    148. sdram_cmd = aref_cmd ;
    149. sdram_bank = aref_ba ;
    150. sdram_addr = aref_addr ;
    151. end
    152. default:
    153. begin
    154. sdram_cmd = NOP ;
    155. sdram_bank = 2'b11 ;
    156. sdram_addr = 13'h1FFF ;
    157. end
    158. endcase
    159. end
    160. // wire [15:0] sdram_dq ,
    161. assign sdram_dq = (wr_sdram_en) ? wr_sdram_data : 16'hzzzz ;
    162. // wire aref_en ,
    163. assign aref_en = (state_c == AREF) ? 1'b1 : 1'b0 ; // 灵活运用三段式状态机。
    164. // wire write_en ,
    165. assign write_en = (state_c == WRITE) ? 1'b1 : 1'b0 ;
    166. // wire read_en
    167. assign read_en = (state_c == READ) ? 1'b1 : 1'b0 ;
    168. endmodule
    1. `timescale 1ns/1ns
    2. module test_sdram_ctrl();
    3. reg sys_clk ; // 50mHz
    4. reg sys_rst_n ;
    5. wire c0_sig ;
    6. wire c1_sig ;
    7. wire c2_sig ;
    8. wire locked_sig ;
    9. wire rst_n ;
    10. assign rst_n = sys_rst_n && (locked_sig) ;
    11. wire wr_end ; // 需要从sdram_write模块引出。
    12. assign wr_end = sdram_ctrl_inst.sdram_write_inst.wr_end ;
    13. // sdram_ctrl模块输入端口信号。
    14. reg sdram_wr_req ;
    15. reg [23:0] sdram_wr_addr ;
    16. reg [15:0] sdram_wr_data ;
    17. reg [9:0] sdram_wr_bust ;
    18. reg sdram_rd_req ;
    19. reg [23:0] sdram_rd_addr ;
    20. reg [9:0] sdram_rd_bust ;
    21. // sdram_ctrl模块的输出信号。
    22. wire sdram_sck ;
    23. wire sdram_cke ;
    24. wire sdram_csn ;
    25. wire sdram_ras ;
    26. wire sdram_cas ;
    27. wire sdram_wen ;
    28. wire [1:0] sdram_bank ;
    29. wire [12:0] sdram_addr ;
    30. wire [15:0] sdram_dq ;
    31. wire sdram_wr_ack ;
    32. wire sdram_rd_ack ;
    33. wire sdram_init_end;
    34. wire [15:0] sdram_data_out;
    35. clk_gen clk_gen_inst (
    36. .areset (~sys_rst_n ) ,
    37. .inclk0 ( sys_clk ) ,
    38. .c0 ( c0_sig ) , // 50
    39. .c1 ( c1_sig ) , // 100
    40. .c2 ( c2_sig ) , // 100+shift30
    41. .locked ( locked_sig )
    42. );
    43. sdram_ctrl sdram_ctrl_inst(
    44. .sys_clk ( c1_sig ) ,
    45. .sys_rst_n ( rst_n ) ,
    46. .clk_shift ( c2_sig ) ,
    47. .sdram_wr_req ( sdram_wr_req ) ,
    48. .sdram_wr_addr ( sdram_wr_addr ) ,
    49. .sdram_wr_data ( sdram_wr_data ) ,
    50. .sdram_wr_bust ( sdram_wr_bust ) ,
    51. .sdram_rd_req ( sdram_rd_req ) ,
    52. .sdram_rd_addr ( sdram_rd_addr ) ,
    53. .sdram_rd_bust ( sdram_rd_bust ) ,
    54. .sdram_sck ( sdram_sck ) ,
    55. .sdram_cke ( sdram_cke ) , // 时钟使能
    56. .sdram_csn ( sdram_csn ) ,
    57. .sdram_ras ( sdram_ras ) ,
    58. .sdram_cas ( sdram_cas ) ,
    59. .sdram_wen ( sdram_wen ) , // 写使能。
    60. .sdram_bank ( sdram_bank ) ,
    61. .sdram_addr ( sdram_addr ) ,
    62. .sdram_dq ( sdram_dq ) ,
    63. .sdram_wr_ack ( sdram_wr_ack ) ,
    64. .sdram_rd_ack ( sdram_rd_ack ) ,
    65. .sdram_init_end ( sdram_init_end ) ,
    66. .sdram_data_out ( sdram_data_out )
    67. );
    68. sdram_model_plus sdram_model_plus_inst(
    69. .Dq ( sdram_dq ) ,
    70. .Addr ( sdram_addr ) ,
    71. .Ba ( sdram_bank ) ,
    72. .Clk ( sdram_sck ) ,
    73. .Cke ( sdram_cke ) ,
    74. .Cs_n ( sdram_csn ) ,
    75. .Ras_n ( sdram_ras ) ,
    76. .Cas_n ( sdram_cas ) ,
    77. .We_n ( sdram_wen ) ,
    78. .Dqm ( 2'b00 ) ,
    79. .Debug ( 1'b1 )
    80. );
    81. parameter CYCLE = 20 ; // 10ns
    82. defparam sdram_model_plus_inst.addr_bits = 13 ;
    83. defparam sdram_model_plus_inst.data_bits = 16 ;
    84. defparam sdram_model_plus_inst.col_bits = 9 ;
    85. defparam sdram_model_plus_inst.mem_sizes = 2*1024*1024 ;
    86. defparam sdram_ctrl_inst.sdram_aref_inst.MAX_CNT_750US = 75 ;
    87. /**********************************************************************/
    88. reg init_end_reg1 ;
    89. reg init_end_reg2 ;
    90. wire wr_flag ;
    91. always @(posedge c1_sig or negedge rst_n) begin
    92. if(~rst_n) begin
    93. init_end_reg1 <= 1'b0 ;
    94. init_end_reg2 <= 1'b0 ;
    95. end
    96. else begin
    97. init_end_reg1 <= sdram_init_end ;
    98. init_end_reg2 <= init_end_reg1 ;
    99. end
    100. end
    101. assign wr_flag = init_end_reg1 && ~init_end_reg2 ;
    102. // reg sdram_wr_req ;
    103. always @(posedge c1_sig or negedge rst_n) begin
    104. if(~rst_n)
    105. sdram_wr_req <= 1'b0 ;
    106. else if(wr_flag) // 初始化完成之后第一个始终周期就拉高写亲求。
    107. sdram_wr_req <= 1'b1 ;
    108. else if(sdram_wr_ack) // sdram_ctrl回应给FIFO控制模块一个写响应信号后,写请求就可以拉低了。
    109. sdram_wr_req <= 1'b0 ;
    110. else
    111. sdram_wr_req <= sdram_wr_req ;
    112. end
    113. // reg [23:0] sdram_wr_addr ;
    114. // reg [15:0] sdram_wr_data ;
    115. // reg [9:0] sdram_wr_bust ;
    116. always @(posedge c1_sig or negedge sys_rst_n) begin
    117. if(~sys_rst_n)
    118. sdram_wr_data <= 16'd0 ;
    119. else if(sdram_wr_ack == 0)
    120. sdram_wr_data <= 16'd0 ;
    121. else
    122. sdram_wr_data <= sdram_wr_data + 1'b1 ;
    123. end
    124. initial begin
    125. sdram_wr_addr <= 24'd0 ; // bank00,行13'd0,列9'd0;
    126. sdram_wr_bust <= 10'd20 ; // 写入10个数据。
    127. end
    128. // reg sdram_rd_req ;
    129. // always @(posedge c1_sig or negedge sys_rst_n) begin
    130. // if(~rst_n)
    131. // sdram_rd_req <= 1'b0;
    132. // else if(wr_end) // 写操作结束后拉高读请求信号。
    133. // sdram_rd_req >= 1'b1 ;
    134. // else if(sdram_rd_ack) // 读响应信号拉高后,读请求信号拉低。
    135. // sdram_rd_req <= 1'b0;
    136. // else
    137. // sdram_rd_req <= sdram_rd_req ;
    138. // end
    139. always @(posedge c1_sig or negedge sys_rst_n) begin
    140. if(~rst_n)
    141. sdram_rd_req <= 1'b0 ;
    142. else if(wr_end)
    143. sdram_rd_req <= 1'b1 ;
    144. else
    145. sdram_rd_req <= sdram_rd_req ;
    146. end
    147. // reg [23:0] sdram_rd_addr ;
    148. // reg [9:0] sdram_rd_bust ;
    149. initial begin
    150. sdram_rd_addr <= 24'd0 ;
    151. sdram_rd_bust <= 10'd13 ;
    152. end
    153. initial begin
    154. sys_clk = 1'b1 ;
    155. sys_rst_n <= 1'b0 ;
    156. #(CYCLE) ;
    157. sys_rst_n <= 1'b1 ;
    158. #(CYCLE * 250_00) ;
    159. $stop ;
    160. end
    161. always #(CYCLE / 2) sys_clk = ~sys_clk ;
    162. endmodule

    仿真:

    fifo_ctrl: 

    设计思路:

    这个模块要想写好,需要先明确输入端口具体信号是什么样子的。

    我在代码部分有详细说明。 

    第一部分:

    输入端口的设计

    写数据控制部分:fifo_ctrl模块先把uart传输接收到的数据,传输进(write_fifo)中。然后用wr_ack做(write_fifo)的读使能,并把数据传输给sdram_data_in[15:0]。

    读数据控制部分:fifo_ctrl模块先从sdram_ctrl中把数据读出来,并存进(read_fifo)中。然后根据rd_fifo_rd_req把(read_fifo)中的数据读出来。

    1,wr_fifo_wr_clk:写FIFO时钟。

    2,wr_fifo_wr_req:写fifo,写请求。应该连接uart_rx,的po_falg端口。

    3,wr_fifo_wr_data:写进fifo中的数据,应该连接uart_rx,的po_data端口。

    4,sdram_wr_b_addr[23:0]:先把从uart_rx模块接收到的数据存进写fifo做跨时钟域处理,然后写进sdram中。这个sdram_wr_b_addr是写数据进sdram的首地址。

    5,sdram_wr_e_addr[23:0]:是末地址。

    6,wr_rst:地址复位信号,高电平有效。

    7,wr_burst_len[9:0]:写突发长度,由顶层自己设置一个数据写入。

    读数据部分:先从sdram_ctrl模块中读出数据,然后写进FIFO控制模块中的读fifo存储器。

    8,rd_fifo_rd_clk:读fifo的读时钟。

    9,rd_fifo_rd_req:读FIFO的读请求信号。串口数据发送模块产生,读取fifo控制模块中“读FIFO”中的数据。

    10,sdram_rd_b_addr[23:0],需要先读取SDRAM、中的数据,然后写进读fifo。这个信号时读sdram的首地址。

    11,sdram_rd_e_addr[23:0],末地址。

    12,rd_rst,读地址复位信号。

    13,rd_valid:由顶层模块传入,高电平有效,表示可进行sdram读操作。

    14,rd_burst_len[9:0]:读数据突发长度。

    15:init_end:初始化结束信号。

    16:sdram_rd_ack与sdram_wr_ack,分别为sdram对应操作的响应信号。

    17:sdram_data_out[15:0]:从sdram中读出的数据,传递给fifo控制模块中的读fifo模块。为了通过uart_tx模块发送数据,做跨时钟域同步处理。

    第二部分:

    内部变量的设计

    满足数据通路,时序对齐,怎么设计都行。明天完成这个fifo_ctrl模块。

    时序图:

    代码:

    编译时遇到一个时序逻辑中产生锁存器的情况:

    时序逻辑,复位某变量时,如果给该变量赋值某变量(非常量),会产生锁存器。

     改成常量就好了。

    1. // 该模块的作用是辅助sdram_ctrl模块进行数据的读写。
    2. // 将要写进sdram模块的数据进行跨时钟域同步处理。
    3. // 通过uart接收模块(50Mhz)接收(写)数据,缓存进write_fifo中。然后大于突发长度时,产生写请求信号,把写数据,写进sdram。
    4. // 通过uart发送模块(50Mhz)发送(读)数据。读数据是通过saram读模块(100Mhz)读取到的缓存进read_fifo的(读)数据。
    5. // 这个读数据的读请求信号是当,初始化完成,写操作完成,read_fifo中数据量小于读突发长度,那么读请求拉高。从sdram中读数据,并写进read_fifo中。
    6. // uart发送模块产生读请求信号,读取read_fifo中的数据,并传输给上位机。
    7. // 该模块部分代码设计与野火官方有很大不同,与模块框图有不一致的地方。但是谁规定一定要完全仿照别人的东西了?
    8. module fifo_ctrl(
    9. input wire clk_50Mhz , // write_fifo的输入端时钟,read_fifo的输出端时钟。
    10. input wire clk_100Mhz , // 大多数信号的时钟,write_fifo的输出端时钟,read_fifo的输入端时钟。
    11. input wire sys_rst_n , // 系统复位
    12. input wire init_end , // 一切请求在初始化完成之后产生?其实没有必要,因为你即使产生了,也不会被响应。
    13. // 写数据进写write_fifo
    14. input wire wr_fifo_wr_req , // 与uart_rx模块的po_flag相连。
    15. input wire [15:0] wr_fifo_wr_data , // 与uart_rx模块的po_data相连。
    16. // 把数据从write_fifo中读出来并写进sdram
    17. output reg sdram_wr_req , //write_fifo中的二数据量大于一次写突发长度时,即可拉高。不大于时拉低。也就是说如果write_fifo中数据比写突发长度大很多倍,写请求会一直拉高。直到write_fifo中数据小于写突发长度时拉低。
    18. output reg [23:0] sdram_wr_addr , // 输出一次突发写sdram的首地址。
    19. output wire [15:0] sdram_data_in , // 输出突发写,数据。连接到write_fifo的读出数据端口。
    20. input wire [23:0] sdram_wr_b_addr , // 写进sdram的首末地址。2bit,bank地址,9bit列地址,中间13bit的行地址。
    21. input wire [23:0] sdram_wr_e_addr , // 写进sdram的首末地址。
    22. input wire sdram_wr_ack , // 用来复位写进sdram地址的(sdram_wr_addr),它的下降沿表示一次写突发数据完成,可以用此下降沿作数据更新依据。因为采用突发方式写数据(写突发长度是任意的)。写完后需要更新地址。除非你想一直在相同地址范围内写数据,那就不用更新写地址,就不用复位。
    23. input wire wr_rst ,
    24. input wire [9:0] wr_bust_len , // 写数据突发长度。
    25. // 从sdram中读数据
    26. output reg sdram_rd_req , // 申请读sdram中数据的读请求。
    27. output reg [23:0] sdram_rd_addr , // 一次读突发的,读首地址。
    28. input wire [23:0] rd_fifo_b_addr , // 外界传入的读突发的首末地址。作为sdram_rd_addr的赋值参考依据。
    29. input wire [23:0] rd_fifo_e_addr , // 外界传入的读突发的首末地址。作为sdram_rd_addr的赋值参考依据。
    30. input wire sdram_rd_ack , // 用来复位读突发地址。用来做read_fifo的写入数据使能。
    31. input wire rd_rst , // 与wr_rst一样,是外界传输的
    32. input wire [9:0] rd_bust_len , // 读突发长度。
    33. input wire [15:0] sdram_data_out , // 从sdram中读数据。
    34. //read_fifo中读出数据。传给下一个模块。
    35. output wire [15:0] rd_fifo_rd_data , //read_fifo中读出的数据。连接到read_fifo的数据输出端口。
    36. output wire [9:0] rd_fifo_num , // read_fifo中“存储”的数据个数,传给外界的一个读模块,用来产生read_fifo的读请求模块。
    37. input wire rd_valid , // 读数据有效信号,sdram_top凭空产生的。个人认为没什么用。类似于使能信号?但是下面都有请求信号了。
    38. input wire rd_fifo_rd_req // 下一个模块产生的,根据read_fifo中存储的数据个数。
    39. ); // 仿真时记得把rd_valid信号拉高;rd_rst ;wr_rst 信号相对于sys_rst_n 取反。
    40. // 例化间连线。
    41. wire [9:0] wrusedw_write_num1 ; // write_fifo中存储的数据个数。
    42. wire [9:0] wrusedw_write_num2 ; // write_fifo中存储的数据个数。
    43. wire [9:0] wrusedw_read_num1 ; // read_fifo中存储的数据个数。
    44. wire [9:0] wrusedw_read_num2 ; // read_fifo中存储的数据个数。
    45. wire wr_ack_dly1_nege ;
    46. wire rd_ack_dly1_nege ;
    47. // reg signal define
    48. reg wr_ack_dly1 ;
    49. reg rd_ack_dly1 ;
    50. // wr_ack_dly1 rd_ack_dly1
    51. always @(posedge clk_100Mhz or negedge sys_rst_n) begin
    52. if(~sys_rst_n)
    53. begin
    54. wr_ack_dly1 <= 1'b0 ;
    55. rd_ack_dly1 <= 1'b0 ;
    56. end
    57. else
    58. begin
    59. wr_ack_dly1 <= sdram_wr_ack ;
    60. rd_ack_dly1 <= sdram_rd_ack ;
    61. end
    62. end
    63. // wr_ack_dly1_nege rd_ack_dly1_nege
    64. assign wr_ack_dly1_nege = (~sdram_wr_ack) && (wr_ack_dly1);
    65. assign rd_ack_dly1_nege = (~sdram_rd_ack) && (rd_ack_dly1);
    66. // reg sdram_wr_req
    67. always @(posedge clk_100Mhz or negedge sys_rst_n) begin
    68. if(~sys_rst_n)
    69. sdram_wr_req <= 1'b0 ;
    70. else if(init_end && wrusedw_write_num1 >= wr_bust_len)
    71. sdram_wr_req <= 1'b1 ;
    72. else
    73. sdram_wr_req <= 1'b0 ;
    74. end
    75. // reg [23:0] sdram_wr_addr , // 输出一次突发写sdram的首地址
    76. // always @(posedge clk_100Mhz or negedge sys_rst_n) begin
    77. // if(~sys_rst_n)
    78. // sdram_wr_addr <= sdram_wr_b_addr ;
    79. // else if((sdram_wr_addr < (sdram_wr_e_addr - sdram_wr_b_addr - wr_bust_len)) && wr_ack_dly1_nege)
    80. // sdram_wr_addr <= sdram_wr_addr + wr_bust_len;
    81. // else if(wr_ack_dly1_nege)
    82. // sdram_wr_addr <= sdram_wr_b_addr ;
    83. // else
    84. // sdram_wr_addr <= sdram_wr_addr ;
    85. // end
    86. always @(posedge clk_100Mhz or negedge sys_rst_n) begin
    87. if(~sys_rst_n)
    88. sdram_wr_addr <= 24'd0 ;
    89. else if(wr_rst == 1)
    90. sdram_wr_addr <= sdram_wr_b_addr ;
    91. else if(wr_ack_dly1_nege)
    92. begin
    93. if(sdram_wr_addr < (sdram_wr_e_addr - sdram_wr_b_addr - wr_bust_len))
    94. sdram_wr_addr <= sdram_wr_addr + wr_bust_len;
    95. else
    96. sdram_wr_addr <= sdram_wr_b_addr ;
    97. end
    98. else
    99. sdram_wr_addr <= sdram_wr_addr ;
    100. end
    101. // reg sdram_rd_req , // 申请读sdram中数据的读请求。每完成一次写操作,或者读操作后,若read_fifo中的数据小于rd_bust_len,则需拉高读请求。
    102. always @(posedge clk_100Mhz or negedge sys_rst_n) begin
    103. if(~sys_rst_n)
    104. sdram_rd_req <= 1'b0 ;
    105. else
    106. if(rd_valid == 1)
    107. begin
    108. if(wrusedw_read_num1 < rd_bust_len && (wr_ack_dly1_nege || rd_ack_dly1_nege))
    109. sdram_rd_req <= 1'b1 ;
    110. else if(wrusedw_read_num1 >= rd_bust_len && (wr_ack_dly1_nege || rd_ack_dly1_nege))
    111. sdram_rd_req <= 1'b0 ;
    112. else
    113. sdram_rd_req <= sdram_rd_req ;
    114. end
    115. else
    116. sdram_rd_req <= 1'b0 ;
    117. end
    118. // reg [23:0] sdram_rd_addr , // 一次读突发的,读首地址。
    119. always @(posedge clk_100Mhz or negedge sys_rst_n) begin
    120. if(~sys_rst_n)
    121. sdram_rd_addr <= 24'd0 ;
    122. else if(rd_rst == 1)
    123. sdram_rd_addr <= rd_fifo_b_addr ;
    124. else if(sdram_rd_addr < (rd_fifo_e_addr - rd_fifo_b_addr - rd_bust_len) && rd_ack_dly1_nege)
    125. sdram_rd_addr <= sdram_rd_addr + rd_bust_len ;
    126. else if(sdram_rd_addr >= (rd_fifo_e_addr - rd_fifo_b_addr - rd_bust_len) && rd_ack_dly1_nege)
    127. sdram_rd_addr <= rd_fifo_b_addr ;
    128. else
    129. sdram_rd_addr <= sdram_rd_addr ;
    130. end
    131. // wire [9:0] rd_fifo_num , // read_fifo中“存储”的数据个数,传给外界的一个读模块,用来产生read_fifo的读请求模块。
    132. assign rd_fifo_num = wrusedw_read_num1 ;
    133. // 例化write_fifo read_fifo
    134. fifo_data_16x1024 write_fifo_data_16x1024(
    135. .data ( wr_fifo_wr_data ) ,
    136. .wrclk ( clk_50Mhz ) ,
    137. .wrreq ( wr_fifo_wr_req ) ,
    138. .wrusedw ( wrusedw_write_num1 ) , // ???
    139. .rdclk ( clk_100Mhz ) ,
    140. .rdreq ( sdram_wr_ack ) ,
    141. .q ( sdram_data_in ) ,
    142. .rdusedw ( wrusedw_write_num2 ) // ???
    143. );
    144. fifo_data_16x1024 read_fifo_data_16x1024(
    145. .data ( sdram_data_out ) ,
    146. .wrclk ( clk_100Mhz ) ,
    147. .wrreq ( sdram_rd_ack ) ,
    148. .wrusedw ( wrusedw_read_num1 ) , // ???
    149. .rdclk ( clk_50Mhz ) ,
    150. .rdreq ( rd_fifo_rd_req ) ,
    151. .q ( rd_fifo_rd_data ) ,
    152. .rdusedw ( wrusedw_read_num2 ) // ???
    153. );
    154. endmodule
    仿真:

    没有单独仿真。

    sdram_top:

    设计思路

    该模块例化了fifo_ctrl模块与sdram_ctrl模块。

    例化完后对sdram_top进行仿真验证:

    通过uart_rx模块,先传输10个数据进write_fifo

    等待sdram完成初始化,然后拉高写请求,把write_fifo中的10个数据写进sdram中。

    写完后仲裁模块响应读请求,然后读取10个数据进read_fifo

    然后拉高rd_fifo_rd_req读读fifo请求信号,把read_fifo中存的10个数据读出来。

    但是要保持read_fifo存储器中存有10个数据,会再次拉高读请求,从sdram中读出10个数据进read_fifo。

    之后不会再次拉高rd_fifo_rd_req,除非有其他控制信号干预,想要再次读取数据时会拉高。

    代码: 

    1. module sdram_top(
    2. input wire clk_50Mhz ,
    3. input wire clk_100Mhz ,
    4. input wire clk_shift ,
    5. input wire sys_rst_n ,
    6. input wire wr_fifo_wr_req ,
    7. input wire [15:0] wr_fifo_wr_data ,
    8. input wire [23:0] sdram_wr_b_addr ,
    9. input wire [23:0] sdram_wr_e_addr ,
    10. input wire wr_rst ,
    11. input wire [9:0] wr_bust_len ,
    12. input wire [23:0] rd_fifo_b_addr ,
    13. input wire [23:0] rd_fifo_e_addr ,
    14. input wire rd_rst ,
    15. input wire [9:0] rd_bust_len ,
    16. input wire rd_valid ,
    17. input wire rd_fifo_rd_req ,
    18. output wire [15:0] rd_fifo_rd_data ,
    19. output wire [9:0] rd_fifo_num ,
    20. output wire sdram_sck , // 偏移+30度的时钟。
    21. output wire sdram_cke , // 时钟使能
    22. output wire sdram_csn ,
    23. output wire sdram_ras ,
    24. output wire sdram_cas ,
    25. output wire sdram_wen , // 写使能。
    26. output wire [1:0] sdram_bank ,
    27. output wire [12:0] sdram_addr ,
    28. inout wire [15:0] sdram_dq ,
    29. output wire [1:0] sdram_dqm // 数据掩码。
    30. );
    31. assign sdram_dqm = 2'b00 ;
    32. // 例化间连线
    33. wire sdram_init_end ;
    34. wire sdram_wr_req ;
    35. wire [23:0] sdram_wr_addr ;
    36. wire [15:0] sdram_data_in ;
    37. wire sdram_wr_ack ;
    38. wire sdram_rd_ack ;
    39. wire sdram_rd_req ;
    40. wire [23:0] sdram_rd_addr ;
    41. wire [15:0] sdram_data_out ;
    42. fifo_ctrl fifo_ctrl_inst(
    43. .clk_50Mhz ( clk_50Mhz ) , // write_fifo的输入端时钟,read_fifo的输出端时钟。
    44. .clk_100Mhz ( clk_100Mhz ) , // 大多数信号的时钟,write_fifo的输出端时钟,read_fifo的输入端时钟。
    45. .sys_rst_n ( sys_rst_n ) , // 系统复位
    46. .init_end ( sdram_init_end ) , // 一切请求在初始化完成之后产生?其实没有必要,因为你即使产生了,也不会被响应。
    47. // 写数据进写write_fifo
    48. .wr_fifo_wr_req ( wr_fifo_wr_req ) , // 与uart_rx模块的po_flag相连。
    49. .wr_fifo_wr_data ( wr_fifo_wr_data ) , // 与uart_rx模块的po_data相连。
    50. // 把数据从write_fifo中读出来并写进sdram
    51. .sdram_wr_req ( sdram_wr_req ) , // 当write_fifo中的二数据量大于一次写突发长度时,即可拉高。不大于时拉低。也就是说如果write_fifo中数据比写突发长度大很多倍,写请求会一直拉高。直到write_fifo中数据小于写突发长度时拉低。
    52. .sdram_wr_addr ( sdram_wr_addr ) , // 输出一次突发写sdram的首地址。
    53. .sdram_data_in ( sdram_data_in ) , // 输出突发写,数据。连接到write_fifo的读出数据端口。
    54. .sdram_wr_b_addr ( sdram_wr_b_addr ) , // 写进sdram的首末地址。2bit,bank地址,9bit列地址,中间13bit的行地址。
    55. .sdram_wr_e_addr ( sdram_wr_e_addr ) , // 写进sdram的首末地址。
    56. .sdram_wr_ack ( sdram_wr_ack ) , // 用来复位写进sdram地址的(sdram_wr_addr),它的下降沿表示一次写突发数据完成,可以用此下降沿作数据更新依据。因为采用突发方式写数据(写突发长度是任意的)。写完后需要更新地址。除非你想一直在相同地址范围内写数据,那就不用更新写地址,就不用复位。
    57. .wr_rst ( wr_rst ) ,
    58. .wr_bust_len ( wr_bust_len ) , // 写数据突发长度。
    59. // 从sdram中读数据
    60. .sdram_rd_req ( sdram_rd_req ) , // 申请读sdram中数据的读请求。
    61. .sdram_rd_addr ( sdram_rd_addr ) , // 一次读突发的,读首地址。
    62. .rd_fifo_b_addr ( rd_fifo_b_addr ) , // 外界传入的读突发的首末地址。作为sdram_rd_addr的赋值参考依据。
    63. .rd_fifo_e_addr ( rd_fifo_e_addr ) , // 外界传入的读突发的首末地址。作为sdram_rd_addr的赋值参考依据。
    64. .sdram_rd_ack ( sdram_rd_ack ) , // 用来复位读突发地址。用来做read_fifo的写入数据使能。
    65. .rd_rst ( rd_rst ) , // 与wr_rst一样,是外界传输的
    66. .rd_bust_len ( rd_bust_len ) , // 读突发长度。
    67. .sdram_data_out ( sdram_data_out ) , // 从sdram中读数据。
    68. // 从read_fifo中读出数据。传给下一个模块。
    69. .rd_fifo_rd_data ( rd_fifo_rd_data ) , // 从read_fifo中读出的数据。连接到read_fifo的数据输出端口。
    70. .rd_fifo_num ( rd_fifo_num ) , // read_fifo中“存储”的数据个数,传给外界的一个读模块,用来产生read_fifo的读请求模块。
    71. .rd_valid ( rd_valid ) , // 读数据有效信号,sdram_top凭空产生的。个人认为没什么用。类似于使能信号?但是下面都有请求信号了。
    72. .rd_fifo_rd_req ( rd_fifo_rd_req ) // 下一个模块产生的,根据read_fifo中存储的数据个数。
    73. );
    74. sdram_ctrl sdram_ctrl_inst(
    75. .sys_clk ( clk_100Mhz ) ,
    76. .sys_rst_n ( sys_rst_n ) ,
    77. .clk_shift ( clk_shift ) ,
    78. .sdram_wr_req ( sdram_wr_req ) ,
    79. .sdram_wr_addr ( sdram_wr_addr ) ,
    80. .sdram_wr_data ( sdram_data_in ) ,
    81. .sdram_wr_bust ( wr_bust_len ) ,
    82. .sdram_rd_req ( sdram_rd_req ) ,
    83. .sdram_rd_addr ( sdram_rd_addr ) ,
    84. .sdram_rd_bust ( rd_bust_len ) ,
    85. .sdram_sck ( sdram_sck ) , // 偏移+30度的时钟。
    86. .sdram_cke ( sdram_cke ) , // 时钟使能
    87. .sdram_csn ( sdram_csn ) ,
    88. .sdram_ras ( sdram_ras ) ,
    89. .sdram_cas ( sdram_cas ) ,
    90. .sdram_wen ( sdram_wen ) , // 写使能。
    91. .sdram_bank ( sdram_bank ) ,
    92. .sdram_addr ( sdram_addr ) ,
    93. .sdram_dq ( sdram_dq ) ,
    94. .sdram_wr_ack ( sdram_wr_ack ) ,
    95. .sdram_rd_ack ( sdram_rd_ack ) ,
    96. .sdram_init_end ( sdram_init_end ) ,
    97. .sdram_data_out ( sdram_data_out )
    98. );
    99. endmodule

    仿真: 

    1. `timescale 1ns/1ns
    2. module test_sdram_top ();
    3. reg sys_clk_50Mhz ;
    4. reg sys_rst_n ;
    5. wire c0_sig ;
    6. wire c1_sig ;
    7. wire c2_sig ;
    8. wire locked_sig ;
    9. wire rst_n ;
    10. reg rx ;
    11. wire po_flag ;
    12. wire [7:0] po_data ;
    13. reg rd_fifo_rd_req ;
    14. wire [15:0] rd_fifo_rd_data ;
    15. wire [9:0] rd_fifo_num ;
    16. wire sdram_sck ;
    17. wire sdram_cke ;
    18. wire sdram_csn ;
    19. wire sdram_ras ;
    20. wire sdram_cas ;
    21. wire sdram_wen ;
    22. wire [1:0] sdram_bank ;
    23. wire [12:0] sdram_addr ;
    24. wire [15:0] sdram_dq ;
    25. wire [1:0] sdram_dqm ;
    26. wire [9:0] rd_bust_len ;
    27. wire [9:0] wr_bust_len ;
    28. reg rd_flag ;
    29. // 例化
    30. clk_gen clk_gen_inst (
    31. .areset ( ~sys_rst_n ) ,
    32. .inclk0 ( sys_clk_50Mhz ) ,
    33. .c0 ( c0_sig ) , // 50m
    34. .c1 ( c1_sig ) , // 100m
    35. .c2 ( c2_sig ) , // 100m shift
    36. .locked ( locked_sig )
    37. );
    38. uart_rx uart_rx_inst(
    39. .sys_clk ( c0_sig ) ,
    40. .sys_rst_n ( rst_n ) ,
    41. .rx ( rx ) ,
    42. .po_flag ( po_flag ) ,
    43. .po_data ( po_data )
    44. );
    45. sdram_top sdram_top_inst(
    46. .clk_50Mhz ( c0_sig ) ,
    47. .clk_100Mhz ( c1_sig ) ,
    48. .clk_shift ( c2_sig ) ,
    49. .sys_rst_n ( rst_n ) ,
    50. .wr_fifo_wr_req ( po_flag ) ,
    51. .wr_fifo_wr_data ( {8'h00,po_data} ) ,
    52. .sdram_wr_b_addr ( 24'd0 ) ,
    53. .sdram_wr_e_addr ( 24'd10 ) ,
    54. .wr_rst ( ~rst_n ) ,
    55. .wr_bust_len ( wr_bust_len ) ,
    56. .rd_fifo_b_addr ( 24'd0 ) ,
    57. .rd_fifo_e_addr ( 24'd10 ) ,
    58. .rd_rst ( ~rst_n ) ,
    59. .rd_bust_len ( rd_bust_len ) ,
    60. .rd_valid ( 1'b1 ) ,
    61. .rd_fifo_rd_req ( rd_fifo_rd_req) ,
    62. .rd_fifo_rd_data (rd_fifo_rd_data) ,
    63. .rd_fifo_num ( rd_fifo_num ) ,
    64. .sdram_sck ( sdram_sck ) , // 偏移+30度的时钟。
    65. .sdram_cke ( sdram_cke ) , // 时钟使能
    66. .sdram_csn ( sdram_csn ) ,
    67. .sdram_ras ( sdram_ras ) ,
    68. .sdram_cas ( sdram_cas ) ,
    69. .sdram_wen ( sdram_wen ) , // 写使能。
    70. .sdram_bank ( sdram_bank ) ,
    71. .sdram_addr ( sdram_addr ) ,
    72. .sdram_dq ( sdram_dq ) ,
    73. .sdram_dqm ( sdram_dqm ) // 数据掩码。
    74. );
    75. sdram_model_plus sdram_model_plus_inst(
    76. .Dq ( sdram_dq ) ,
    77. .Addr ( sdram_addr ) ,
    78. .Ba ( sdram_bank ) ,
    79. .Clk ( sdram_sck ) ,
    80. .Cke ( sdram_cke ) ,
    81. .Cs_n ( sdram_csn ) ,
    82. .Ras_n ( sdram_ras ) ,
    83. .Cas_n ( sdram_cas ) ,
    84. .We_n ( sdram_wen ) ,
    85. .Dqm ( {2'b00,sdram_dqm} ) ,
    86. .Debug ( 1'b1 )
    87. );
    88. /****************************************************************/
    89. parameter CYCLE = 20 ;
    90. defparam uart_rx_inst.CLK_UART = 50_000_0 ;
    91. defparam sdram_top_inst.sdram_ctrl_inst.sdram_aref_inst.MAX_CNT_750US = 200 ;
    92. defparam sdram_model_plus_inst.addr_bits = 13 ;
    93. defparam sdram_model_plus_inst.data_bits = 16 ;
    94. defparam sdram_model_plus_inst.col_bits = 9 ;
    95. defparam sdram_model_plus_inst.mem_sizes = 2*1024*1024 ;
    96. // rst_n rd_bust_len wr_bust_len
    97. assign rst_n = sys_rst_n && locked_sig ;
    98. assign rd_bust_len = 10'd10 ;
    99. assign wr_bust_len = 10'd10 ;
    100. // rx
    101. task rx_bit ;
    102. input [7:0] data ;
    103. integer i ;
    104. for (i = 0;i <= 9 ;i = i + 1 ) begin
    105. case (i)
    106. 0: rx <= 1'b0 ;
    107. 1: rx <= data[i - 1];
    108. 2: rx <= data[i - 1];
    109. 3: rx <= data[i - 1];
    110. 4: rx <= data[i - 1];
    111. 5: rx <= data[i - 1];
    112. 6: rx <= data[i - 1];
    113. 7: rx <= data[i - 1];
    114. 8: rx <= data[i - 1];
    115. 9: rx <= 1'b1 ;
    116. default: rx <= 1'b1 ;
    117. endcase
    118. #(CYCLE * 52) ;
    119. end
    120. endtask
    121. // rd_fifo_rd_req
    122. // always @(posedge c0_sig or negedge rst_n) begin
    123. // if(~rst_n)
    124. // rd_fifo_rd_req <= 1'b0 ;
    125. // else if(rd_fifo_num == rd_bust_len)
    126. // rd_fifo_rd_req <= 1'b1 ;
    127. // else if(rd_fifo_num == 0)
    128. // rd_fifo_rd_req <= 1'b0 ;
    129. // else
    130. // rd_fifo_rd_req <= rd_fifo_rd_req ;
    131. // end
    132. always @(posedge c0_sig or negedge rst_n) begin
    133. if(~rst_n)
    134. rd_flag <= 1'b1 ;
    135. else if(rd_fifo_num == rd_bust_len && rd_flag == 1'b1)
    136. rd_flag <= 1'b0 ;
    137. else
    138. rd_flag <= rd_flag ;
    139. end
    140. always @(posedge c0_sig or negedge rst_n) begin
    141. if(~rst_n)
    142. rd_fifo_rd_req <= 1'b0 ;
    143. else if(rd_fifo_num == rd_bust_len && rd_flag)
    144. rd_fifo_rd_req <= 1'b1 ;
    145. else if(rd_fifo_num == 0)
    146. rd_fifo_rd_req <= 1'b0 ;
    147. else
    148. rd_fifo_rd_req <= rd_fifo_rd_req ;
    149. end
    150. initial begin
    151. sys_clk_50Mhz = 1'b1 ;
    152. sys_rst_n <= 1'b0 ;
    153. rx <= 1'b1 ;
    154. #(CYCLE) ;
    155. sys_rst_n <= 1'b1 ;
    156. #( CYCLE * 100 ) ;
    157. rx_bit(8'b1) ;
    158. rx_bit(8'd2) ;
    159. rx_bit(8'd3) ;
    160. rx_bit(8'd4) ;
    161. rx_bit(8'd5) ;
    162. rx_bit(8'd6) ;
    163. rx_bit(8'd7) ;
    164. rx_bit(8'd8) ;
    165. rx_bit(8'd9) ;
    166. rx_bit(8'd9) ;
    167. end
    168. always #(CYCLE / 2) sys_clk_50Mhz = ~sys_clk_50Mhz ;
    169. endmodule

    uart_sdram:

    read_fifo:

    设计思路:

    从read_fifo中读出的10个数据时50Mhz时钟下的,需要先存进fifo,然后由波特率产生标志信号,作为fifo的读标志。把标志打拍与读出的数据作为po_flag_tx与po_flag_tx。传给uart_tx模块。

    修改uart_tx模块,产生一个data_over信号,传递完一帧数据的最后一位拉高一个时钟周期,作为read_fifo的读信号。

    时序图:

    代码:
    1. module fifo_read(
    2. input wire sys_clk , // clk_50M
    3. input wire sys_rst_n ,
    4. input wire [7:0] rd_fifo_rd_data ,
    5. input wire [9:0] rd_fifo_num ,
    6. input wire [9:0] bust_num , // 作为顶层模块设置并输入,为固定参数,表示本模块一次读取读 FIFO 中数据个数,参数数值与数据读模块中读突发长度一致,防止数据读空。
    7. input wire data_over ,
    8. output reg read_en , // read_en的设计可以参考仿真模块里的设计。
    9. output wire [7:0] tx_data ,
    10. output reg tx_flag
    11. );
    12. parameter BPS = 9600 ,
    13. BIT = 10 ;
    14. reg fifo_256_wren ; // 经过观察read_en与rd_fifo_rd_data的关系,打一拍,会与rd_fifo_rd_data对齐,做fifo的写使能。
    15. wire [7:0] wrusedw ; // 写进本模块fifo中的数据。当wrusedw == bust_len - 2时,read_en拉低。
    16. reg rd_fifo256_en ; // fifo256开始进行读的使能信号。
    17. reg rd_fifo256_en_r ; // fifo256开始进行读的使能信号。打拍
    18. reg rd_fifo256 ; // fifo256读请求信号。
    19. wire empty ;
    20. // fifo_256_wren
    21. always @(posedge sys_clk or negedge sys_rst_n) begin
    22. if(~sys_rst_n)
    23. fifo_256_wren <= 1'b0 ;
    24. else
    25. fifo_256_wren <= read_en ;
    26. end
    27. // rd_fifo256_en
    28. always @(posedge sys_clk or negedge sys_rst_n) begin
    29. if(~sys_rst_n)
    30. rd_fifo256_en <= 1'b0 ;
    31. else if(empty == 1)
    32. rd_fifo256_en <= 1'b0 ;
    33. else if(!empty && !read_en && fifo_256_wren)
    34. rd_fifo256_en <= 1'b1 ;
    35. end
    36. // rd_fifo256_en_r
    37. always @(posedge sys_clk or negedge sys_rst_n) begin
    38. if(~sys_rst_n)
    39. rd_fifo256_en_r <= 1'b0 ;
    40. else
    41. rd_fifo256_en_r <= rd_fifo256_en ;
    42. end
    43. // rd_fifo256
    44. always @(posedge sys_clk or negedge sys_rst_n) begin
    45. if(~sys_rst_n)
    46. rd_fifo256 <= 1'b0 ;
    47. else if(rd_fifo256_en) begin
    48. if((~rd_fifo256_en_r) || (!empty && data_over))
    49. rd_fifo256 <= 1'b1 ;
    50. else
    51. rd_fifo256 <= 1'b0 ;
    52. end
    53. else
    54. rd_fifo256 <= 1'b0 ;
    55. end
    56. // output signal describe
    57. // read_en
    58. always @(posedge sys_clk or negedge sys_rst_n) begin
    59. if(~sys_rst_n)
    60. read_en <= 1'b0 ;
    61. else if(rd_fifo_num == bust_num)
    62. read_en <= 1'b1 ;
    63. else if(wrusedw == bust_num - 3) // 提前拉低。
    64. read_en <= 1'b0 ;
    65. else
    66. read_en <= read_en ;
    67. end
    68. // wire [7:0] tx_data ,
    69. // reg tx_flag
    70. always @(posedge sys_clk or negedge sys_rst_n) begin
    71. if(~sys_rst_n)
    72. tx_flag <= 1'b0 ;
    73. else
    74. tx_flag <= rd_fifo256 ;
    75. end
    76. // 例化
    77. fifo_data_8x256 fifo_data_8x256_inst(
    78. .wrclk ( sys_clk ) , // 写时钟与读时钟貌似是相同的。
    79. .wrreq ( fifo_256_wren ) , // 写请求。
    80. .data ( rd_fifo_rd_data ) ,
    81. .rdclk ( sys_clk ) ,
    82. .rdreq ( rd_fifo256 ) ,
    83. .rdempty ( empty ),
    84. .q ( tx_data ) ,
    85. .rdusedw ( ) ,
    86. .wrusedw ( wrusedw )
    87. );
    88. endmodule
    仿真:

    仍然对顶层模块仿真,测试文件稍作修改。

    把read_fifo模块与uart_tx加进去。

    1. `timescale 1ns/1ns
    2. module test_sdram_top ();
    3. reg sys_clk_50Mhz ;
    4. reg sys_rst_n ;
    5. wire c0_sig ;
    6. wire c1_sig ;
    7. wire c2_sig ;
    8. wire locked_sig ;
    9. wire rst_n ;
    10. reg rx ;
    11. wire po_flag ;
    12. wire [7:0] po_data ;
    13. reg rd_fifo_rd_req ;
    14. wire [15:0] rd_fifo_rd_data ;
    15. wire [9:0] rd_fifo_num ;
    16. wire sdram_sck ;
    17. wire sdram_cke ;
    18. wire sdram_csn ;
    19. wire sdram_ras ;
    20. wire sdram_cas ;
    21. wire sdram_wen ;
    22. wire [1:0] sdram_bank ;
    23. wire [12:0] sdram_addr ;
    24. wire [15:0] sdram_dq ;
    25. wire [1:0] sdram_dqm ;
    26. wire [9:0] rd_bust_len ;
    27. wire [9:0] wr_bust_len ;
    28. reg rd_flag ;
    29. wire data_over ;
    30. wire read_en ;
    31. wire [7:0] tx_data ;
    32. wire tx_flag ;
    33. wire tx ;
    34. // 例化
    35. clk_gen clk_gen_inst (
    36. .areset ( ~sys_rst_n ) ,
    37. .inclk0 ( sys_clk_50Mhz ) ,
    38. .c0 ( c0_sig ) , // 50m
    39. .c1 ( c1_sig ) , // 100m
    40. .c2 ( c2_sig ) , // 100m shift
    41. .locked ( locked_sig )
    42. );
    43. uart_rx uart_rx_inst(
    44. .sys_clk ( c0_sig ) ,
    45. .sys_rst_n ( rst_n ) ,
    46. .rx ( rx ) ,
    47. .po_flag ( po_flag ) ,
    48. .po_data ( po_data )
    49. );
    50. sdram_top sdram_top_inst(
    51. .clk_50Mhz ( c0_sig ) ,
    52. .clk_100Mhz ( c1_sig ) ,
    53. .clk_shift ( c2_sig ) ,
    54. .sys_rst_n ( rst_n ) ,
    55. .wr_fifo_wr_req ( po_flag ) ,
    56. .wr_fifo_wr_data ( {8'h00,po_data} ) ,
    57. .sdram_wr_b_addr ( 24'd0 ) ,
    58. .sdram_wr_e_addr ( 24'd10 ) ,
    59. .wr_rst ( ~rst_n ) ,
    60. .wr_bust_len ( wr_bust_len ) ,
    61. .rd_fifo_b_addr ( 24'd0 ) ,
    62. .rd_fifo_e_addr ( 24'd10 ) ,
    63. .rd_rst ( ~rst_n ) ,
    64. .rd_bust_len ( rd_bust_len ) ,
    65. .rd_valid ( 1'b1 ) ,
    66. .rd_fifo_rd_req ( read_en ) , // rd_fifo_rd_req
    67. .rd_fifo_rd_data (rd_fifo_rd_data) ,
    68. .rd_fifo_num ( rd_fifo_num ) ,
    69. .sdram_sck ( sdram_sck ) , // 偏移+30度的时钟。
    70. .sdram_cke ( sdram_cke ) , // 时钟使能
    71. .sdram_csn ( sdram_csn ) ,
    72. .sdram_ras ( sdram_ras ) ,
    73. .sdram_cas ( sdram_cas ) ,
    74. .sdram_wen ( sdram_wen ) , // 写使能。
    75. .sdram_bank ( sdram_bank ) ,
    76. .sdram_addr ( sdram_addr ) ,
    77. .sdram_dq ( sdram_dq ) ,
    78. .sdram_dqm ( sdram_dqm ) // 数据掩码。
    79. );
    80. sdram_model_plus sdram_model_plus_inst(
    81. .Dq ( sdram_dq ) ,
    82. .Addr ( sdram_addr ) ,
    83. .Ba ( sdram_bank ) ,
    84. .Clk ( sdram_sck ) ,
    85. .Cke ( sdram_cke ) ,
    86. .Cs_n ( sdram_csn ) ,
    87. .Ras_n ( sdram_ras ) ,
    88. .Cas_n ( sdram_cas ) ,
    89. .We_n ( sdram_wen ) ,
    90. .Dqm ( {2'b00,sdram_dqm} ) ,
    91. .Debug ( 1'b1 )
    92. );
    93. fifo_read fifo_read_inst(
    94. .sys_clk ( c0_sig ) , // clk_50M
    95. .sys_rst_n ( rst_n ) ,
    96. .rd_fifo_rd_data ( rd_fifo_rd_data[7:0] ) ,
    97. .rd_fifo_num ( rd_fifo_num ) ,
    98. .bust_num ( rd_bust_len ) ,
    99. .data_over ( data_over ) ,
    100. .read_en ( read_en ) , // read_en的设计可以参考仿真模块里的设计。
    101. .tx_data ( tx_data ) ,
    102. .tx_flag ( tx_flag )
    103. );
    104. uart_tx uart_tx_inst(
    105. .sys_clk ( c0_sig ) ,
    106. .sys_rst_n ( rst_n ) ,
    107. .pi_data ( tx_data ) ,
    108. .pi_flag ( tx_flag ) ,
    109. .data_over ( data_over ) ,
    110. .tx ( tx )
    111. );
    112. /****************************************************************/
    113. parameter CYCLE = 20 ;
    114. defparam uart_tx_inst.CLK_UART = 50_000_0 ;
    115. defparam uart_rx_inst.CLK_UART = 50_000_0 ;
    116. defparam sdram_top_inst.sdram_ctrl_inst.sdram_aref_inst.MAX_CNT_750US = 200 ;
    117. defparam sdram_model_plus_inst.addr_bits = 13 ;
    118. defparam sdram_model_plus_inst.data_bits = 16 ;
    119. defparam sdram_model_plus_inst.col_bits = 9 ;
    120. defparam sdram_model_plus_inst.mem_sizes = 2*1024*1024 ;
    121. // rst_n rd_bust_len wr_bust_len
    122. assign rst_n = sys_rst_n && locked_sig ;
    123. assign rd_bust_len = 10'd10 ;
    124. assign wr_bust_len = 10'd10 ;
    125. // rx
    126. task rx_bit ;
    127. input [7:0] data ;
    128. integer i ;
    129. for (i = 0;i <= 9 ;i = i + 1 ) begin
    130. case (i)
    131. 0: rx <= 1'b0 ;
    132. 1: rx <= data[i - 1];
    133. 2: rx <= data[i - 1];
    134. 3: rx <= data[i - 1];
    135. 4: rx <= data[i - 1];
    136. 5: rx <= data[i - 1];
    137. 6: rx <= data[i - 1];
    138. 7: rx <= data[i - 1];
    139. 8: rx <= data[i - 1];
    140. 9: rx <= 1'b1 ;
    141. default: rx <= 1'b1 ;
    142. endcase
    143. #(CYCLE * 52) ;
    144. end
    145. endtask
    146. // rd_fifo_rd_req
    147. // always @(posedge c0_sig or negedge rst_n) begin
    148. // if(~rst_n)
    149. // rd_fifo_rd_req <= 1'b0 ;
    150. // else if(rd_fifo_num == rd_bust_len)
    151. // rd_fifo_rd_req <= 1'b1 ;
    152. // else if(rd_fifo_num == 0)
    153. // rd_fifo_rd_req <= 1'b0 ;
    154. // else
    155. // rd_fifo_rd_req <= rd_fifo_rd_req ;
    156. // end
    157. always @(posedge c0_sig or negedge rst_n) begin
    158. if(~rst_n)
    159. rd_flag <= 1'b1 ;
    160. else if(rd_fifo_num == rd_bust_len && rd_flag == 1'b1)
    161. rd_flag <= 1'b0 ;
    162. else
    163. rd_flag <= rd_flag ;
    164. end
    165. always @(posedge c0_sig or negedge rst_n) begin
    166. if(~rst_n)
    167. rd_fifo_rd_req <= 1'b0 ;
    168. else if(rd_fifo_num == rd_bust_len && rd_flag)
    169. rd_fifo_rd_req <= 1'b1 ;
    170. else if(rd_fifo_num == 2)
    171. rd_fifo_rd_req <= 1'b0 ;
    172. else
    173. rd_fifo_rd_req <= rd_fifo_rd_req ;
    174. end
    175. initial begin
    176. sys_clk_50Mhz = 1'b1 ;
    177. sys_rst_n <= 1'b0 ;
    178. rx <= 1'b1 ;
    179. #(CYCLE) ;
    180. sys_rst_n <= 1'b1 ;
    181. #( CYCLE * 100 ) ;
    182. rx_bit(8'b1) ;
    183. rx_bit(8'd2) ;
    184. rx_bit(8'd3) ;
    185. rx_bit(8'd4) ;
    186. rx_bit(8'd5) ;
    187. rx_bit(8'd6) ;
    188. rx_bit(8'd7) ;
    189. rx_bit(8'd8) ;
    190. rx_bit(8'd9) ;
    191. rx_bit(8'd10) ;
    192. end
    193. always #(CYCLE / 2) sys_clk_50Mhz = ~sys_clk_50Mhz ;
    194. endmodule

    top: 

    对下列模块进行例化。

     代码:

    1. module top(
    2. input wire sys_clk ,
    3. input wire sys_rst_n ,
    4. input wire rx ,
    5. output wire tx ,
    6. output wire sdram_cke ,
    7. output wire sdram_sck ,
    8. output wire sdram_csn ,
    9. output wire sdram_ras ,
    10. output wire sdram_cas ,
    11. output wire sdram_wen ,
    12. output wire [1:0] sdram_bank ,
    13. output wire [12:0] sdram_addr ,
    14. inout wire [15:0] sdram_dq ,
    15. output wire [1:0] sdram_dqm
    16. );
    17. // 例化间连线
    18. wire clk_50Mhz ;
    19. wire clk_100Mhz ;
    20. wire clk_100Mhz_shift;
    21. wire rst_n ;
    22. wire po_flag ;
    23. wire [7:0] po_data ;
    24. wire read_en ;
    25. wire [7:0] tx_data ;
    26. wire tx_flag ;
    27. wire [15:0] rd_fifo_rd_data ;
    28. wire [9:0] rd_fifo_num ;
    29. wire data_over ;
    30. // 例化
    31. clk_gen clk_gen_inst(
    32. .areset ( ~sys_rst_n ) ,
    33. .inclk0 ( sys_clk ) ,
    34. .c0 ( clk_50Mhz ) ,
    35. .c1 ( clk_100Mhz ) ,
    36. .c2 ( clk_100Mhz_shift ) ,
    37. .locked ( rst_n )
    38. );
    39. uart_rx uart_rx_inst(
    40. .sys_clk ( clk_50Mhz ) ,
    41. .sys_rst_n ( rst_n ) ,
    42. .rx ( rx ) ,
    43. .po_flag ( po_flag ) ,
    44. .po_data ( po_data )
    45. );
    46. sdram_top sdram_top_inst(
    47. .clk_50Mhz ( clk_50Mhz ) ,
    48. .clk_100Mhz ( clk_100Mhz ) ,
    49. .clk_shift ( clk_100Mhz_shift ) ,
    50. .sys_rst_n ( rst_n ) ,
    51. .wr_fifo_wr_req ( po_flag ) ,
    52. .wr_fifo_wr_data ( {8'd0,po_data} ) ,
    53. .sdram_wr_b_addr ( 24'd0 ) ,
    54. .sdram_wr_e_addr ( 24'd10 ) ,
    55. .wr_rst ( ~rst_n ) ,
    56. .wr_bust_len ( 10'd10 ) ,
    57. .rd_fifo_b_addr ( 24'd0 ) ,
    58. .rd_fifo_e_addr ( 24'd10 ) ,
    59. .rd_rst ( ~rst_n ) ,
    60. .rd_bust_len ( 10'd10 ) ,
    61. .rd_valid ( 1'b1 ) ,
    62. .rd_fifo_rd_req ( read_en ) ,
    63. .rd_fifo_rd_data ( rd_fifo_rd_data ) ,
    64. .rd_fifo_num ( rd_fifo_num ) ,
    65. .sdram_cke ( sdram_cke ) ,
    66. .sdram_sck ( sdram_sck ) ,
    67. .sdram_csn ( sdram_csn ) ,
    68. .sdram_ras ( sdram_ras ) ,
    69. .sdram_cas ( sdram_cas ) ,
    70. .sdram_wen ( sdram_wen ) ,
    71. .sdram_bank ( sdram_bank ) ,
    72. .sdram_addr ( sdram_addr ) ,
    73. .sdram_dq ( sdram_dq ) ,
    74. .sdram_dqm ( sdram_dqm )
    75. );
    76. fifo_read fifo_read_inst(
    77. .sys_clk ( clk_50Mhz ) ,
    78. .sys_rst_n ( rst_n ) ,
    79. .rd_fifo_rd_data ( rd_fifo_rd_data[7:0] ) ,
    80. .rd_fifo_num ( rd_fifo_num ) ,
    81. .bust_num ( 10'd10 ) ,
    82. .data_over ( data_over ) ,
    83. .read_en ( read_en ) ,
    84. .tx_data ( tx_data ) ,
    85. .tx_flag ( tx_flag )
    86. );
    87. uart_tx uart_tx_inst(
    88. .sys_clk ( clk_50Mhz ) ,
    89. .sys_rst_n ( rst_n ) ,
    90. .pi_data ( tx_data ) ,
    91. .pi_flag ( tx_flag ) ,
    92. .data_over ( data_over ) ,
    93. .tx ( tx )
    94. );
    95. endmodule

    仿真:

    1. `timescale 1ns/1ns
    2. module test_top();
    3. reg sys_clk_50Mhz ;
    4. reg sys_rst_n ;
    5. reg rx ;
    6. wire tx ;
    7. wire sdram_cke ;
    8. wire sdram_sck ;
    9. wire sdram_csn ;
    10. wire sdram_ras ;
    11. wire sdram_cas ;
    12. wire sdram_wen ;
    13. wire [1:0] sdram_bank ;
    14. wire [12:0] sdram_addr ;
    15. wire [15:0] sdram_dq ;
    16. wire [1:0] sdram_dqm ;
    17. top top_inst(
    18. .sys_clk ( sys_clk_50Mhz ) ,
    19. .sys_rst_n ( sys_rst_n ) ,
    20. .rx ( rx ) ,
    21. .tx ( tx ) ,
    22. .sdram_cke ( sdram_cke ) ,
    23. .sdram_sck ( sdram_sck ) ,
    24. .sdram_csn ( sdram_csn ) ,
    25. .sdram_ras ( sdram_ras ) ,
    26. .sdram_cas ( sdram_cas ) ,
    27. .sdram_wen ( sdram_wen ) ,
    28. .sdram_bank ( sdram_bank ) ,
    29. .sdram_addr ( sdram_addr ) ,
    30. .sdram_dq ( sdram_dq ) ,
    31. .sdram_dqm ( sdram_dqm )
    32. );
    33. sdram_model_plus sdram_model_plus_inst(
    34. .Dq ( sdram_dq ) ,
    35. .Addr ( sdram_addr ) ,
    36. .Ba ( sdram_bank ) ,
    37. .Clk ( sdram_sck ) ,
    38. .Cke ( sdram_cke ) ,
    39. .Cs_n ( sdram_csn ) ,
    40. .Ras_n ( sdram_ras ) ,
    41. .Cas_n ( sdram_cas ) ,
    42. .We_n ( sdram_wen ) ,
    43. .Dqm ( {2'b00,sdram_dqm} ) ,
    44. .Debug ( 1'b1 )
    45. );
    46. /******************************************************/
    47. parameter CYCLE = 20 ;
    48. defparam top_inst.uart_rx_inst.CLK_UART = 50_000_0 ;
    49. defparam top_inst.uart_tx_inst.CLK_UART = 50_000_0 ;
    50. defparam top_inst.uart_tx_inst.SUB_1K = 100 ;
    51. defparam top_inst.sdram_top_inst.sdram_ctrl_inst.sdram_aref_inst.MAX_CNT_750US = 200 ;
    52. defparam sdram_model_plus_inst.addr_bits = 13 ;
    53. defparam sdram_model_plus_inst.data_bits = 16 ;
    54. defparam sdram_model_plus_inst.col_bits = 9 ;
    55. defparam sdram_model_plus_inst.mem_sizes = 2*1024*1024 ;
    56. // rx
    57. task rx_bit ;
    58. input [7:0] data ;
    59. integer i ;
    60. for (i = 0;i <= 9 ;i = i + 1 ) begin
    61. case (i)
    62. 0: rx <= 1'b0 ;
    63. 1: rx <= data[i - 1];
    64. 2: rx <= data[i - 1];
    65. 3: rx <= data[i - 1];
    66. 4: rx <= data[i - 1];
    67. 5: rx <= data[i - 1];
    68. 6: rx <= data[i - 1];
    69. 7: rx <= data[i - 1];
    70. 8: rx <= data[i - 1];
    71. 9: rx <= 1'b1 ;
    72. default: rx <= 1'b1 ;
    73. endcase
    74. #(CYCLE * 52) ;
    75. end
    76. endtask
    77. initial begin
    78. sys_clk_50Mhz = 1'b1 ;
    79. sys_rst_n <= 1'b0 ;
    80. rx <= 1'b1 ;
    81. #(CYCLE) ;
    82. sys_rst_n <= 1'b1 ;
    83. #( CYCLE * 100 ) ;
    84. rx_bit(8'b1) ;
    85. rx_bit(8'd2) ;
    86. rx_bit(8'd3) ;
    87. rx_bit(8'd4) ;
    88. rx_bit(8'd5) ;
    89. rx_bit(8'd6) ;
    90. rx_bit(8'd7) ;
    91. rx_bit(8'd8) ;
    92. rx_bit(8'd9) ;
    93. rx_bit(8'd10) ;
    94. end
    95. always #(CYCLE / 2) sys_clk_50Mhz = ~sys_clk_50Mhz ;
    96. endmodule

    上板验证: 

  • 相关阅读:
    【语音识别入门】My-Voice-Analysis
    3D游戏角色动画
    vue的双向绑定的原理,和angular的对比
    springboot使用mybatis
    ubuntu上安装edge浏览器
    机房环境监控什么意思?机房环境监控系统作用
    mediakit 源码 轻微微 学习总结
    vue3 事件 emit 使用
    非零基础自学Java (老师:韩顺平) 第4章 运算符 4.21 二进制转八进制等 && 4.27 原码、反码、补码 && 4.28 位运算符
    【Java】如何将二进制转换成MultipartFile
  • 原文地址:https://blog.csdn.net/Meng_long2022/article/details/133965524