绪论

本项目用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引入额外的时钟源

1.3 RTL设计

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

sram_top

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

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 ),
    .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_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

其次是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

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

ADDR:地址。根据AHB SRAM读写时序中所介绍,
当执行SRAM写操作时,interface模块会将存储器地址通过寄存器打一拍,然后在下一个周期和写数据一起送到相应的存储器端口上
而执行SRAM读操作时,我们为了实现单周期读写,会直接将地址送到存储器端口。这样,就可以在下个时钟上升沿顺利地拿到存储器返回的读数据,并送回AHB总线

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 [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_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    
    
  ); 

  /*————————————————————————————————————————————————————————————————————————*
  /                         Register for AHB Signal                          
  *————————————————————————————————————————————————————————————————————————*/
  reg         iHSEL_r   ;
  reg         iHWRITE_r ;
  reg         iHWRITE_2r;
  reg  [2:0]  iHBURST_r ;
  reg  [1:0]  iHTRANS_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; 
      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; 
      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_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

1.4 SRAM读写仿真验证

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

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

首先,T1-T7进行了六次写操作,将6个数据依次写入SRAM的0x0000,0x0001,0x0002,0x8000,0x8001,0x8002六个地址当中

其中前三个地址对应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控制器的设计逻辑是正确的

2. 基于March C-算法的DFT功能

2.1 BIST架构

在设计中,SRAM读写模式和DFT模式的选择通过2选1选择器实现,当DFT模式的使能信号BIST_en = 1时,来自于sram_interface的所有信号逻辑将被忽略,

SRAM端口上的输入信号将全部来自于sram_bist内部的BIST控制电路生成的Pattern,

对于March C-算法,BIST控制电路会对SRAM每个地址进行“写 → 读 → 比较”的操作,

若所有的读数据结果与写入的数据是一致的,BIST_done最终将被拉高,说明该电路生产过程中没有出现生产故障,

反之,如果比较发现有错误,BIST_fail最终将被拉高,该块芯片将被报废,

在模块内加入DFT测试电路,虽然会增加系统的数字面积,但同时也极大地降低了产品在测试环节所花费的开销成本

2.2 SRAM常见故障

首先,介绍一些常见的存储器(比如SRAM)故障模型:

固定型故障(Stuck-At Faults,SAF):
存储单元中的值固定为0/1(简记为SA0/SA1),无法发生改变。固定型故障可以通过对待测单元写入0再读出0,然后写入1再读出1来进行检测。

跳变故障(Transition Faults,TF):
存储单元中的值无法从0跳变到1(简记为TF(0→1)),或者从1跳变到0(简记为TF(1→0)),需要通过写入1到0的跳变再读出0,然后写入0到1的跳变再读出1来进行检测

耦合故障(Coupling Faults,CF):
一个存储单元的值发生改变,导致另一个存储单元的值发生改变,可以通过先升序对所有存储单元进行写读操作,然后再降序对所有存储单元进行写读操作的方法进行故障检测

2.3 March C-算法

March C算法是目前应用最为广泛的MBIST(Memory Built-In-Self-Test,存储器内建自测试)算法,

March C算法对上文提到的SAF故障,TF故障,CF故障的故障覆盖率均达到100%,

March C算法的具体检测流程如下:

  1. 从最低地址开始,在整个存储器中依次写入0(升序)

  2. 读出最低地址,结果应为0,然后把1写入该存储单元。完成后地址+1,再次执行该操作,直至对整个存储器执行该操作(升序)

  3. 读出最高地址,结果应为1,然后把0写入该存储单元,再次读该单元,结果应为0。完成后地址-1,再次执行该操作,直至对整个存储器执行该操作(降序)

  4. 读出最高地址,结果应为0,然后把1写入该存储单元。完成后地址-1,再次执行该操作,直至对整个存储器执行该操作(降序)

  5. 读出最低地址,结果应为1,然后把0写入该存储单元,再次读该单元,结果应为0。完成后地址+1,再次执行该操作,直至对整个存储器执行该操作(升序)

