赞
踩
本项目用Verilog HDL语言设计了AHB总线上的SRAM控制器,SRAM存储器在AHB总线上作为AHB slave存在,该SRAM控制器具有以下特性:
支持单周期的SRAM读写操作
支持低功耗工作
SRAM存储体由两个Bank组成,系统根据地址选中一块/多块Bank,未被选中的Bank将处于low-power standby模式以降低功耗
支持DFT功能
DFT(Design for Test,可测性设计),指通过在芯片原始设计中插入各种用于提高芯片可测试性(包括可控制性和可观测性)的硬件逻辑,从而使芯片变得容易测试,大幅度节省芯片测试的成本。
本项目中,DFT功能通过BIST(Build-in Self Test,内建自测试)实现,采用March C-作为检测算法
最后,在Vivado平台上对本项目进行了逻辑仿真与验证
下面给出本项目的顶层设计架构,其中sram_top为顶层模块,其下包含sram_interface模块以及SRAM_core两个子模块
sram_interface模块:本质是AHB总线上的slave接口,起到连接总线与SRAM存储体的作用,具体来说:
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功能设计将在第二章中进行介绍
AHB总线时序:
其中来自AHB总线的control信号包括HTRANS,HBURST,HWRITE
SRAM接口时序:
写时序:
读时序:
读时序与写时序的区别主要在于SRAM_ADDR的处理上:
对于写操作,为了将地址与数据对齐,sram_interface模块会将总线上的地址与控制信号写入寄存器,
而对于读操作,为了实现总线上的单周期读出,会直接将地址送到SRAM端口(注意:SRAM的时钟为AHB总线时钟信号HCLK)。这样,在数据周期刚开始时,读数据就可以返回HRDATA,
这样的设计具有一些局限性:由于SRAM端口上的读地址相比于写地址要滞后一个周期,因此当写操作的下一个周期切换为读操作时,会产生地址冲突,
于是,SRAM控制器会将HREADY拉低一个周期,进行缓冲,下一个周期才会重新拉高HREADY并且返回相应的读数据,
在连续执行多个读操作/连续执行多个写操作时,则不会有这样的问题,可以以AHB总线所允许的最高的速度进行SRAM读写访问,
由于在实际应用中,存储器访问一般不会频繁地在读与写之间切换,因此这样设计对于访问速度带来的代价并不大,
而这样设计的好处,则在于可以避免为SRAM引入额外的时钟源
首先是顶层模块,主要内容是对两个子模块进行了例化,其中涉及到的信号均已经在架构图中标明,这里不再赘述
- module sram_top (
-
- // AHB Signal
- input HCLK,
- input HRESETn,
- input HSEL ,
- input [1:0] HTRANS,
- input [2:0] HBURST,
- input [2:0] HSIZE ,
- input HWRITE,
- input [15:0] HADDR ,
- input [31:0] HWDATA,
- output HREADY,
- output [1:0] HRESP ,
- output [31:0] HRDATA,
-
- // DFT Signal
- input BIST_en ,
- output BIST_done ,
- output BIST_fail
-
- );
-
- // Wires Between SRAM_interface and SRAM_core
- wire SRAM_WEN_BANK0;
- wire SRAM_WEN_BANK1;
- wire [12:0] SRAM_ADDR ;
- wire [3:0] SRAM_CSN_BANK0;
- wire [3:0] SRAM_CSN_BANK1;
- wire [31:0] SRAM_WDATA ;
-
- wire [7:0] SRAM0_q;
- wire [7:0] SRAM1_q;
- wire [7:0] SRAM2_q;
- wire [7:0] SRAM3_q;
- wire [7:0] SRAM4_q;
- wire [7:0] SRAM5_q;
- wire [7:0] SRAM6_q;
- wire [7:0] SRAM7_q;
-
- /*————————————————————————————————————————————————————————————————————————*\
- / SRAM Interface Instantiation \
- \*————————————————————————————————————————————————————————————————————————*/
- sram_interface u_interface(
-
- //---------------AHB SIGNAL--------------
- //in
- .iHCLK (HCLK ),
- .iHRESETn(HRESETn),
- .iHSEL (HSEL ),
- .iHBURST (HBURST ),
- .iHWRITE (HWRITE ),
- .iHTRANS (HTRANS ),
- .iHSIZE (HSIZE ),
- .iHWDATA (HWDATA ),
- .iHADDR (HADDR ),
- //out
- .oHRESP (HRESP ),
- .oHREADY (HREADY ),
- .oHRDATA (HRDATA ),
-
- //--------------SRAM SIGNAL--------------
- //in
- .iSRAM0_q(SRAM0_q),
- .iSRAM1_q(SRAM1_q),
- .iSRAM2_q(SRAM2_q),
- .iSRAM3_q(SRAM3_q),
- .iSRAM4_q(SRAM4_q),
- .iSRAM5_q(SRAM5_q),
- .iSRAM6_q(SRAM6_q),
- .iSRAM7_q(SRAM7_q),
- //out
- .oSRAM_CLK (SRAM_CLK ),
- .oSRAM_WEN_BANK0(SRAM_WEN_BANK0),
- .oSRAM_WEN_BANK1(SRAM_WEN_BANK1),
- .oSRAM_CSN_BANK0(SRAM_CSN_BANK0),
- .oSRAM_CSN_BANK1(SRAM_CSN_BANK1),
- .oSRAM_ADDR (SRAM_ADDR),
- .oSRAM_WDATA (SRAM_WDATA)
-
- );
- /*————————————————————————————————————————————————————————————————————————*\
- / SRAM Core Instantiation \
- \*————————————————————————————————————————————————————————————————————————*/
- sram_core u_core(
- //----------- From AHB ------------
- .iHCLK (HCLK ),
- .iHRESETn (HRESETn),
- //--------- From Interface ---------
- .iSRAM_WEN_BANK0 (SRAM_WEN_BANK0),
- .iSRAM_WEN_BANK1(SRAM_WEN_BANK1),
- .iSRAM_ADDR (SRAM_ADDR ),
- .iSRAM_CSN_BANK0(SRAM_CSN_BANK0),
- .iSRAM_CSN_BANK1(SRAM_CSN_BANK1),
- .iSRAM_WDATA (SRAM_WDATA ),
- //---------- To Interface ---------
- .oSRAM0_q (SRAM0_q),
- .oSRAM1_q (SRAM1_q),
- .oSRAM2_q (SRAM2_q),
- .oSRAM3_q (SRAM3_q),
- .oSRAM4_q (SRAM4_q),
- .oSRAM5_q (SRAM5_q),
- .oSRAM6_q (SRAM6_q),
- .oSRAM7_q (SRAM7_q),
- //-------------- DFT --------------
- .iBIST_en (BIST_en ),
- .oBIST_done (BIST_done),
- .oBIST_fail (BIST_fail)
- );
-
- endmodule
-
其次是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的地址端口:
- wire [12:0] SRAM_ADDR_write;
-
- wire [12:0] SRAM_ADDR_read;
-
- assign SRAM_ADDR_write = iHADDR_r[14:2]; // WRITE:addr have to wait a T , sent together
- //with data to SRAM_CORE
-
- assign SRAM_ADDR_read = iHADDR [14:2]; // READ :addr send to MEM at once
-
- 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代码如下:
- module sram_interface (
- //---------------AHB SIGNAL--------------
- //in
- input iHCLK ,
- input iHRESETn,
- input iHSEL ,
- input iHWRITE ,
- input [2:0] iHBURST ,
- input [1:0] iHTRANS ,
- input [2:0] iHSIZE ,
- input [31:0] iHWDATA ,
- input [15:0] iHADDR ,
- //out
- output [1:0] oHRESP ,
- output oHREADY ,
- output [31:0] oHRDATA ,
-
- //--------------SRAM SIGNAL--------------
- //in
- input [7:0] iSRAM0_q,
- input [7:0] iSRAM1_q,
- input [7:0] iSRAM2_q,
- input [7:0] iSRAM3_q,
- input [7:0] iSRAM4_q,
- input [7:0] iSRAM5_q,
- input [7:0] iSRAM6_q,
- input [7:0] iSRAM7_q,
- //out
- output oSRAM_CLK,
- output oSRAM_WEN_BANK0,
- output oSRAM_WEN_BANK1,
- output [3:0] oSRAM_CSN_BANK0,
- output [3:0] oSRAM_CSN_BANK1,
- output [12:0] oSRAM_ADDR,
- output [31:0] oSRAM_WDATA
-
- );
-
- /*————————————————————————————————————————————————————————————————————————*\
- / AHB Signal Register \
- \*————————————————————————————————————————————————————————————————————————*/
- reg iHSEL_r ;
- reg iHWRITE_r ;
- reg iHWRITE_2r;
- reg [2:0] iHBURST_r ;
- reg [1:0] iHTRANS_r ;
- reg [2:0] iHSIZE_r ;
- reg [31:0] iHWDATA_r ;
- reg [15:0] iHADDR_r ;
- reg [15:0] iHADDR_2r ;
-
- always@( posedge iHCLK) begin
- if(!iHRESETn) begin
- iHSEL_r <= 1'b0;
- iHWRITE_r <= 1'b0;
- iHWRITE_2r <= 1'b0;
- iHBURST_r <= 3'b0;
- iHTRANS_r <= 2'b0;
- iHSIZE_r <= 3'b0;
- iHWDATA_r <= 32'b0;
- iHADDR_r <= 16'b0;
- iHADDR_2r <= 16'b0;
- end
- else begin
- iHSEL_r <= iHSEL;
- iHWRITE_r <= iHWRITE;
- iHWRITE_2r <= iHWRITE_r;
- iHBURST_r <= iHBURST;
- iHTRANS_r <= iHTRANS;
- iHSIZE_r <= iHSIZE;
- iHWDATA_r <= iHWDATA;
- iHADDR_r <= iHADDR;
- iHADDR_2r <= iHADDR_r;
- end
- end
- /*————————————————————————————————————————————————————————————————————————*\
- / AHB BUS → Interface → SRAM Core \
- \*————————————————————————————————————————————————————————————————————————*/
- // SRAM Write Enable
- assign oSRAM_WEN_BANK0 = ( iHWRITE_r == 1'b1 && iHADDR_r[15] == 1'b0) ? 1'b1 : 1'b0;
- assign oSRAM_WEN_BANK1 = ( iHWRITE_r == 1'b1 && iHADDR_r[15] == 1'b1) ? 1'b1 : 1'b0;
- // SRAM Bank CSN select for read ↓ select for write ↓
- assign oSRAM_CSN_BANK0 = ( iHADDR_r[15] == 1'b0 || (iHADDR[15] == 1'b0 && iHWRITE == 1'b0) ) ? 4'b1111 : 4'b0000;
- assign oSRAM_CSN_BANK1 = ( iHADDR_r[15] == 1'b1 || (iHADDR[15] == 1'b1 && iHWRITE == 1'b0) ) ? 4'b1111 : 4'b0000;
- // SRAM Addr
- wire [12:0] SRAM_WRITE_ADDR;
- wire [12:0] SRAM_READ_ADDR;
- assign SRAM_WRITE_ADDR = iHADDR_r[14:2]; // WRITE:addr have to wait a T , sent together with data to SRAM_CORE
- assign SRAM_READ_ADDR = iHADDR [14:2]; // READ :addr send to MEM at once
- assign oSRAM_ADDR = (iHWRITE_r == 1'b1) ? SRAM_WRITE_ADDR : SRAM_READ_ADDR;
-
- // SRAM Write Data
- assign oSRAM_WDATA = iHWDATA;
-
- /*————————————————————————————————————————————————————————————————————————*\
- / AHB BUS ← Interface ← SRAM Core \
- \*————————————————————————————————————————————————————————————————————————*/
- // response to AHB MASTER
- assign oHREADY = (iHSEL_r == 1'b1 && (iHWRITE_r == 1'b1 || iHWRITE_2r == 1'b0)) ? 1'b1 : 1'b0 ;
- assign oHRESP = (iHSEL_r == 1'b1) ? 2'b00 : 2'b00; //OKAY = 2'b00
-
- // sram read data
- assign oHRDATA = (iHSEL_r == 1'b1 && iHWRITE_r == 1'b0 && iHADDR_r[15] == 1'b0) ? {iSRAM3_q, iSRAM2_q, iSRAM1_q, iSRAM0_q}:
- (iHSEL_r == 1'b1 && iHWRITE_r == 1'b0 && iHADDR_r[15] == 1'b1) ? {iSRAM7_q, iSRAM6_q, iSRAM5_q, iSRAM4_q}:
- 32'bz;
-
- endmodule
-
接下来是顶层模块下的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代码如下:
- module sram_core (
-
- // From AHB
- input iHCLK ,
- input iHRESETn,
-
- // From sram_interface
- input iSRAM_WEN_BANK0,
- input iSRAM_WEN_BANK1,
- input [12:0] iSRAM_ADDR ,
- input [3:0] iSRAM_CSN_BANK0,
- input [3:0] iSRAM_CSN_BANK1,
- input [31:0] iSRAM_WDATA ,
-
- // To sram_interface
- output [7:0] oSRAM0_q,
- output [7:0] oSRAM1_q,
- output [7:0] oSRAM2_q,
- output [7:0] oSRAM3_q,
- output [7:0] oSRAM4_q,
- output [7:0] oSRAM5_q,
- output [7:0] oSRAM6_q,
- output [7:0] oSRAM7_q,
-
- // BIST Signals
- input iBIST_en,
- output oBIST_done,
- output oBIST_fail
-
- );
-
- /*————————————————————————————————————————————————————————————————————————*\
- / BIST Ouput Logic \
- \*————————————————————————————————————————————————————————————————————————*/
- wire BIST_done_0;
- assign oBIST_done = BIST_done_0 && BIST_done_1 && BIST_done_2 && BIST_done_3
- && BIST_done_4 && BIST_done_5 && BIST_done_6 && BIST_done_7; // done if every sram_bist dones
-
- assign oBIST_fail = BIST_done_0 || BIST_done_1 || BIST_done_2 || BIST_done_3
- || BIST_done_4 || BIST_done_5 || BIST_done_6 || BIST_done_7; // fail if any sram_bist fails
-
- /*————————————————————————————————————————————————————————————————————————*\
- / BANK 0 Instantiation \
- \*————————————————————————————————————————————————————————————————————————*/
- sram_bist u_bank0_sram0 (
- // Function Mode IO
- .iSRAM_CLK (iHCLK ),
- .iSRAM_CSN (iSRAM_CSN_BANK0[0]),
- .iSRAM_WEN (iSRAM_WEN_BANK0 ),
- .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
- .iSRAM_WDATA(iSRAM_WDATA[7:0] ),
- .oSRAM_RDATA(oSRAM0_q ),
- // Test Mode IO
- .iBIST_en (iBIST_en ),
- .oBIST_done (BIST_done_0 ),
- .oBIST_fail (BIST_fail_0 )
- );
- sram_bist u_bank0_sram1 (
- // Function Mode IO
- .iSRAM_CLK (iHCLK ),
- .iSRAM_CSN (iSRAM_CSN_BANK0[1]),
- .iSRAM_WEN (iSRAM_WEN_BANK0 ),
- .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
- .iSRAM_WDATA(iSRAM_WDATA[15:8] ),
- .oSRAM_RDATA(oSRAM1_q ),
- // Test Mode IO
- .iBIST_en (iBIST_en ),
- .oBIST_done (BIST_done_1 ),
- .oBIST_fail (BIST_fail_1 )
- );
-
- sram_bist u_bank0_sram2 (
- // Function Mode IO
- .iSRAM_CLK (iHCLK ),
- .iSRAM_CSN (iSRAM_CSN_BANK0[2]),
- .iSRAM_WEN (iSRAM_WEN_BANK0 ),
- .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
- .iSRAM_WDATA(iSRAM_WDATA[23:16]),
- .oSRAM_RDATA(oSRAM2_q ),
- // Test Mode IO
- .iBIST_en (iBIST_en ),
- .oBIST_done (BIST_done_2 ),
- .oBIST_fail (BIST_fail_2 )
- );
- sram_bist u_bank0_sram3 (
- // Function Mode IO
- .iSRAM_CLK (iHCLK ),
- .iSRAM_CSN (iSRAM_CSN_BANK0[3]),
- .iSRAM_WEN (iSRAM_WEN_BANK0 ),
- .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
- .iSRAM_WDATA(iSRAM_WDATA[31:24]),
- .oSRAM_RDATA(oSRAM3_q ),
- // Test Mode IO
- .iBIST_en (iBIST_en ),
- .oBIST_done (BIST_done_3 ),
- .oBIST_fail (BIST_fail_3 )
- );
-
- /*————————————————————————————————————————————————————————————————————————*\
- / BANK 1 Instantiation \
- \*————————————————————————————————————————————————————————————————————————*/
- sram_bist u_bank1_sram4 (
- // Function Mode IO
- .iSRAM_CLK (iHCLK ),
- .iSRAM_CSN (iSRAM_CSN_BANK1[0]),
- .iSRAM_WEN (iSRAM_WEN_BANK1 ),
- .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
- .iSRAM_WDATA(iSRAM_WDATA[7:0] ),
- .oSRAM_RDATA(oSRAM4_q ),
- // Test Mode IO
- .iBIST_en (iBIST_en ),
- .oBIST_done (BIST_done_4 ),
- .oBIST_fail (BIST_fail_4 )
- );
- sram_bist u_bank1_sram5 (
- // Function Mode IO
- .iSRAM_CLK (iHCLK ),
- .iSRAM_CSN (iSRAM_CSN_BANK1[1]),
- .iSRAM_WEN (iSRAM_WEN_BANK1 ),
- .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
- .iSRAM_WDATA(iSRAM_WDATA[15:8] ),
- .oSRAM_RDATA(oSRAM5_q ),
- // Test Mode IO
- .iBIST_en (iBIST_en ),
- .oBIST_done (BIST_done_5 ),
- .oBIST_fail (BIST_fail_5 )
- );
-
- sram_bist u_bank1_sram6 (
- // Function Mode IO
- .iSRAM_CLK (iHCLK ),
- .iSRAM_CSN (iSRAM_CSN_BANK1[2]),
- .iSRAM_WEN (iSRAM_WEN_BANK1 ),
- .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
- .iSRAM_WDATA(iSRAM_WDATA[23:16]),
- .oSRAM_RDATA(oSRAM6_q ),
- // Test Mode IO
- .iBIST_en (iBIST_en ),
- .oBIST_done (BIST_done_6 ),
- .oBIST_fail (BIST_fail_6 )
- );
- sram_bist u_bank1_sram7 (
- // Function Mode IO
- .iSRAM_CLK (iHCLK ),
- .iSRAM_CSN (iSRAM_CSN_BANK1[3]),
- .iSRAM_WEN (iSRAM_WEN_BANK1 ),
- .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
- .iSRAM_WDATA(iSRAM_WDATA[31:24]),
- .oSRAM_RDATA(oSRAM7_q ),
- // Test Mode IO
- .iBIST_en (iBIST_en ),
- .oBIST_done (BIST_done_7 ),
- .oBIST_fail (BIST_fail_7 )
- );
-
- endmodule
在完成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控制器的设计逻辑是正确的
细心的读者们可能发现上述设计仅考虑了读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信号的生成变得更为复杂,
基于上述设计,读者们可以思考一下如何实现该功能,
以下给出参考设计:
- // SRAM Bank CSN
- wire [3:0] SRAM_CSN_BANK0_write;
- wire [3:0] SRAM_CSN_BANK0_read ;
- wire [3:0] SRAM_CSN_BANK1_write;
- wire [3:0] SRAM_CSN_BANK1_read ;
-
- always @(*) begin
- case( {iHADDR[15],iHSIZE} )
- //选中BANK0,HSIZE = Word
- 4'b0010:begin
- SRAM_CSN_BANK0_read <= 4'b1111;
- SRAM_CSN_BANK0_read <= 4'b0000;
- end
- //选中BANK1,HSIZE = Word
- 4'b1010:begin
- SRAM_CSN_BANK0_read <= 4'b0000;
- SRAM_CSN_BANK1_read <= 4'b1111;
- end
- //选中BANK0,HSIZE = Half Word
- 4'b0001:begin
- if(iHADDR[1]) begin
- SRAM_CSN_BANK0_read <= 4'b1100;
- SRAM_CSN_BANK1_read <= 4'b0000;
- end else begin
- SRAM_CSN_BANK0_read <= 4'b0011;
- SRAM_CSN_BANK1_read <= 4'b0000;
- end
- end
- //选中BANK1,HSIZE = Half Word
- 4'b1001:begin
- if(iHADDR[1]) begin
- SRAM_CSN_BANK0_read <= 4'b0000;
- SRAM_CSN_BANK1_read <= 4'b1100;
- end else begin
- SRAM_CSN_BANK0_read <= 4'b0000;
- SRAM_CSN_BANK1_read <= 4'b0011;
- end
- end
- //选中BANK0,HSIZE = BYTE
- 4'b0000:begin
- case (iHADDR[1:0])
- 2'b00: begin
- SRAM_CSN_BANK0_read <= 4'b0001;
- SRAM_CSN_BANK1_read <= 4'b0000;
- end
- 2'b01: begin
- SRAM_CSN_BANK0_read <= 4'b0010;
- SRAM_CSN_BANK1_read <= 4'b0000;
- end
- 2'b10: begin
- SRAM_CSN_BANK0_read <= 4'b0100;
- SRAM_CSN_BANK1_read <= 4'b0000;
- end
- 2'b11: begin
- SRAM_CSN_BANK0_read <= 4'b1000;
- SRAM_CSN_BANK1_read <= 4'b0000;
- end
- endcase
- end
- //选中BANK1,HSIZE = BYTE
- 4'b1000:begin
- case (iHADDR[1:0])
- 2'b00: begin
- SRAM_CSN_BANK0_read <= 4'b0000;
- SRAM_CSN_BANK1_read <= 4'b0001;
- end
- 2'b01: begin
- SRAM_CSN_BANK0_read <= 4'b0000;
- SRAM_CSN_BANK1_read <= 4'b0010;
- end
- 2'b10: begin
- SRAM_CSN_BANK0_read <= 4'b0000;
- SRAM_CSN_BANK1_read <= 4'b0100;
- end
- 2'b11: begin
- SRAM_CSN_BANK0_read <= 4'b0000;
- SRAM_CSN_BANK1_read <= 4'b1000;
- end
- endcase
- end
- endcase
- end
-
- always @(*) begin
- case( {iHADDR_r[15],iHSIZE_r} )
- //选中BANK0,HSIZE = Word
- 4'b0010:begin
- SRAM_CSN_BANK0_write <= 4'b1111;
- SRAM_CSN_BANK0_write <= 4'b0000;
- end
- //选中BANK1,HSIZE = Word
- 4'b1010:begin
- SRAM_CSN_BANK0_write <= 4'b0000;
- SRAM_CSN_BANK1_write <= 4'b1111;
- end
- //选中BANK0,HSIZE = Half Word
- 4'b0001:begin
- if(iHADDR_r[1]) begin
- SRAM_CSN_BANK0_write <= 4'b1100;
- SRAM_CSN_BANK1_write <= 4'b0000;
- end else begin
- SRAM_CSN_BANK0_write <= 4'b0011;
- SRAM_CSN_BANK1_write <= 4'b0000;
- end
- end
- //选中BANK1,HSIZE = Half Word
- 4'b1001:begin
- if(iHADDR_r[1]) begin
- SRAM_CSN_BANK0_write <= 4'b0000;
- SRAM_CSN_BANK1_write <= 4'b1100;
- end else begin
- SRAM_CSN_BANK0_write <= 4'b0000;
- SRAM_CSN_BANK1_write <= 4'b0011;
- end
- end
- //选中BANK0,HSIZE = BYTE
- 4'b0000:begin
- case (iHADDR_r[1:0])
- 2'b00: begin
- SRAM_CSN_BANK0_write <= 4'b0001;
- SRAM_CSN_BANK1_write <= 4'b0000;
- end
- 2'b01: begin
- SRAM_CSN_BANK0_write <= 4'b0010;
- SRAM_CSN_BANK1_write <= 4'b0000;
- end
- 2'b10: begin
- SRAM_CSN_BANK0_write <= 4'b0100;
- SRAM_CSN_BANK1_write <= 4'b0000;
- end
- 2'b11: begin
- SRAM_CSN_BANK0_write <= 4'b1000;
- SRAM_CSN_BANK1_write <= 4'b0000;
- end
- endcase
- end
- //选中BANK1,HSIZE = BYTE
- 4'b1000:begin
- case (iHADDR_r[1:0])
- 2'b00: begin
- SRAM_CSN_BANK0_write <= 4'b0000;
- SRAM_CSN_BANK1_write <= 4'b0001;
- end
- 2'b01: begin
- SRAM_CSN_BANK0_write <= 4'b0000;
- SRAM_CSN_BANK1_write <= 4'b0010;
- end
- 2'b10: begin
- SRAM_CSN_BANK0_write <= 4'b0000;
- SRAM_CSN_BANK1_write <= 4'b0100;
- end
- 2'b11: begin
- SRAM_CSN_BANK0_write <= 4'b0000;
- SRAM_CSN_BANK1_write <= 4'b1000;
- end
- endcase
- end
- endcase
- end
-
- assign oSRAM_CSN_BANK0 = (iHWRITE_r == 1'b1) ? SRAM_CSN_BANK0_write : SRAM_CSN_BANK0_read;
- 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来对两者进行选择
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。