【FPGA】双端口RAM的设计(同步读写)

举报
李锐博恩 发表于 2021/07/15 03:39:13 2021/07/15
【摘要】 之前的博文都是讲单端口RAM的,它们仅有一套控制输入,例如cs,we,oe,还有数据总线以及地址。 【FPGA】单端口RAM的设计(同步读、同步写) 附上太多链接,我也累,自己找吧。 双端口RAM,顾名思义,有两套地址,数据总线,以及cs等。 从输入输出也可以看出来: input clk       , // Clock Inpu...

之前的博文都是讲单端口RAM的,它们仅有一套控制输入,例如cs,we,oe,还有数据总线以及地址。

【FPGA】单端口RAM的设计(同步读、同步写)

附上太多链接,我也累,自己找吧。

双端口RAM,顾名思义,有两套地址,数据总线,以及cs等。

从输入输出也可以看出来:

input clk       , // Clock Input
input [ADDR_WIDTH - 1 : 0] address_0 , // address_0 Input
inout [data_0_WIDTH-1 : 0] data_0    , // data_0 bi-directional
input cs_0      , // Chip Select
input we_0      , // Write Enable/Read Enable
input oe_0      , // Output Enable
input [ADDR_WIDTH - 1 : 0] address_1 , // address_1 Input
inout [data_0_WIDTH-1 : 0] data_1    , // data_1 bi-directional
input cs_1      , // Chip Select
input we_1      , // Write Enable/Read Enable
input oe_1        // Output Enable

写部分:

//--------------Code Starts Here------------------ 
// Memory Write Block 
// Write Operation : When we_0 = 1, cs_0 = 1
always @ (posedge clk)
begin : MEM_WRITE
  if ( cs_0 && we_0 ) begin
     mem[address_0] <= data_0;
  end 
  else if (cs_1 && we_1) begin 
     mem[address_1] <= data_1;
  end
end

读部分:

// Tri-State Buffer control 
// output : When we_0 = 0, oe_0 = 1, cs_0 = 1
assign data_0 = (cs_0 && oe_0 && !we_0) ? data_0_out : 8'bz; 

// Memory Read Block 
// Read Operation : When we_0 = 0, oe_0 = 1, cs_0 = 1
always @ (posedge clk)
begin : MEM_READ_0
  if (cs_0 && !we_0 && oe_0) begin
    data_0_out <= mem[address_0]; 
  end 
  else begin
    data_0_out <= 0; 
  end  
end 

//Second Port of RAM
// Tri-State Buffer control 
// output : When we_0 = 0, oe_0 = 1, cs_0 = 1
assign data_1 = (cs_1 && oe_1 && !we_1) ? data_1_out : 8'bz; 
// Memory Read Block 1 
// Read Operation : When we_1 = 0, oe_1 = 1, cs_1 = 1
always @ (posedge clk)
begin : MEM_READ_1
  if (cs_1 && !we_1 && oe_1) begin
    data_1_out <= mem[address_1]; 
  end else begin
    data_1_out <= 0;
  end
end

可见,可以操作地址0以及地址1读写,因此可以实现同时读写操作。

如果对两套端口同时进行写操作,可见地址0优先,而读就不存在这种情况。(可不必考虑这句话!)