由于步骤4,步骤5中,加粗字体所描述的操作实际上是重复的,

因此后来有了改进的March C-算法, 将步骤3中的加粗部分删除,如下:

图中,March C-所执行的全套操作被分成了5个部分,也就是MARCH_0~MARCH_ 4

这也是本项目的BIST功能在RTL设计中,March C-状态机所用到的5个状态的名称

2.4 Verilog实现March C-算法的BIST

本项目中,内建自测试逻辑电路位于每个sram_bist模块中,

BIST_en作为顶层模块的BIST使能信号,被直接接到每块bist的BIST_en输入使能端口,

依据March C-算法发起的SRAM读写操作,是由有限状态机控制的,该状态机示意图如下:

下面让我们来看看sram_bist模块的RTL代码:

module sram_bist #(

    //---------------    MARCH C-  --------------------//
    //   STATE            ACTION           DIRECTION
    // MARCH 0            write 0              ↑  
    // MARCH 1         read 0, write 1         ↑
    // MARCH 2         read 1, write 0         ↓
    // MARCH 3         read 0, write 1         ↓
    // MARCH 4         read 1, write 0         ↑        
    //-------------------------------------------------//
    
            // TEST_state parameters //            
        parameter MARCH_0 = 3'b000,        // 0
        parameter MARCH_1 = 3'b001,        // 1
        parameter MARCH_2 = 3'b010,        // 2
        parameter MARCH_3 = 3'b011,        // 3
        parameter MARCH_4 = 3'b100,        // 4
        parameter MARCH_finished = 3'b101, // 5

            // TEST_action parameters //
              
        parameter WRITE_0 = 2'b00,
        parameter READ_0  = 2'b01,
        parameter WRITE_1 = 2'b10,
        parameter READ_1  = 2'b11,

            // TEST_compare_result parameters //
                      
        parameter COMPARE_RIGHT  = 1'b1,
        parameter COMPARE_ERROR  = 1'b0

)(

    // Function Mode IO
    input         iSRAM_CLK  ,
    input         iSRAM_CSN  ,
    input         iSRAM_WEN  ,
    input  [12:0] iSRAM_ADDR ,
    input  [7:0]  iSRAM_WDATA,    
    output [7:0]  oSRAM_RDATA,

    // Test Mode IO
    input  iBIST_en   ,     
    output oBIST_done ,
    output oBIST_fail
);

    /*————————————————————————————————————————————————————————————————————————*
    /                                                                          
    /                     SRAM Normal Function Mode                            
    /                                                                          
    *————————————————————————————————————————————————————————————————————————*/

    // wire connected to sram's port
    wire SRAM_CLK  ;  
    wire SRAM_CSN  ;  
    wire SRAM_WEN  ;  
    wire [12:0] SRAM_ADDR ;  
    wire [7:0]  SRAM_WDATA;  
    wire [7:0]  SRAM_RDATA;  
    
    // TEST-FUN MUX
    assign SRAM_ADDR  = (iBIST_en == 1'b1) ? TEST_ADDR   :
                        (iBIST_en == 1'b0) ? iSRAM_ADDR  : 13'bz;
    
    assign SRAM_CSN   = (iBIST_en == 1'b1) ? 1'b1        :
                        (iBIST_en == 1'b0) ? iSRAM_CSN   : 1'bz;  
    
    
    assign SRAM_WDATA = (iBIST_en == 1'b1) ? TEST_WDATA     :
                        (iBIST_en == 1'b0) ? iSRAM_WDATA    : 8'bz;  

    assign SRAM_WEN   = (iBIST_en == 1'b1) ? TEST_SRAM_WEN  :
                        (iBIST_en == 1'b0) ? iSRAM_WEN      : 1'bz;                    
    
    assign oSRAM_RDATA = SRAM_RDATA;
       
    // IP instantiation
    RAM_8K_8 u_bt_sram (
        .clka  (iSRAM_CLK   ),// HCLK → SRAM_CLK
        .ena   (SRAM_CSN    ),// csn → ena
        .wea   (SRAM_WEN    ),// 
        .addra (SRAM_ADDR   ),// unite addr
        .dina  (SRAM_WDATA  ),// input data
        .douta (SRAM_RDATA  ) // output data
    );
    
    /*————————————————————————————————————————————————————————————————————————*
    /                                                                          
    /                   BIST (Build-in Self Test)                            
    /                                                                          
    *————————————————————————————————————————————————————————————————————————*/

    // BIST CLOCK Generation   
    wire   BIST_CLK;
    assign BIST_CLK = ( iBIST_en == 1'b1) ? iSRAM_CLK : 1'b0;

    // BIST RESET Generation
    reg  iBIST_en_r;
    reg  iBIST_en_2r;
    wire TEST_RESET;    
    always @( posedge BIST_CLK) begin
        if(iBIST_en && iBIST_en_r) begin
            iBIST_en_r  <= 1'b1;
            iBIST_en_2r <= 1'b1;
        end
        else if ( iBIST_en ) begin
            iBIST_en_r  <= 1'b1;
            iBIST_en_2r <= 1'b0;
        end
        else begin
            iBIST_en_r  <= 1'b0;
            iBIST_en_2r <= 1'b0;
        end
    end
    assign TEST_RESET = iBIST_en_2r ^ iBIST_en;


    // BIST Controller (March C)
    reg        TEST_flag_finish;
    reg [2:0]  TEST_state;
    reg [1:0]  TEST_action;
    reg        TEST_SRAM_WEN;
    reg [31:0] TEST_ADDR;
    reg [7:0]  TEST_WDATA;    
    
    always@( posedge BIST_CLK ) begin 
    if ( TEST_RESET ) begin                                    //Synchronous Reset
        TEST_flag_finish <= 1'b0;
        TEST_state       <= MARCH_0;
        TEST_action      <= WRITE_0;
        TEST_SRAM_WEN    <= 1'b1;
        TEST_ADDR        <= 13'h0000;
        TEST_WDATA       <= 8'b0000_0000;
    end
    else begin       
        case ( TEST_state )
            //---------------    MARCH 0  ↑   -----------------//
            MARCH_0 : begin                  
                if ( TEST_ADDR == 13'h1FFF ) begin
                    TEST_state       <= MARCH_1;               // 
                    TEST_action      <= READ_0;                // 
                    TEST_SRAM_WEN    <= 1'b0;                  // jump to MARCH_1 to read 0
                    TEST_ADDR        <= 13'h0000;              // 
                    TEST_WDATA       <= 8'bz;                  // 
                end 
                else if ( TEST_action == WRITE_0 ) begin
                    TEST_state       <= TEST_state;
                    TEST_action      <= TEST_action;
                    TEST_SRAM_WEN    <= 1'b1;
                    TEST_ADDR        <= TEST_ADDR + 1'b1;     // addr ++   
                    TEST_WDATA       <= 8'b0000_0000;         // write 0
                end          
            end 

            //---------------    MARCH 1  ↑   ----------------//
            MARCH_1 : begin
                if ( TEST_action == WRITE_1 && TEST_ADDR == 13'h1FFF ) begin
                    TEST_state       <= MARCH_2;              // 
                    TEST_action      <= READ_1;               //
                    TEST_SRAM_WEN    <= 1'b0;                 // jump to MARCH_2 to read 1
                    TEST_ADDR        <= 13'h1FFF;             // 
                    TEST_WDATA       <= 8'bz;                 //
                end 
                else if ( TEST_action == READ_0 ) begin
                    TEST_state       <= TEST_state;
                    TEST_action      <= WRITE_1;              // write 1 in next clk
                    TEST_SRAM_WEN    <= 1'b1;                 // write 1 in next clk
                    TEST_ADDR        <= TEST_ADDR;            // addr kept for write 1  
                    TEST_WDATA       <= 8'b1111_1111;         // write 1 in next clk
                end 
                else if ( TEST_action == WRITE_1 )begin
                    TEST_state       <= TEST_state;
                    TEST_action      <= READ_0;               // read 0 in next clk 
                    TEST_SRAM_WEN    <= 1'b0;                 // read 0 in next clk 
                    TEST_ADDR        <= TEST_ADDR + 1'b1;     // addr++ 
                    TEST_WDATA       <= 8'bz;                 // read 0 in next clk 
                end
            end

            //---------------    MARCH 2  ↓   ----------------//
            MARCH_2 : begin
                if ( TEST_action == WRITE_0 && TEST_ADDR == 13'h0000 ) begin
                    TEST_state       <= MARCH_3;              //                     
                    TEST_action      <= READ_0;               //                             
                    TEST_SRAM_WEN    <= 1'b0;                 // jump to MARCH_3 to read 0  
                    TEST_ADDR        <= 13'h1FFF;             //      
                    TEST_WDATA       <= 8'bz;                 //                              
                end                                            
                else if ( TEST_action == READ_1 ) begin             
                    TEST_state       <= TEST_state;               
                    TEST_action      <= WRITE_0;              // write 0 in next clk               
                    TEST_SRAM_WEN    <= 1'b1;                 // write 0 in next clk        
                    TEST_ADDR        <= TEST_ADDR;            // addr kept for write 0         
                    TEST_WDATA       <= 8'b0000_0000;         // write 0 in next clk                                  
                end                                             
                else if ( TEST_action == WRITE_0 )begin       //      
                    TEST_state       <= TEST_state;           //    
                    TEST_action      <= READ_1;               // read 1 in next clk             
                    TEST_SRAM_WEN    <= 1'b0;                 // read 1 in next clk   
                    TEST_ADDR        <= TEST_ADDR - 1'b1;     // addr-- 
                    TEST_WDATA       <= 8'bz;                 // read 1 in next clk
                end    
            end

            //---------------    MARCH 3  ↓   ----------------//
            MARCH_3 : begin
                if ( TEST_action == WRITE_1 && TEST_ADDR == 13'h0000 ) begin
                    TEST_state       <= MARCH_4;
                    TEST_action      <= READ_1;               // jump to MARCH_4 to read 1
                    TEST_SRAM_WEN    <= 1'b0;
                    TEST_ADDR        <= 13'h0000;
                    TEST_WDATA       <= 8'bz;
                end 
                else if ( TEST_action == READ_0 ) begin
                    TEST_state       <= TEST_state;           // write 1 in next clk
                    TEST_action      <= WRITE_1;              // write 1 in next clk
                    TEST_SRAM_WEN    <= 1'b1;                 // write 1 in next clk
                    TEST_ADDR        <= TEST_ADDR;            // addr kept for write 1   
                    TEST_WDATA       <= 8'b1111_1111;         // write 1 in next clk
                end 
                else if ( TEST_action == WRITE_1 )begin
                    TEST_state       <= TEST_state;           // read 0 in next clk
                    TEST_action      <= READ_0;               // read 0 in next clk
                    TEST_SRAM_WEN    <= 1'b0;                 // read 0 in next clk
                    TEST_ADDR        <= TEST_ADDR - 1'b1;     // addr-- 
                    TEST_WDATA       <= 8'bz;                 // read 0 in next clk
                end
            end

            //---------------    MARCH 4  ↑   ----------------//
            MARCH_4 : begin
                if ( TEST_action == READ_0 && TEST_ADDR == 13'h1FFF ) begin
                    TEST_flag_finish <= 1'b1;
                    TEST_state       <= MARCH_finished;
                    TEST_action      <= 2'bz;          
                    TEST_SRAM_WEN    <= 1'bz;
                    TEST_ADDR        <= 13'hz;
                    TEST_WDATA       <= 8'bz;
                end 
                else if ( TEST_action == READ_1 ) begin
                    TEST_state       <= TEST_state;     
                    TEST_action      <= WRITE_0;              // write 0 in next clk
                    TEST_SRAM_WEN    <= 1'b1;                 // write 0 in next clk
                    TEST_ADDR        <= TEST_ADDR;            // addr kept for write 0   
                    TEST_WDATA       <= 8'b0000_0000;         // write 0 in next clk
                end 
                else if ( TEST_action == WRITE_0 )begin
                    TEST_state       <= TEST_state; 
                    TEST_action      <= READ_0;               // read 0 in next clk
                    TEST_SRAM_WEN    <= 1'b0;                 // read 0 in next clk
                    TEST_ADDR        <= TEST_ADDR;            // addr kept for read 0 
                    TEST_WDATA       <= 8'bz;                 // read 0 in next clk
                end
                else if ( TEST_action == READ_0 )begin
                    TEST_state       <= TEST_state;
                    TEST_action      <= READ_1;               // read 1 in next clk
                    TEST_SRAM_WEN    <= 1'b0;                 // read 1 in next clk
                    TEST_ADDR        <= TEST_ADDR + 1'b1;     // addr++ 
                    TEST_WDATA       <= 8'bz;                 // read 1 in next clk
                end
            end
            MARCH_finished : begin
                TEST_flag_finish <= 1'b1;
                TEST_state       <= TEST_state;
            end
            default: begin
                TEST_flag_finish <= 1'b0;
                TEST_state       <= MARCH_0;
                TEST_action      <= WRITE_0;
                TEST_SRAM_WEN    <= 1'b1;
                TEST_ADDR        <= 13'h0000;
                TEST_WDATA       <= 8'b0000_0000;
            end 
        endcase        
    end
    end

    // Compare SRAM_RDATA with Ideal Result 
    reg TEST_compare_result;

    always@( posedge BIST_CLK ) begin     

        // Reset the Comparsion Result
        if ( TEST_RESET ) begin
            TEST_compare_result <= COMPARE_RIGHT; // COMPARE_RIGHT = 1'b1
        end

        // Read 0 in March_1 
        else if ( TEST_state == MARCH_1 && TEST_action == WRITE_1 ) begin
            if ( SRAM_RDATA == 8'b0000_0000)   TEST_compare_result <= TEST_compare_result && 1'b1; 
            else                               TEST_compare_result <= TEST_compare_result && 1'b0; 
        end

        // Read 1 in March_2 
        else if ( TEST_state == MARCH_2 && TEST_action == WRITE_0 ) begin
            if ( SRAM_RDATA == 8'b1111_1111)   TEST_compare_result <= TEST_compare_result && 1'b1;
            else                               TEST_compare_result <= TEST_compare_result && 1'b0; 
        end

        // Read 0 in March_3 
        else if ( TEST_state == MARCH_3 && TEST_action == WRITE_1 ) begin
            if ( SRAM_RDATA == 8'b0000_0000)   TEST_compare_result <= TEST_compare_result && 1'b1; 
            else                               TEST_compare_result <= TEST_compare_result && 1'b0; 
        end

        // Read 1 in March_4 
        else if ( TEST_state == MARCH_4 && TEST_action == WRITE_0 ) begin
            if ( SRAM_RDATA == 8'b1111_1111)   TEST_compare_result <= TEST_compare_result && 1'b1; 
            else                               TEST_compare_result <= TEST_compare_result && 1'b0; 
        end

        // Read 0 in March_4    
        else if ( TEST_state == MARCH_4 && TEST_action == READ_1 && TEST_ADDR != 13'h0000) begin
            if ( SRAM_RDATA == 8'b0000_0000)   TEST_compare_result <= TEST_compare_result && 1'b1; 
            else                               TEST_compare_result <= TEST_compare_result && 1'b0; 
        end

        else begin
            TEST_compare_result <= TEST_compare_result ; 
        end

    end

    assign oBIST_done = ( TEST_flag_finish && TEST_compare_result  ) ? 1'b1 : 1'b0; 
    assign oBIST_fail = ( TEST_flag_finish && !TEST_compare_result ) ? 1'b1 : 1'b0; 

endmodule

2.4 BIST的仿真验证

最后,BIST功能同样在Vivado平台上进行了逻辑仿真,

整个BIST过程共BIST_en = 1开始,一共花费了约1600μs完成,

最后BIST_done被拉高,这是必然的 ,因为逻辑仿真中不涉及实际芯片制造中的各种故障,

我们先从宏观上看仿真波形:

从波形中可以看到,MARCH_0状态持续时间最短,这是因为MARCH_0对于每个地址操作仅为WRITE_0,

而MARCH_1,MARCH_2,MARCH_3状态分别要进行读和写两个操作,因此每个状态下的总周期数均为MARCH_0状态的2倍,

MARCH_4则更长,共READ_1,WRITE_0,READ_0三个操作,总周期数为MARCH_0状态的3倍,

接下来看看MARCH_0和MARCH_1状态之间的转换波形:

其他几段状态转化处的波形也是同理,在此不在一一标注解释了,具体如下:

MARCH_1状态和MARCH_2状态之间的波形:

MARCH_2状态和MARCH_3状态之间的波形:

MARCH_3状态和MARCH_4状态之间的波形:

MARCH_4状态最后一段波形:

完成MARCH_4后,BIST_done被拉高,代表BIST结束。

以上,就是关于AHB-SRAN的BIST模式下的逻辑仿真解读。

最后附上两种工作模式下的Testbench:

点击查看代码
`timescale 1ns / 1ps

module sram_tb #(
    //HRESP
    parameter    OKAY  = 2'b00   ,
    parameter    ERROR = 2'b01   ,
    parameter    SPLIT = 2'b10   ,
    parameter    RETRY = 2'b11   ,
    //HTRANS
    parameter    IDLE   = 2'b00  ,
    parameter    BUSY   = 2'b01  ,
    parameter    SEQ    = 2'b10  ,
    parameter    NONSEQ = 2'b11  ,
    //HSIZE
    parameter    BYTE  = 3'b000  ,
    parameter    WORD  = 3'b001  ,
    parameter    DWORD = 3'b010  ,
    //HBURST
    parameter    SINGLE = 3'b000 ,
    parameter    INCR   = 3'b001 ,
    parameter    WRAP4  = 3'b010 ,
    parameter    INCR4  = 3'b011 ,
    parameter    WARP8  = 3'b100 ,
    parameter    INCR8  = 3'b101 ,
    parameter    WARP16 = 3'b110 ,
    parameter    INCR16 = 3'b111 

)();

    // input output declaration   
    reg HCLK;
    reg HRESETn;
    reg           HSEL  ;
    reg  [1:0]    HTRANS;    
    reg  [2:0]    HBURST;
    reg  [2:0]    HSIZE ;
    reg           HWRITE;
    reg  [15:0]   HADDR ;
    reg  [31:0]   HWDATA;
    wire          HREADY;
    wire [1:0]    HRESP ;
    wire [31:0]   HRDATA;
    // BIST IO
    reg           BIST_en;
    wire          BIST_done;
    wire          BIST_fail;

    // top module instantion
    sram_top u_test(
        .HCLK   (HCLK   ), 
        .HRESETn(HRESETn), 
        .HSEL   (HSEL   ),
        .HTRANS (HTRANS ),    
        .HBURST (HBURST ),
        .HSIZE  (HSIZE  ),
        .HWRITE (HWRITE ),
        .HADDR  (HADDR  ),
        .HWDATA (HWDATA ),
        .HREADY (HREADY ),
        .HRESP  (HRESP  ),
        .HRDATA (HRDATA ),
        .BIST_en  (BIST_en  ),     
        .BIST_done(BIST_done),
        .BIST_fail(BIST_fail)
    );
 
    // Excitation Vector Generation
    initial begin
    	forever #10 HCLK = ~HCLK;	//50Mhz
    end
    
    initial begin
        HCLK  = 0;
        HRESETn = 0;


    // Choose BIST Mode/ FUNC Mode to run simulation 
    
    /*————————————————————————————————————————————————————————————————————————*
    /                        Testbench for BIST Mode                             
    *————————————————————————————————————————————————————————————————————————*/        
        
/*
        BIST_en = 1;
    end
*/  

    /*————————————————————————————————————————————————————————————————————————*
    /                        Testbench for FUNC Mode                           
    *————————————————————————————————————————————————————————————————————————*/      
        
        HRESETn = 0;
        BIST_en = 0;

        HSEL    = 0;
        HTRANS  = 3'b111;    
        HBURST  = 2'b11;
        HSIZE   = 3'b111;
        HWRITE  = 1'b0;
        HADDR   = 16'h0000; //HADDR[1:0] have to be 2'b00 ( 4n )
        HWDATA  = 32'h0;

        #65  HRESETn = 1;
        //-------------------------WRITE MEM---------------
        #20  
        // write control0 
        HSEL    = 1;
        HTRANS  = NONSEQ;    
        HBURST  = SINGLE;
        HSIZE   = WORD;
        HWRITE  = 1'b1;
        HADDR   = 16'h0000;

        #20  
        // data0 → mem(0x0000)     
        HWDATA  = 32'h11223344;
        // write control 1        
        HWRITE  = 1'b1;
        HADDR   = 16'h0004;


        #20  
        // data1 → mem(0x0004)
        HWDATA  = 32'h55667788;
        // write control 2     
        HWRITE  = 1'b1;
        HADDR   = 16'h0008;


        #20  
        // data2 → mem(0x0008)
        HWDATA  = 32'h99AABBCC;
        //// write control 3
        //HWRITE  = 1'b1;
        //HADDR   = 16'h000C;

        #20  
        // data3 → mem(0x000C)
        HWDATA  = 32'hAAAAAAAA;
        // write control 4
        HWRITE  = 1'b1;
        HADDR   = 16'h0010;

        #20  
        // data4 → mem(0x0010)
        HWDATA  = 32'hBBBBBBBB;
        // write control 5
        HWRITE  = 1'b1;
        HADDR   = 16'h0014;

        
        #20  
        // data5 → mem(0x0014)
        HWDATA  = 32'hCCCCCCCC;
        // write control 6
        HWRITE  = 1'b1;
        HADDR   = 16'h8000;

        #20  
        // data6 → mem(0x8000)
        HWDATA  = 32'hDDDDDDDD;
        // write control 7
        HWRITE  = 1'b1;
        HADDR   = 16'h8004;

        #20  
        // data7 → mem(0x8004)
        HWDATA  = 32'hEEEEEEEE;
        // write control 8
        HWRITE  = 1'b1;
        HADDR   = 16'h8008;

        #20  
        // data8 → mem(0x8008)
        HWDATA  = 32'hFFFFFFFF;
        // read control 0
        HWRITE  = 1'b0;
        HADDR   = 16'h0000;
        
        //--------------READ MEM----------------
        #20
        // MASTER FINDS HREADY=0, SO MASTER WAITS
        
        #20  
        // read control 1
        HWRITE  = 1'b0;
        HADDR   = 16'h0004;
        HWDATA  = 32'h00000000; // to test if hwdata will work when HWRTIE = 0

        #20  
        // read control 2
        HWRITE  = 1'b0;
        HADDR   = 16'h0008;

        #20  
        // read control 3
        HWRITE  = 1'b0;
        HADDR   = 16'h000C;

        #20  
        // read control 4
        HWRITE  = 1'b0;
        HADDR   = 16'h0010;

        #20  
        // read control 5
        HWRITE  = 1'b0;
        HADDR   = 16'h0014;

        #20  
        // read control 6
        HWRITE  = 1'b0;
        HADDR   = 16'h8000;

        #20  
        // read control 7
        HWRITE  = 1'b0;
        HADDR   = 16'h8004;

        #20  
        // read control 8
        HWRITE  = 1'b0;
        HADDR   = 16'h8008;

        #100 
        $finish();
    end


endmodule

至此,本项目的所有内容已介绍完毕。

内容来源于网络如有侵权请私信删除

文章来源: 博客园

原文链接: https://www.cnblogs.com/sjtu-zsj-990702/p/17243626.html

你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!