当前位置:   article > 正文

AHB SRAM控制器设计

ahb sram

本项目用Verilog HDL语言设计了AHB总线上的SRAM控制器,SRAM存储器在AHB总线上作为AHB slave存在,该SRAM控制器具有以下特性:

  1. 支持单周期的SRAM读写操作

  2. 支持低功耗工作
    SRAM存储体由两个Bank组成,系统根据地址选中一块/多块Bank,未被选中的Bank将处于low-power standby模式以降低功耗

  3. 支持DFT功能
    DFT(Design for Test,可测性设计),指通过在芯片原始设计中插入各种用于提高芯片可测试性(包括可控制性和可观测性)的硬件逻辑,从而使芯片变得容易测试,大幅度节省芯片测试的成本。
    本项目中,DFT功能通过BIST(Build-in Self Test,内建自测试)实现,采用March C-作为检测算法

最后,在Vivado平台上对本项目进行了逻辑仿真与验证

1. SRAM数据读写功能的实现

1.1 顶层设计架构

下面给出本项目的顶层设计架构,其中sram_top为顶层模块,其下包含sram_interface模块以及SRAM_core两个子模块

sram_interface模块:本质是AHB总线上的slave接口,起到连接总线与SRAM存储体的作用,具体来说:

  1. 将HCLK,HRESETn,HTRANS,HBURST,HWRITE,HWDATA这些来自于AHB总线的信号转化为存储器接口信号
  2. 接收存储器8位读数据SRAM_q,并根据总线给出的地址,整理成为32位HRDATA,然后返回给AHB总线

sram_core模块:包含两块32位SRAM存储体Bank,其中每块Bank包含4个8k×8的单端口SRAM,本项目中通过例化Vivado中的IP核生成,实际芯片生产应用中常通过Memory Compiler生成

sram_bist模块:使用SRAM读写功能时,可看做8k×8的单端口SRAM;当BIST功能被使能时,将会由sram_bist内部的内建自测试电路生成Pattern对SRAM进行DFT测试。在本项目中,BIST功能将基于March C-算法设计,具体将在本文的第二章中介绍。在第一章中,我们将每个sram_bist模块视为8k×8的单端口SRAM即可

在上图中标注出了模块的主要信号,其中红色、蓝色的信号分别代表了两个不同的数据通路

红色数据通路:正常使用SRAM读写功能时的信号,interface接收来自于AHB总线的信号,并将其转化为SRAM所需要的控制信号和写数据,然后再由interface将SRAM的读数据整理后返回AHB总线

蓝色数据通路:使用DFT功能时的信号。BIST_en = 1时,DFT功能被使能,此时红色信号全部被屏蔽。该功能用于芯片生产完毕之后,对每块芯片进行DFT测试以检测是否有生产故障,该数据通路对于SRAM的逻辑功能来说,属于冗余的部分,但是在实际芯片生产中却是必不可少的

在本章中,我们关注红色数据通路的电路设计,而DFT功能设计将在第二章中进行介绍

1.2 AHB SRAM读写时序

AHB总线时序

其中来自AHB总线的control信号包括HTRANS,HBURST,HWRITE

SRAM接口时序
写时序

读时序

读时序与写时序的区别主要在于SRAM_ADDR的处理上:

对于写操作,为了将地址与数据对齐,sram_interface模块会将总线上的地址与控制信号写入寄存器,

而对于读操作,为了实现总线上的单周期读出,会直接将地址送到SRAM端口(注意:SRAM的时钟为AHB总线时钟信号HCLK)。这样,在数据周期刚开始时,读数据就可以返回HRDATA,

这样的设计具有一些局限性:由于SRAM端口上的读地址相比于写地址要滞后一个周期,因此当写操作的下一个周期切换为读操作时,会产生地址冲突

于是,SRAM控制器会将HREADY拉低一个周期,进行缓冲,下一个周期才会重新拉高HREADY并且返回相应的读数据,

在连续执行多个读操作/连续执行多个写操作时,则不会有这样的问题,可以以AHB总线所允许的最高的速度进行SRAM读写访问,

由于在实际应用中,存储器访问一般不会频繁地在读与写之间切换,因此这样设计对于访问速度带来的代价并不大,

而这样设计的好处,则在于可以避免为SRAM引入额外的时钟源

在明确了AHB SRAM读写的设计需求和读写时序后,我们来看看具体的硬件电路是怎样用Verilog实现的:

1.3 sram_top