下面给出完整Verilog HDL设计代码:


  
  1. `timescale 1ns / 1ps
  2. //
  3. // Create Date: 2019/05/28 20:50:48
  4. // Design Name:
  5. // Module Name: ram_dp_sr_sw
  6. //
  7. module ram_dp_sr_sw #(
  8. parameter data_0_WIDTH = 8,
  9. parameter ADDR_WIDTH = 8,
  10. parameter RAM_DEPTH = 1 << ADDR_WIDTH
  11. )(
  12. input clk , // Clock Input
  13. input [ADDR_WIDTH - 1 : 0] address_0 , // address_0 Input
  14. inout [data_0_WIDTH-1 : 0] data_0 , // data_0 bi-directional
  15. input cs_0 , // Chip Select
  16. input we_0 , // Write Enable/Read Enable
  17. input oe_0 , // Output Enable
  18. input [ADDR_WIDTH - 1 : 0] address_1 , // address_1 Input
  19. inout [data_0_WIDTH-1 : 0] data_1 , // data_1 bi-directional
  20. input cs_1 , // Chip Select
  21. input we_1 , // Write Enable/Read Enable
  22. input oe_1 // Output Enable
  23. );
  24. //--------------Internal variables----------------
  25. reg [data_0_WIDTH-1:0] data_0_out ;
  26. reg [data_0_WIDTH-1:0] data_1_out ;
  27. reg [data_0_WIDTH-1:0] mem [0:RAM_DEPTH-1];
  28. //initialization
  29. // synopsys_translate_off
  30. integer i;
  31. initial begin
  32. for(i=0; i < RAM_DEPTH; i = i + 1) begin
  33. mem[i] = 8'h00;
  34. end
  35. end
  36. // synopsys_translate_on
  37. //--------------Code Starts Here------------------
  38. // Memory Write Block
  39. // Write Operation : When we_0 = 1, cs_0 = 1
  40. always @ (posedge clk)
  41. begin : MEM_WRITE
  42. if ( cs_0 && we_0 ) begin
  43. mem[address_0] <= data_0;
  44. end
  45. else if (cs_1 && we_1) begin
  46. mem[address_1] <= data_1;
  47. end
  48. end
  49. // Tri-State Buffer control
  50. // output : When we_0 = 0, oe_0 = 1, cs_0 = 1
  51. assign data_0 = (cs_0 && oe_0 && !we_0) ? data_0_out : 8'bz;
  52. // Memory Read Block
  53. // Read Operation : When we_0 = 0, oe_0 = 1, cs_0 = 1
  54. always @ (posedge clk)
  55. begin : MEM_READ_0
  56. if (cs_0 && !we_0 && oe_0) begin
  57. data_0_out <= mem[address_0];
  58. end
  59. else begin
  60. data_0_out <= 0;
  61. end
  62. end
  63. //Second Port of RAM
  64. // Tri-State Buffer control
  65. // output : When we_0 = 0, oe_0 = 1, cs_0 = 1
  66. assign data_1 = (cs_1 && oe_1 && !we_1) ? data_1_out : 8'bz;
  67. // Memory Read Block 1
  68. // Read Operation : When we_1 = 0, oe_1 = 1, cs_1 = 1
  69. always @ (posedge clk)
  70. begin : MEM_READ_1
  71. if (cs_1 && !we_1 && oe_1) begin
  72. data_1_out <= mem[address_1];
  73. end else begin
  74. data_1_out <= 0;
  75. end
  76. end
  77. endmodule // End of Module ram_dp_sr_sw

下面对此进行测试:

过程如下:

两个端口同时对RAM初值:

端口0写,同时端口1读:

两端口同时读:

可见,读出来的数据与时钟同步。

最后给出测试文件:


  
  1. `timescale 1ns / 1ps
  2. module ram_dp_sr_sw_tb;
  3. reg clk ; // Clock
  4. reg [7 : 0] address_0 ; // address_0 input
  5. wire [7 : 0] data_0 ; // data_0 bi-directional
  6. reg cs_0 ; // Chip Select
  7. reg we_0 ; // Write Enable/Read Enable
  8. reg oe_0 ; // Output Enable
  9. reg [7 : 0] address_1 ; // address_1 input
  10. wire [7 : 0] data_1 ; // data_1 bi-directional
  11. reg cs_1 ; // Chip Select
  12. reg we_1 ; // Write Enable/Read Enable
  13. reg oe_1 ; // Output Enable
  14. initial begin
  15. clk = 0;
  16. forever
  17. #2 clk = ~clk;
  18. end
  19. reg [7 : 0] data_in0; //写数据时候,双向总线与data_in0连接(这样做的目的是保证总线在某一时刻读和写,二者之一有效)
  20. assign data_0 = (cs_0 && we_0 && !oe_0) ? data_in0 : 8'dz;
  21. reg [7 : 0] data_in1; //写数据时候,双向总线与data_in1连接(这样做的目的是保证总线在某一时刻读和写,二者之一有效)
  22. assign data_1 = (cs_1 && we_1 && !oe_1) ? data_in1 : 8'dz;
  23. integer i = 0;
  24. initial begin
  25. oe_0 = 0;
  26. oe_1 = 0;
  27. we_0 = 0;
  28. we_1 = 0;
  29. cs_0 = 0;
  30. cs_1 = 0;
  31. address_0 = 0;
  32. address_1 = 0;
  33. data_in0 = 0;
  34. data_in1 = 0;
  35. //先读出初识值(两套地址一起读)
  36. #4
  37. cs_0 = 1;
  38. cs_1 = 1;
  39. oe_0 = 1;
  40. oe_1 = 1;
  41. for(i = 0; i < 256; i = i + 1) begin
  42. @(negedge clk) begin
  43. address_0 = i;
  44. address_1 = i;
  45. end
  46. end
  47. //地址0写,地址1读
  48. @(negedge clk) begin
  49. we_0 = 1;
  50. we_1 = 0;
  51. oe_0 = 0;
  52. oe_1 = 1;
  53. end
  54. for(i = 0; i < 256; i = i + 1) begin
  55. @(negedge clk) begin
  56. address_0 = i;
  57. data_in0 = data_in0 + 1;
  58. address_1 = i;
  59. end
  60. end
  61. //地址0读·,地址1读
  62. @(negedge clk) begin
  63. we_0 = 0;
  64. we_1 = 0;
  65. oe_0 = 1;
  66. oe_1 = 1;
  67. end
  68. for(i = 0; i < 256; i = i + 1) begin
  69. @(negedge clk) begin
  70. address_0 = i;
  71. address_1 = i;
  72. end
  73. end
  74. //结束吧,片选结束
  75. @(negedge clk) begin
  76. cs_0 = 0;
  77. cs_1 = 0;
  78. end
  79. #100 $stop;
  80. end
  81. ram_dp_sr_sw #(
  82. .ADDR_WIDTH(8), //给参数
  83. .data_0_WIDTH(8)
  84. ) u_ram(
  85. .clk(clk),
  86. .address_0(address_0),
  87. .data_0(data_0),
  88. .cs_0(cs_0),
  89. .we_0(we_0),
  90. .oe_0(oe_0),
  91. .address_1(address_1),
  92. .data_1(data_1),
  93. .cs_1(cs_1),
  94. .we_1(we_1),
  95. .oe_1(oe_1)
  96. );
  97. endmodule

参考链接:http://www.asic-world.com/examples/verilog/ram_dp_sr_sw.html

 

 

文章来源: reborn.blog.csdn.net,作者:李锐博恩,版权归原作者所有,如需转载,请联系作者。

原文链接:reborn.blog.csdn.net/article/details/90647784

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。