首先是顶层模块,主要内容是对两个子模块进行了例化,其中涉及到的信号均已经在架构图中标明,这里不再赘述

  1. module sram_top (
  2. // AHB Signal
  3. input HCLK,
  4. input HRESETn,
  5. input HSEL ,
  6. input [1:0] HTRANS,
  7. input [2:0] HBURST,
  8. input [2:0] HSIZE ,
  9. input HWRITE,
  10. input [15:0] HADDR ,
  11. input [31:0] HWDATA,
  12. output HREADY,
  13. output [1:0] HRESP ,
  14. output [31:0] HRDATA,
  15. // DFT Signal
  16. input BIST_en ,
  17. output BIST_done ,
  18. output BIST_fail
  19. );
  20. // Wires Between SRAM_interface and SRAM_core
  21. wire SRAM_WEN_BANK0;
  22. wire SRAM_WEN_BANK1;
  23. wire [12:0] SRAM_ADDR ;
  24. wire [3:0] SRAM_CSN_BANK0;
  25. wire [3:0] SRAM_CSN_BANK1;
  26. wire [31:0] SRAM_WDATA ;
  27. wire [7:0] SRAM0_q;
  28. wire [7:0] SRAM1_q;
  29. wire [7:0] SRAM2_q;
  30. wire [7:0] SRAM3_q;
  31. wire [7:0] SRAM4_q;
  32. wire [7:0] SRAM5_q;
  33. wire [7:0] SRAM6_q;
  34. wire [7:0] SRAM7_q;
  35. /*————————————————————————————————————————————————————————————————————————*\
  36. / SRAM Interface Instantiation \
  37. \*————————————————————————————————————————————————————————————————————————*/
  38. sram_interface u_interface(
  39. //---------------AHB SIGNAL--------------
  40. //in
  41. .iHCLK (HCLK ),
  42. .iHRESETn(HRESETn),
  43. .iHSEL (HSEL ),
  44. .iHBURST (HBURST ),
  45. .iHWRITE (HWRITE ),
  46. .iHTRANS (HTRANS ),
  47. .iHSIZE (HSIZE ),
  48. .iHWDATA (HWDATA ),
  49. .iHADDR (HADDR ),
  50. //out
  51. .oHRESP (HRESP ),
  52. .oHREADY (HREADY ),
  53. .oHRDATA (HRDATA ),
  54. //--------------SRAM SIGNAL--------------
  55. //in
  56. .iSRAM0_q(SRAM0_q),
  57. .iSRAM1_q(SRAM1_q),
  58. .iSRAM2_q(SRAM2_q),
  59. .iSRAM3_q(SRAM3_q),
  60. .iSRAM4_q(SRAM4_q),
  61. .iSRAM5_q(SRAM5_q),
  62. .iSRAM6_q(SRAM6_q),
  63. .iSRAM7_q(SRAM7_q),
  64. //out
  65. .oSRAM_CLK (SRAM_CLK ),
  66. .oSRAM_WEN_BANK0(SRAM_WEN_BANK0),
  67. .oSRAM_WEN_BANK1(SRAM_WEN_BANK1),
  68. .oSRAM_CSN_BANK0(SRAM_CSN_BANK0),
  69. .oSRAM_CSN_BANK1(SRAM_CSN_BANK1),
  70. .oSRAM_ADDR (SRAM_ADDR),
  71. .oSRAM_WDATA (SRAM_WDATA)
  72. );
  73. /*————————————————————————————————————————————————————————————————————————*\
  74. / SRAM Core Instantiation \
  75. \*————————————————————————————————————————————————————————————————————————*/
  76. sram_core u_core(
  77. //----------- From AHB ------------
  78. .iHCLK (HCLK ),
  79. .iHRESETn (HRESETn),
  80. //--------- From Interface ---------
  81. .iSRAM_WEN_BANK0 (SRAM_WEN_BANK0),
  82. .iSRAM_WEN_BANK1(SRAM_WEN_BANK1),
  83. .iSRAM_ADDR (SRAM_ADDR ),
  84. .iSRAM_CSN_BANK0(SRAM_CSN_BANK0),
  85. .iSRAM_CSN_BANK1(SRAM_CSN_BANK1),
  86. .iSRAM_WDATA (SRAM_WDATA ),
  87. //---------- To Interface ---------
  88. .oSRAM0_q (SRAM0_q),
  89. .oSRAM1_q (SRAM1_q),
  90. .oSRAM2_q (SRAM2_q),
  91. .oSRAM3_q (SRAM3_q),
  92. .oSRAM4_q (SRAM4_q),
  93. .oSRAM5_q (SRAM5_q),
  94. .oSRAM6_q (SRAM6_q),
  95. .oSRAM7_q (SRAM7_q),
  96. //-------------- DFT --------------
  97. .iBIST_en (BIST_en ),
  98. .oBIST_done (BIST_done),
  99. .oBIST_fail (BIST_fail)
  100. );
  101. endmodule

1.4 sram_interface

其次是sram_interface模块,该模块是本项目中重点模块之一,负责寄存AHB总线控制信号、AHB总线地址信号,

然后根据AHB信号对SRAM存储体进行读写访问,

那么SRAM的接口信号是如何生成的呢?

CLK:直接采用AHB总线时钟HCLK作为存储器时钟

CSN:片选,当地址对应BANK0时,sram0、sram1、sram2、sram3被选中,而sram3~sram7则对应BANK1。具体来说,当总线地址HADDR的值在0x0000—0x7FFF之间时地址指向BANK0,而在0x8000—0xFFFF之间时地址指向BANK1

注:8K *  4 = 32KB 是2^15, 所以是 0111 1111 1111 1111 , 【15:0】,16h'7FFF

WEN:写使能,当HWRITE = 1时,总线对SRAM发起write操作,WEN将被拉高;
当HWRITE = 0时,总线对SRAM发起read操作,WEN将被拉低,以保证读地址的数据不会被改写

ADDR:地址。

根据AHB SRAM读写时序中所介绍,当执行SRAM写操作时,interface模块会将存储器地址通过寄存器打一拍,然后在下一个周期和写数据一起送到相应的存储器端口上;

而执行SRAM读操作时,我们为了实现单周期读写,会直接将地址送到存储器端口,
这样,就可以在下个时钟上升沿顺利地拿到存储器返回的读数据,并送回AHB总线。

以上两种情况分别对应生成了SRAM_ADDR_write[12:0]SRAM_ADDR_read[12:0]两个地址信号,我们通过iHWRITE_r判断当前周期的任务是read还是write,由此决定将哪个地址作真正被送往SRAM的地址端口:

  1. wire [12:0] SRAM_ADDR_write;
  2. wire [12:0] SRAM_ADDR_read;
  3. assign SRAM_ADDR_write = iHADDR_r[14:2]; // WRITE:addr have to wait a T , sent together
  4. //with data to SRAM_CORE
  5. assign SRAM_ADDR_read = iHADDR [14:2]; // READ :addr send to MEM at once
  6. assign oSRAM_ADDR = (iHWRITE_r == 1'b1) ? SRAM_ADDR_write : SRAM_ADDR_read;

WDATA:SRAM写数据,来自于总线上的HWDATA[31:0],sram_interface将32位的HWDATA按照下图顺序分配给8位SRAM,作为SRAM的写数据SRAM_WDATA

q:SRAM读数据,每个被选中的sram_bist将返回一个8位数据,sram_interface会将每个Bank中的4个单Byte读数据,组合为一个完整的32位读数据,返回到总线上的HRDATA

HWDATA与SRAM_WDATA的对应关系,
HRDATA与SRAM_q的对应关系,
如下图所示(以Bank0为例):

sram_interface模块的RTL代码如下:

  1. module sram_interface (
  2. //---------------AHB SIGNAL--------------
  3. //in
  4. input iHCLK ,
  5. input iHRESETn,
  6. input iHSEL ,
  7. input iHWRITE ,
  8. input [2:0] iHBURST ,
  9. input [1:0] iHTRANS ,
  10. input [2:0] iHSIZE ,
  11. input [31:0] iHWDATA ,
  12. input [15:0] iHADDR ,
  13. //out
  14. output [1:0] oHRESP ,
  15. output oHREADY ,
  16. output [31:0] oHRDATA ,
  17. //--------------SRAM SIGNAL--------------
  18. //in
  19. input [7:0] iSRAM0_q,
  20. input [7:0] iSRAM1_q,
  21. input [7:0] iSRAM2_q,
  22. input [7:0] iSRAM3_q,
  23. input [7:0] iSRAM4_q,
  24. input [7:0] iSRAM5_q,
  25. input [7:0] iSRAM6_q,
  26. input [7:0] iSRAM7_q,
  27. //out
  28. output oSRAM_CLK,
  29. output oSRAM_WEN_BANK0,
  30. output oSRAM_WEN_BANK1,
  31. output [3:0] oSRAM_CSN_BANK0,
  32. output [3:0] oSRAM_CSN_BANK1,
  33. output [12:0] oSRAM_ADDR,
  34. output [31:0] oSRAM_WDATA
  35. );
  36. /*————————————————————————————————————————————————————————————————————————*\
  37. / AHB Signal Register \
  38. \*————————————————————————————————————————————————————————————————————————*/
  39. reg iHSEL_r ;
  40. reg iHWRITE_r ;
  41. reg iHWRITE_2r;
  42. reg [2:0] iHBURST_r ;
  43. reg [1:0] iHTRANS_r ;
  44. reg [2:0] iHSIZE_r ;
  45. reg [31:0] iHWDATA_r ;
  46. reg [15:0] iHADDR_r ;
  47. reg [15:0] iHADDR_2r ;
  48. always@( posedge iHCLK) begin
  49. if(!iHRESETn) begin
  50. iHSEL_r <= 1'b0;
  51. iHWRITE_r <= 1'b0;
  52. iHWRITE_2r <= 1'b0;
  53. iHBURST_r <= 3'b0;
  54. iHTRANS_r <= 2'b0;
  55. iHSIZE_r <= 3'b0;
  56. iHWDATA_r <= 32'b0;
  57. iHADDR_r <= 16'b0;
  58. iHADDR_2r <= 16'b0;
  59. end
  60. else begin
  61. iHSEL_r <= iHSEL;
  62. iHWRITE_r <= iHWRITE;
  63. iHWRITE_2r <= iHWRITE_r;
  64. iHBURST_r <= iHBURST;
  65. iHTRANS_r <= iHTRANS;
  66. iHSIZE_r <= iHSIZE;
  67. iHWDATA_r <= iHWDATA;
  68. iHADDR_r <= iHADDR;
  69. iHADDR_2r <= iHADDR_r;
  70. end
  71. end
  72. /*————————————————————————————————————————————————————————————————————————*\
  73. / AHB BUS → Interface → SRAM Core \
  74. \*————————————————————————————————————————————————————————————————————————*/
  75. // SRAM Write Enable
  76. assign oSRAM_WEN_BANK0 = ( iHWRITE_r == 1'b1 && iHADDR_r[15] == 1'b0) ? 1'b1 : 1'b0;
  77. assign oSRAM_WEN_BANK1 = ( iHWRITE_r == 1'b1 && iHADDR_r[15] == 1'b1) ? 1'b1 : 1'b0;
  78. // SRAM Bank CSN select for read ↓ select for write ↓
  79. assign oSRAM_CSN_BANK0 = ( iHADDR_r[15] == 1'b0 || (iHADDR[15] == 1'b0 && iHWRITE == 1'b0) ) ? 4'b1111 : 4'b0000;
  80. assign oSRAM_CSN_BANK1 = ( iHADDR_r[15] == 1'b1 || (iHADDR[15] == 1'b1 && iHWRITE == 1'b0) ) ? 4'b1111 : 4'b0000;
  81. // SRAM Addr
  82. wire [12:0] SRAM_WRITE_ADDR;
  83. wire [12:0] SRAM_READ_ADDR;
  84. assign SRAM_WRITE_ADDR = iHADDR_r[14:2]; // WRITE:addr have to wait a T , sent together with data to SRAM_CORE
  85. assign SRAM_READ_ADDR = iHADDR [14:2]; // READ :addr send to MEM at once
  86. assign oSRAM_ADDR = (iHWRITE_r == 1'b1) ? SRAM_WRITE_ADDR : SRAM_READ_ADDR;
  87. // SRAM Write Data
  88. assign oSRAM_WDATA = iHWDATA;
  89. /*————————————————————————————————————————————————————————————————————————*\
  90. / AHB BUS ← Interface ← SRAM Core \
  91. \*————————————————————————————————————————————————————————————————————————*/
  92. // response to AHB MASTER
  93. assign oHREADY = (iHSEL_r == 1'b1 && (iHWRITE_r == 1'b1 || iHWRITE_2r == 1'b0)) ? 1'b1 : 1'b0 ;
  94. assign oHRESP = (iHSEL_r == 1'b1) ? 2'b00 : 2'b00; //OKAY = 2'b00
  95. // sram read data
  96. assign oHRDATA = (iHSEL_r == 1'b1 && iHWRITE_r == 1'b0 && iHADDR_r[15] == 1'b0) ? {iSRAM3_q, iSRAM2_q, iSRAM1_q, iSRAM0_q}:
  97. (iHSEL_r == 1'b1 && iHWRITE_r == 1'b0 && iHADDR_r[15] == 1'b1) ? {iSRAM7_q, iSRAM6_q, iSRAM5_q, iSRAM4_q}:
  98. 32'bz;
  99. endmodule

1.5 sram_core

接下来是顶层模块下的sram_core,主要内容是将sram_bist模块进行了8次例化,

因此,sram_core实际上是将这8个SRAM拼成了一个16k×32的SRAM,

sram_core的地址共15位,地址范围为0x0000-0xFFFFF,

其中,Bank0对应0x0000-0x7FFFF;Bank1对应0x8000~0xFFFFF,

而每个sram_bist端口上的地址为sram_core上的地址右移两位得到,共13位,地址范围为0x0000~0x1FFF,

除此之外,sram_core将每个8k×8 SRAM的内建自测试的输出结果BIST_done_x,BIST_fail_x(x=0~7)进行了逻辑与/或以得到整块sram_core存储体的DFT测试结果,

在执行SRAM数据读写功能的时候,sram_bist可以看做8k×8的单端口SRAM。

sram_core模块的RTL代码如下:

  1. module sram_core (
  2. // From AHB
  3. input iHCLK ,
  4. input iHRESETn,
  5. // From sram_interface
  6. input iSRAM_WEN_BANK0,
  7. input iSRAM_WEN_BANK1,
  8. input [12:0] iSRAM_ADDR ,
  9. input [3:0] iSRAM_CSN_BANK0,
  10. input [3:0] iSRAM_CSN_BANK1,
  11. input [31:0] iSRAM_WDATA ,
  12. // To sram_interface
  13. output [7:0] oSRAM0_q,
  14. output [7:0] oSRAM1_q,
  15. output [7:0] oSRAM2_q,
  16. output [7:0] oSRAM3_q,
  17. output [7:0] oSRAM4_q,
  18. output [7:0] oSRAM5_q,
  19. output [7:0] oSRAM6_q,
  20. output [7:0] oSRAM7_q,
  21. // BIST Signals
  22. input iBIST_en,
  23. output oBIST_done,
  24. output oBIST_fail
  25. );
  26. /*————————————————————————————————————————————————————————————————————————*\
  27. / BIST Ouput Logic \
  28. \*————————————————————————————————————————————————————————————————————————*/
  29. wire BIST_done_0
  30. assign oBIST_done = BIST_done_0 && BIST_done_1 && BIST_done_2 && BIST_done_3
  31. && BIST_done_4 && BIST_done_5 && BIST_done_6 && BIST_done_7; // done if every sram_bist dones
  32. assign oBIST_fail = BIST_done_0 || BIST_done_1 || BIST_done_2 || BIST_done_3
  33. || BIST_done_4 || BIST_done_5 || BIST_done_6 || BIST_done_7; // fail if any sram_bist fails
  34. /*————————————————————————————————————————————————————————————————————————*\
  35. / BANK 0 Instantiation \
  36. \*————————————————————————————————————————————————————————————————————————*/
  37. sram_bist u_bank0_sram0 (
  38. // Function Mode IO
  39. .iSRAM_CLK (iHCLK ),
  40. .iSRAM_CSN (iSRAM_CSN_BANK0[0]),
  41. .iSRAM_WEN (iSRAM_WEN_BANK0 ),
  42. .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
  43. .iSRAM_WDATA(iSRAM_WDATA[7:0] ),
  44. .oSRAM_RDATA(oSRAM0_q ),
  45. // Test Mode IO
  46. .iBIST_en (iBIST_en ),
  47. .oBIST_done (BIST_done_0 ),
  48. .oBIST_fail (BIST_fail_0 )
  49. );
  50. sram_bist u_bank0_sram1 (
  51. // Function Mode IO
  52. .iSRAM_CLK (iHCLK ),
  53. .iSRAM_CSN (iSRAM_CSN_BANK0[1]),
  54. .iSRAM_WEN (iSRAM_WEN_BANK0 ),
  55. .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
  56. .iSRAM_WDATA(iSRAM_WDATA[15:8] ),
  57. .oSRAM_RDATA(oSRAM1_q ),
  58. // Test Mode IO
  59. .iBIST_en (iBIST_en ),
  60. .oBIST_done (BIST_done_1 ),
  61. .oBIST_fail (BIST_fail_1 )
  62. );
  63. sram_bist u_bank0_sram2 (
  64. // Function Mode IO
  65. .iSRAM_CLK (iHCLK ),
  66. .iSRAM_CSN (iSRAM_CSN_BANK0[2]),
  67. .iSRAM_WEN (iSRAM_WEN_BANK0 ),
  68. .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
  69. .iSRAM_WDATA(iSRAM_WDATA[23:16]),
  70. .oSRAM_RDATA(oSRAM2_q ),
  71. // Test Mode IO
  72. .iBIST_en (iBIST_en ),
  73. .oBIST_done (BIST_done_2 ),
  74. .oBIST_fail (BIST_fail_2 )
  75. );
  76. sram_bist u_bank0_sram3 (
  77. // Function Mode IO
  78. .iSRAM_CLK (iHCLK ),
  79. .iSRAM_CSN (iSRAM_CSN_BANK0[3]),
  80. .iSRAM_WEN (iSRAM_WEN_BANK0 ),
  81. .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
  82. .iSRAM_WDATA(iSRAM_WDATA[31:24]),
  83. .oSRAM_RDATA(oSRAM3_q ),
  84. // Test Mode IO
  85. .iBIST_en (iBIST_en ),
  86. .oBIST_done (BIST_done_3 ),
  87. .oBIST_fail (BIST_fail_3 )
  88. );
  89. /*————————————————————————————————————————————————————————————————————————*\
  90. / BANK 1 Instantiation \
  91. \*————————————————————————————————————————————————————————————————————————*/
  92. sram_bist u_bank1_sram4 (
  93. // Function Mode IO
  94. .iSRAM_CLK (iHCLK ),
  95. .iSRAM_CSN (iSRAM_CSN_BANK1[0]),
  96. .iSRAM_WEN (iSRAM_WEN_BANK1 ),
  97. .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
  98. .iSRAM_WDATA(iSRAM_WDATA[7:0] ),
  99. .oSRAM_RDATA(oSRAM4_q ),
  100. // Test Mode IO
  101. .iBIST_en (iBIST_en ),
  102. .oBIST_done (BIST_done_4 ),
  103. .oBIST_fail (BIST_fail_4 )
  104. );
  105. sram_bist u_bank1_sram5 (
  106. // Function Mode IO
  107. .iSRAM_CLK (iHCLK ),
  108. .iSRAM_CSN (iSRAM_CSN_BANK1[1]),
  109. .iSRAM_WEN (iSRAM_WEN_BANK1 ),
  110. .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
  111. .iSRAM_WDATA(iSRAM_WDATA[15:8] ),
  112. .oSRAM_RDATA(oSRAM5_q ),
  113. // Test Mode IO
  114. .iBIST_en (iBIST_en ),
  115. .oBIST_done (BIST_done_5 ),
  116. .oBIST_fail (BIST_fail_5 )
  117. );
  118. sram_bist u_bank1_sram6 (
  119. // Function Mode IO
  120. .iSRAM_CLK (iHCLK ),
  121. .iSRAM_CSN (iSRAM_CSN_BANK1[2]),
  122. .iSRAM_WEN (iSRAM_WEN_BANK1 ),
  123. .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
  124. .iSRAM_WDATA(iSRAM_WDATA[23:16]),
  125. .oSRAM_RDATA(oSRAM6_q ),
  126. // Test Mode IO
  127. .iBIST_en (iBIST_en ),
  128. .oBIST_done (BIST_done_6 ),
  129. .oBIST_fail (BIST_fail_6 )
  130. );
  131. sram_bist u_bank1_sram7 (
  132. // Function Mode IO
  133. .iSRAM_CLK (iHCLK ),
  134. .iSRAM_CSN (iSRAM_CSN_BANK1[3]),
  135. .iSRAM_WEN (iSRAM_WEN_BANK1 ),
  136. .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
  137. .iSRAM_WDATA(iSRAM_WDATA[31:24]),
  138. .oSRAM_RDATA(oSRAM7_q ),
  139. // Test Mode IO
  140. .iBIST_en (iBIST_en ),
  141. .oBIST_done (BIST_done_7 ),
  142. .oBIST_fail (BIST_fail_7 )
  143. );
  144. endmodule

1.6 SRAM读写功能的仿真验证

在完成RTL设计后,我们编写了Testbench,
并在Vivado平台上进行了简单的读写仿真验证,波形如下:

分析一下Testbench具体对SRAM发起了什么操作:

首先,T1-T7进行了六次写操作,将6个数据依次写入SRAM的0x0000,0x0004,0x0008,0x8000,0x8004,0x8008六个地址当中

其中前三个地址对应Bank0,后三个地址对应Bank1,

因此在T2-T4期间 SRAM_CSN_BANK0 和 SRAM_WEN_BANK0 被拉高,

在T5-T7期间 SRAM_CSN_BANK1 和 SRAM_WEN_BANK1 被拉高,

从上图中可以看出,T7除了是Data 6的写数据周期,也是Data 1 读地址周期,

但是由于SRAM端口上,该周期需要执行写Data 6的操作。

于是发生了地址冲突,无法在该周期同时进行读Data 1

因此,在T8并没有返回Data 1的读数据,HREADY被拉低,

随后,在T9-T14,总线上HRDATA依次拿到了六个SRAM读数据,读出的data与T1-T7写入的data完全一致,证明了以上SRAM控制器的设计逻辑是正确的

1.7 支持半字/字节读写

细心的读者们可能发现上述设计仅考虑了读SRAM按字进行读写的情况,

也就是每次读写都是32位的。

实际上,AHB协议同样支持我们以16位/8位的方式对SRAM进行访问,由HSIZE[2:0]控制,具体对应关系如下:

HSIZE[2:0] = 3'b000:按BYTE读写
HSIZE[2:0] = 3'b001:按Half Word读写
HSIZE[2:0] = 3'b010:按Word读写

支持半字/字节读写使得CSN信号的生成变得更为复杂,

基于上述设计,读者们可以思考一下如何实现该功能,

以下给出参考设计:

  1. // SRAM Bank CSN
  2. wire [3:0] SRAM_CSN_BANK0_write;
  3. wire [3:0] SRAM_CSN_BANK0_read ;
  4. wire [3:0] SRAM_CSN_BANK1_write;
  5. wire [3:0] SRAM_CSN_BANK1_read ;
  6. always @(*) begin
  7. case( {iHADDR[15],iHSIZE} )
  8. //选中BANK0,HSIZE = Word
  9. 4'b0010:begin
  10. SRAM_CSN_BANK0_read <= 4'b1111;
  11. SRAM_CSN_BANK0_read <= 4'b0000;
  12. end
  13. //选中BANK1,HSIZE = Word
  14. 4'b1010:begin
  15. SRAM_CSN_BANK0_read <= 4'b0000;
  16. SRAM_CSN_BANK1_read <= 4'b1111;
  17. end
  18. //选中BANK0,HSIZE = Half Word
  19. 4'b0001:begin
  20. if(iHADDR[1]) begin
  21. SRAM_CSN_BANK0_read <= 4'b1100;
  22. SRAM_CSN_BANK1_read <= 4'b0000;
  23. end else begin
  24. SRAM_CSN_BANK0_read <= 4'b0011;
  25. SRAM_CSN_BANK1_read <= 4'b0000;
  26. end
  27. end
  28. //选中BANK1,HSIZE = Half Word
  29. 4'b1001:begin
  30. if(iHADDR[1]) begin
  31. SRAM_CSN_BANK0_read <= 4'b0000;
  32. SRAM_CSN_BANK1_read <= 4'b1100;
  33. end else begin
  34. SRAM_CSN_BANK0_read <= 4'b0000;
  35. SRAM_CSN_BANK1_read <= 4'b0011;
  36. end
  37. end
  38. //选中BANK0,HSIZE = BYTE
  39. 4'b0000:begin
  40. case (iHADDR[1:0])
  41. 2'b00: begin
  42. SRAM_CSN_BANK0_read <= 4'b0001;
  43. SRAM_CSN_BANK1_read <= 4'b0000;
  44. end
  45. 2'b01: begin
  46. SRAM_CSN_BANK0_read <= 4'b0010;
  47. SRAM_CSN_BANK1_read <= 4'b0000;
  48. end
  49. 2'b10: begin
  50. SRAM_CSN_BANK0_read <= 4'b0100;
  51. SRAM_CSN_BANK1_read <= 4'b0000;
  52. end
  53. 2'b11: begin
  54. SRAM_CSN_BANK0_read <= 4'b1000;
  55. SRAM_CSN_BANK1_read <= 4'b0000;
  56. end
  57. endcase
  58. end
  59. //选中BANK1,HSIZE = BYTE
  60. 4'b1000:begin
  61. case (iHADDR[1:0])
  62. 2'b00: begin
  63. SRAM_CSN_BANK0_read <= 4'b0000;
  64. SRAM_CSN_BANK1_read <= 4'b0001;
  65. end
  66. 2'b01: begin
  67. SRAM_CSN_BANK0_read <= 4'b0000;
  68. SRAM_CSN_BANK1_read <= 4'b0010;
  69. end
  70. 2'b10: begin
  71. SRAM_CSN_BANK0_read <= 4'b0000;
  72. SRAM_CSN_BANK1_read <= 4'b0100;
  73. end
  74. 2'b11: begin
  75. SRAM_CSN_BANK0_read <= 4'b0000;
  76. SRAM_CSN_BANK1_read <= 4'b1000;
  77. end
  78. endcase
  79. end
  80. endcase
  81. end
  82. always @(*) begin
  83. case( {iHADDR_r[15],iHSIZE_r} )
  84. //选中BANK0,HSIZE = Word
  85. 4'b0010:begin
  86. SRAM_CSN_BANK0_write <= 4'b1111;
  87. SRAM_CSN_BANK0_write <= 4'b0000;
  88. end
  89. //选中BANK1,HSIZE = Word
  90. 4'b1010:begin
  91. SRAM_CSN_BANK0_write <= 4'b0000;
  92. SRAM_CSN_BANK1_write <= 4'b1111;
  93. end
  94. //选中BANK0,HSIZE = Half Word
  95. 4'b0001:begin
  96. if(iHADDR_r[1]) begin
  97. SRAM_CSN_BANK0_write <= 4'b1100;
  98. SRAM_CSN_BANK1_write <= 4'b0000;
  99. end else begin
  100. SRAM_CSN_BANK0_write <= 4'b0011;
  101. SRAM_CSN_BANK1_write <= 4'b0000;
  102. end
  103. end
  104. //选中BANK1,HSIZE = Half Word
  105. 4'b1001:begin
  106. if(iHADDR_r[1]) begin
  107. SRAM_CSN_BANK0_write <= 4'b0000;
  108. SRAM_CSN_BANK1_write <= 4'b1100;
  109. end else begin
  110. SRAM_CSN_BANK0_write <= 4'b0000;
  111. SRAM_CSN_BANK1_write <= 4'b0011;
  112. end
  113. end
  114. //选中BANK0,HSIZE = BYTE
  115. 4'b0000:begin
  116. case (iHADDR_r[1:0])
  117. 2'b00: begin
  118. SRAM_CSN_BANK0_write <= 4'b0001;
  119. SRAM_CSN_BANK1_write <= 4'b0000;
  120. end
  121. 2'b01: begin
  122. SRAM_CSN_BANK0_write <= 4'b0010;
  123. SRAM_CSN_BANK1_write <= 4'b0000;
  124. end
  125. 2'b10: begin
  126. SRAM_CSN_BANK0_write <= 4'b0100;
  127. SRAM_CSN_BANK1_write <= 4'b0000;
  128. end
  129. 2'b11: begin
  130. SRAM_CSN_BANK0_write <= 4'b1000;
  131. SRAM_CSN_BANK1_write <= 4'b0000;
  132. end
  133. endcase
  134. end
  135. //选中BANK1,HSIZE = BYTE
  136. 4'b1000:begin
  137. case (iHADDR_r[1:0])
  138. 2'b00: begin
  139. SRAM_CSN_BANK0_write <= 4'b0000;
  140. SRAM_CSN_BANK1_write <= 4'b0001;
  141. end
  142. 2'b01: begin
  143. SRAM_CSN_BANK0_write <= 4'b0000;
  144. SRAM_CSN_BANK1_write <= 4'b0010;
  145. end
  146. 2'b10: begin
  147. SRAM_CSN_BANK0_write <= 4'b0000;
  148. SRAM_CSN_BANK1_write <= 4'b0100;
  149. end
  150. 2'b11: begin
  151. SRAM_CSN_BANK0_write <= 4'b0000;
  152. SRAM_CSN_BANK1_write <= 4'b1000;
  153. end
  154. endcase
  155. end
  156. endcase
  157. end
  158. assign oSRAM_CSN_BANK0 = (iHWRITE_r == 1'b1) ? SRAM_CSN_BANK0_write : SRAM_CSN_BANK0_read;
  159. assign oSRAM_CSN_BANK1 = (iHWRITE_r == 1'b1) ? SRAM_CSN_BANK1_write : SRAM_CSN_BANK1_read;

可以看到,CSN信号的生成和ADDR类似,需要考虑因为读/写操作时序不同而带来的两种情况,

分别生成了SRAM_CSN_BANK0_write[3:0]SRAM_CSN_BANK0_read[3:0](BANK1同理),

最后通过iHWRITE_r来对两者进行选择

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/901895
推荐阅读
相关标签
  

闽ICP备14008679号