基于 AHB 总线的 SRAM 控制器设计

4 篇文章 0 订阅
3 篇文章 1 订阅


一、基于 AHB 的 sram 设计

1、总体设计框架

ahb_sramc_control

2、AHB总线传输协议

①没有等待状态的单个读写操作

请添加图片描述

②有等待状态的单个读写操作

请添加图片描述

③连续读写操作

请添加图片描述

二、数据读写位宽与深度、块选与片选控制

1、hsize控制读写数据位宽与数据深度(默认位宽为32bit,深度为2^14)

    通过haddr的高位自动控制sram内的块选与片选,根据位宽自动拼接各片存储ram,对应关系如下图所示:

绘图5

2、当hsize为2’b00时,数据位宽为8bit,数据深度为2^16

    当数据位宽为8位时由下图可知,控制器内的sram相当于串联了每个片选,数据会根据地址位的增加进而向高位片选进行存取操作。

fbc7243cd8f6d3286070628d774b1c8

3、当hsize为2’b01时,数据位宽为16bit,数据深度为2^15

    当数据位宽为16位时由下图可知,控制器将两两片选绑定,低位片选存取数据低8位,高位片选存取数据高8位。

979e27f5082deef4e8b00e63921ec6f

4、当hsize为2’b10时,数据位宽为32bit,数据深度为2^14

    当数据位宽为32位时由下图可知,控制器将4个片选绑定,即每一块作为一个数据的32位存取。

cdca3ff32af45260c13a686fb47f368

三、程序设计

RTL设计

1、sramc_top.v

module sramc_top(
    //input signals
    input wire			hclk,
    input wire			sram_clk,   // hclk 的反向,与hclk属于同一个时钟沿
    input wire    		hresetn,    // 复位

    input wire    		hsel,       // AHB-Slave 有多个,此处对应的是AHB-SRAM的hsel
    input wire   	 	hwrite,     // 读/写指示
    input wire			hready,     // master -> slave,一般接常高
    input wire [2:0]  	hsize ,     // 访问数据有效字节数 
    input wire [2:0]  	hburst,     // 此处没有用到
    input wire [1:0]  	htrans,     // SEQ/NOSEQ,传输是否有效
    input wire [31:0] 	hwdata,     // 写数据
    input wire [31:0] 	haddr,      // 本次命令访问的地址		

    //Signals for BIST and DFT test mode
    //When signal"dft_en" or "bist_en" is high, sram controller enters into test mode.
    // 内建测试,测试内部的SRAM制造是否有问题,功能验证时此处接零即可,DFT工程师会专门去做的!		
    input wire            dft_en,
    input wire            bist_en,

    //output signals
    output wire         	hready_resp, // slave -> master,看 slave 是否ready,在前面介绍的规格里我们知道slave不支持反压,hready_resp 会常高
    output wire [1:0]   	hresp,       // hresp 也只会返回0,即ok状态。
    output wire [31:0] 	    hrdata,      // 从sram读出的数据

    //When "bist_done" is high, it shows BIST test is over.
    output wire        	    bist_done,
    //"bist_fail" shows the results of each sram funtions.There are 8 srams in this controller.
    output wire [7:0]       bist_fail
);

    //Select one of the two sram blocks according to the value of sram_csn
    wire       bank_sel ;
    wire [3:0] bank0_csn;
    wire [3:0] bank1_csn;
    //Sram read or write signals: When it is high, read sram; low, writesram.
    wire  sram_w_en; // hwrite is 1, write; hwrite is 0, read. 但是sram是为0时写,为1时读。所以需要一个信号去翻译AHB信号(取反)

    //Each of 8 srams is 8kx8, the depth is 2^13 (8K), so the sram's address width is 13 bits. 
    wire [12:0] sram_addr;

    //AHB bus data write into srams
    wire [31:0] sram_wdata;

    //sram data output data which selected and read by AHB bus
    wire [7:0] sram_q0;
    wire [7:0] sram_q1;
    wire [7:0] sram_q2;
    wire [7:0] sram_q3;
    wire [7:0] sram_q4;
    wire [7:0] sram_q5;
    wire [7:0] sram_q6;
    wire [7:0] sram_q7;

 
    // Instance the two modules:           
    // ahb_slave_if.v and sram_core.v      
    ahb_slave_if  ahb_slave_if_u(
        //-----------------------------------------
        // AHB input signals into sram controller
        //-----------------------------------------
        .hclk     (hclk),
        .hresetn  (hresetn),
        .hsel     (hsel),
        .hwrite   (hwrite),
        .hready   (hready),
        .hsize    (hsize),
        .htrans   (htrans),
        .hburst   (hburst),
        .hwdata   (hwdata),
        .haddr    (haddr),

        //-----------------------------------------
        //8 sram blcoks data output into ahb slave
        //interface
        //-----------------------------------------
        .sram_q0   (sram_q0),
        .sram_q1   (sram_q1),
        .sram_q2   (sram_q2),
        .sram_q3   (sram_q3),
        .sram_q4   (sram_q4),
        .sram_q5   (sram_q5),
        .sram_q6   (sram_q6),
        .sram_q7   (sram_q7),

        //---------------------------------------------
        //AHB slave(sram controller) output signals 
        //---------------------------------------------
        .hready_resp  (hready_resp),
        .hresp        (hresp),
        .hrdata       (hrdata),

        //---------------------------------------------
        //sram control signals and sram address  
        //---------------------------------------------
        // 五组信号:读写指示、数据、地址、块选、片选
        .sram_w_en    (sram_w_en),
        .sram_addr_out(sram_addr),
        //data write into sram
        .sram_wdata   (sram_wdata),
        //choose the corresponding sram in a bank, active low
        .bank_sel     (bank_sel ),
        .bank0_csn    (bank0_csn),
        .bank1_csn    (bank1_csn)
    );

  
    sram_core  sram_core_u(
        //AHB bus signals
        .hclk        (hclk    ),
        .sram_clk    (sram_clk),
        .hresetn     (hresetn ),

        //-------------------------------------------
        //sram control singals from ahb_slave_if.v
        //-------------------------------------------
        .sram_addr    (sram_addr ),
        .sram_wdata_in(sram_wdata),
        .sram_wen     (sram_w_en ),
        .bank_sel     (bank_sel  ),
        .bank0_csn    (bank0_csn ),
        .bank1_csn    (bank1_csn ),

        //test mode enable signals
        .bist_en      (bist_en   ),
        .dft_en       (dft_en    ),

        //-------------------------------------------
        //8 srams data output into AHB bus
        //-------------------------------------------
        .sram_q0    (sram_q0),
        .sram_q1    (sram_q1),
        .sram_q2    (sram_q2),
        .sram_q3    (sram_q3),
        .sram_q4    (sram_q4),
        .sram_q5    (sram_q5),
        .sram_q6    (sram_q6),
        .sram_q7    (sram_q7),

        //test results output when in test mode
        .bist_done  (bist_done),
        .bist_fail  (bist_fail)
    );
  
endmodule

2、ahb_slave_if.v

    ahb slave接口模块将ahb master发送的存取指令转换为sram的数据存取与块、片选指令。

module ahb_slave_if(
    //               AHB信号列表
    // singals used during normal operation
    input  hclk,
    input  hresetn,
    // signals from AHB bus during normal operation
    input  hsel,                   //hsel恒为1,表示选中该SRAMC
    input  hready,                 //由Master总线发出,hready=1,读/写数据有效;否则,无效
    input  hwrite,                 //hwrite=1,写操作;hwrite=0,读操作
    input  [1:0]   htrans,         //当前传输类型10:NONSEQ,11:SEQ(命令是否有效)
    input  [2:0]   hsize,          //每一次传输的数据大小,支持8/16/32bit传输
    input  [2:0]   hburst,         //burst操作,该项目无用,置0即可
    input  [31:0]  haddr,          //AHB:32位系统总线地址
    input  [31:0]  hwdata,         //AHB:32位写数据操作
    // signals from sram_core data output (read srams)
    input  [7:0]  sram_q0,              //表示读取sram数据信号
    input  [7:0]  sram_q1,              //8片RAM的返回数据
    input  [7:0]  sram_q2,              //可以根据hsize和haddr判断哪一片RAM有效
    input  [7:0]  sram_q3,
    input  [7:0]  sram_q4,
    input  [7:0]  sram_q5,
    input  [7:0]  sram_q6,
    input  [7:0]  sram_q7,
    


    // signals to AHB bus used during normal operation 
    //(读数据输出->进入AHB总线),即返回给Master的相关信号
    output  [1:0]  hresp,             //状态信号,判断hrdata读数据是否出错;00:OKAY,01:ERROR传输错误
    output         hready_resp,       //判断hrdata是否有效,hready_out
    output  [31:0] hrdata,            //读数据信号

    // sram read or write enable signals,
    // 以下5个信号为返回给RAM的信号
    // when "sram_w_en" is low, it means write sram, when "sram_w_en" is high, it means read sram,
    output  sram_w_en,         //写使能信号,0:写;1:读

    // choose the write srams when bank is confirmed
    // bank_csn allows the four bytes in the 32-bit width to be written independently
    output  reg        bank_sel,//bank_sel为1代表bank0被访问;bank_sel为0代表bank1被访问
    output  reg [3:0]  bank0_csn,//bank0内片区选择(0为选中该片区,如4’b1100则选中bank0低两位片区)
    output  reg [3:0]  bank1_csn,//bank1内片区选择

    // signals to sram_core in normal operation, it contains sram address and data writing into sram 
    //(写数据输出->进入sram存储单元)
    output  [12:0]  sram_addr_out,          // 地址输出进入sram,13位地址(8k=2^3*2^10=2^13)
    output  [31:0]  sram_wdata              //写数据进入sram
); 

    // internal registers used for temp the input ahb signals (临时信号)
    // temperate all the AHB input signals
    reg         hwrite_r;         //_r:表示这些信号会经过寄存器寄存一拍;
    reg  [2:0]  hsize_r;          //因为AHB协议传输分为地址阶段和数据阶段两个部分,而SRAM的地址和数据是在同一拍进行传输,
    reg  [2:0]  hburst_r;         //AHB的地址和控制信号会在数据信号的前一拍生效,所以,为了将AHB与SRAM之间的协议进行转换,
    reg  [1:0]  htrans_r;         //使数据对齐,需将AHB的地址与控制信号打一拍再传输,这样传入SRAM的地址和数据便处于同一拍,
    reg  [31:0] haddr_r;          //以满足SRAM的时序要求。

    reg  [3:0]  sram_csn;         //内部信号,由于sram分为bank0和bank1两部分,在进行读写数据时,首先会根据地址范围判断选中bank0
                                  //或者bank1,再根据hsize_r和haddr_r来确定具体访问到bank0/bank1中的具体哪一片sram。
    // Internal signals    中间信号
    // "haddr'_sel" and "hsize_sel" used to generate banks of sram: "bank0_sel" and "bank1_sel"
    wire  [1:0]  haddr_sel;
    wire  [1:0]  hsize_sel;
    //reg          bank_sel;

    wire         sram_csn_en;     //sram片选使能信号

    wire         sram_write;     //来自AHB总线的sram写使能信号
    wire         sram_read;      //来自AHB总线的sram读使能信号
    wire  [15:0] sram_addr;      //来自AHB总线的sram地址信号,64K=2^5*2^10=2^15
    reg   [31:0] sram_data_out;  //从sram发出的读数据信号,发送至AHB总线

    // transfer type signal encoding
    parameter  IDLE   = 2'b00; //定义htrans的状态
    parameter  BUSY   = 2'b01;
    parameter  NONSEQ = 2'b10; //数据传输有效(非连续传输)
    parameter  SEQ    = 2'b11;  //数据传输有效(连续传输)
   
    parameter SUB_DATA = 1'b0;//输出数据补状态(例输出16位数据,则高16位补SUB_DATA)
//--------------------------------------------------------------------------------------------------------
//----------------------------------------------Main code-------------------------------------------------
//--------------------------------------------------------------------------------------------------------


    // Combitional portion ,     组合逻辑部分
    // assign the response and read data of the AHB slave
    // To implement sram function-writing or reading in one cycle, value of hready_resp is always "1"
    assign  hready_resp = 1'b1;    //hready_resp恒为1,不支持反压,由Slave返回给Master,读/写数据可在一个循环内完成
    assign  hresp       = 2'b00;   //00表示hrdata读数据OKAY,不支持ERROR、RETRY、SPLIT,只返回OKAY状态

    // sram data output to AHB bus
    assign  hrdata = sram_data_out;  //由sram存储单元输出数据,经hrdata导出至AHB总线,支持8/16/32bit位

    // Generate sram write and read enable signals
    assign  sram_write = ((htrans_r == NONSEQ) || (htrans_r == SEQ)) && hwrite_r;
    assign  sram_read = ((htrans_r == NONSEQ) || (htrans_r == SEQ)) && (! hwrite_r);
    assign  sram_w_en = !sram_write;     //SRAM写使能为0,代表写;为1,代表读;其含义与由总线产生的sram_write中间信号相反


    // Generate sram address 
    // 系统逻辑地址(eg:CPU)看到的空间是 0 1 2 3 4 5 6 7 8 ...,但是访问的时候总线位宽是32bit,所以访问地址依次是0 4 8 C。
    // 但是对于SRAM这个存储介质来讲,看到的空间是实际的物理地址,每个地址是由32bit组成的,所以访问地址依次是:0 1 2 3
    assign  sram_addr = haddr_r[15:0];      //系统内存空间:64K=2^6*2^10=2^16,即系统地址由16根地址线组成--系统地址
    //assign  sram_addr_out = sram_addr[14:2];//物理地址=系统地址/4,即右移两位,64KB=8*8K*8bit,每一片SRAM地址深度为8K=2^13,有13根地址线(详细原因参考后文)
    assign  sram_addr_out = sram_addr[12:0];//物理地址=系统地址/4,即右移两位,64KB=8*8K*8bit,每一片SRAM地址深度为8K=2^13,有13根地址线(详细原因参考后文)
    // Generate bank select signals by the value of sram_addr[15].
    // Each bank(32K*32)comprises of four sram block(8K*8), and the width of the address of the bank is
    // 15 bits(14-0),so the sram_addr[15] is the minimum of the next bank. if it is value is '1', it means 
    // the next bank is selected.
    assign sram_csn_en = (sram_write || sram_read); 

    // signals used to generating sram chip select signal in one bank.
    //assign  haddr_sel = sram_addr[1:0];    /*修改前*/ 
    assign  haddr_sel = sram_addr[14:13];    /*修改后*/ //通过sram的地址低两位和hsize_r信号判断选择4片sram中的具体哪一片
    assign  hsize_sel  = hsize_r[1:0];

    // data from AHB writing into sram.
    assign  sram_wdata =hwdata;   //将通过AHB的数据写进sram存储单元中

    /*修改前*/
    //片选使能为1且sram_addr[15]为0,表示选中bank0,接着再根据sram_csn选中bank0中4个RAM的某几个RAM(详细原因参考后文)
    //assign  bank0_csn = (sram_csn_en && (sram_addr[15] == 1'b0))?sram_csn:4'b1111;  //系统地址的最高位为sram_addr[15],用来判断访问sram的bank0还是bank1
    //assign  bank1_csn = (sram_csn_en && (sram_addr[15] == 1'b1))?sram_csn:4'b1111;  //sram_addr[15]=0 访问bank0;sram_addr[15]=1 访问bank1 因为是均分的BANK
    //assign  bank_sel = (sram_csn_en && (sram_addr[15] == 1'b0))?1'b1:1'b0; //bank_sel为1代表bank0被访问;bank_sel为0代表bank1被访问 


    
    /*修改后*///bank与cs控制选择
    always@(*)begin
        if(sram_csn_en)begin
            case(hsize_sel)
                2'b00:begin//8bit
                    bank0_csn = (sram_addr[15] == 1'b0)?sram_csn:4'b1111;
                    bank1_csn = (sram_addr[15] == 1'b1)?sram_csn:4'b1111;
                    bank_sel =  (sram_addr[15] == 1'b0)?1'b1:1'b0;
                end
                2'b01:begin                          
                    bank0_csn = (sram_addr[14] == 1'b0)?sram_csn:4'b1111;
                    bank1_csn = (sram_addr[14] == 1'b1)?sram_csn:4'b1111;
                    bank_sel =  (sram_addr[14] == 1'b0)?1'b1:1'b0;               
                end
                2'b10:begin                            
                    bank0_csn = (sram_addr[13] == 1'b0)?sram_csn:4'b1111;
                    bank1_csn = (sram_addr[13] == 1'b1)?sram_csn:4'b1111;
                    bank_sel =  (sram_addr[13] == 1'b0)?1'b1:1'b0;                
                end
                default:begin//默认32位            
                    bank0_csn = (sram_addr[13] == 1'b0)?sram_csn:4'b1111;
                    bank1_csn = (sram_addr[13] == 1'b1)?sram_csn:4'b1111;
                    bank_sel =  (sram_addr[13] == 1'b0)?1'b1:1'b0;                 
                end
            endcase
        end
        else begin
            bank0_csn = 4'b1111;
            bank1_csn = 4'b1111;
            bank_sel  = 1'b1;
        end
    end
    
        
    // Choose the right data output of two banks(bank0,bank1) according to the value of bank_sel.
    
      /*修改前*///If bank_sel = 1'b1, bank1 selected;or, bank0 selected.    
//    assign  sram_data_out = (bank_sel) ? {sram_q3,sram_q2,sram_q1,sram_q0}:         //对sram的数据输出进行选择
//                                         {sram_q7,sram_q6,sram_q5,sram_q4};

    /*修改一版*///改为可变数据位宽输出与默认输出为0    
//    /assign  sram_data_out = sram_read?//如果sram读,则对sram的数据输出进行选择、如果sram非读,sram输出为0
//    ((bank_sel) ? ((hsize_sel==2'b10)?{sram_q3,sram_q2,sram_q1,sram_q0}:((hsize_sel==2'b01)?{16'd0,sram_q1,sram_q0}:{24'd0,sram_q0})):
//    ((hsize_sel==2'b10)?{sram_q7,sram_q6,sram_q5,sram_q4}:((hsize_sel==2'b01)?{16'd0,sram_q5,sram_q4}:{24'd0,sram_q4})))
//    :32'd0;

    /*修改最终版*///片区输出控制sram_data_out 
    always@(*)begin
        if(!hresetn)begin
            sram_data_out = {32{SUB_DATA}};
        end
        else if(sram_read)begin
            if(bank_sel)begin
                case(hsize_sel)
                    2'b00:begin//data size 8bit
                        case(haddr_sel)
                            2'b00:sram_data_out = {{24{SUB_DATA}},sram_q0};
                            2'b01:sram_data_out = {{24{SUB_DATA}},sram_q1};
                            2'b10:sram_data_out = {{24{SUB_DATA}},sram_q2};
                            2'b11:sram_data_out = {{24{SUB_DATA}},sram_q3};
                        endcase
                    end
                    2'b01:begin//data size 16bit
                         case(haddr_sel[0])
                            1'b0:sram_data_out = {{16{SUB_DATA}},sram_q1,sram_q0};
                            1'b1:sram_data_out = {{16{SUB_DATA}},sram_q3,sram_q2};
                        endcase                   
                     
                    end
                    2'b10:sram_data_out = {sram_q3,sram_q2,sram_q1,sram_q0};//data size 32bit
                    default:begin 
                          sram_data_out = {sram_q3,sram_q2,sram_q1,sram_q0};//data size 32bit                  
                    end
                endcase
            end
            else begin
                 case(hsize_sel)
                    2'b00:begin//data size 8bit
                        case(haddr_sel)
                            2'b00:sram_data_out = {{24{SUB_DATA}},sram_q4};
                            2'b01:sram_data_out = {{24{SUB_DATA}},sram_q5};
                            2'b10:sram_data_out = {{24{SUB_DATA}},sram_q6};
                            2'b11:sram_data_out = {{24{SUB_DATA}},sram_q7};
                        endcase
                    end
                    2'b01:begin//data size 16bit
                         case(haddr_sel[0])
                            1'b0:sram_data_out = {{16{SUB_DATA}},sram_q5,sram_q4};
                            1'b1:sram_data_out = {{16{SUB_DATA}},sram_q7,sram_q6};
                        endcase                   
                     
                    end
                    2'b10:sram_data_out = {sram_q7,sram_q6,sram_q5,sram_q4};//data size 32bit
                    default:begin 
                          sram_data_out = {sram_q7,sram_q6,sram_q5,sram_q4};//data size 32bit                   
                   end
                endcase           
            end
        end
        else begin
            sram_data_out = sram_data_out;
        end
    end


// Generate the sram chip selecting signals in one bank.
// results show the AHB bus write or read how many data once a time:byte(8),halfword(16) or word(32).
    always@(*) begin
    //always@(*) begin
        if(hsize_sel == 2'b10)            //32bits:word operation,4片sram都会进行访问
          sram_csn = 4'b0;                //active low,sram_csn信号低有效,4'b0000代表4片SRAM都被选中
        else if(hsize_sel == 2'b01)       //16bits:halfword,选中4片中的其中两片(前两片或者后两片)
          begin
            //if(haddr_sel[1] == 1'b0)      /*修改前*/ //low halfword,若地址的低两位为00,则访问低16位;如为10,则访问高16位(详细原因参考后文)
            if(haddr_sel[0] == 1'b0)        /*修改后*/
              sram_csn = 4'b1100;         //访问低两片SRAM(低16bit)
            else                          //high halfword
              sram_csn = 4'b0011;         //访问高两片SRAM(高16bit)
          end
        else if(hsize_sel == 2'b00)       //8bits:byte,访问4片sram中的一片
          begin
            case(haddr_sel)
              2'b00:sram_csn = 4'b1110;    //访问最右侧的sram
              2'b01:sram_csn = 4'b1101;    //访问最右侧左边第一片sram
              2'b10:sram_csn = 4'b1011;    //访问最左侧右边第一片sram
              2'b11:sram_csn = 4'b0111;    //访问最左侧的sram
            endcase
          end
        else
          sram_csn = 4'b0;      //默认32bit数据位宽
    end

// Sequential portion,     时序逻辑部分(SRAM 地址和数据要对齐,所以将AHB两拍转一拍)
// tmp the ahb address and control signals
    always@(posedge hclk or negedge hresetn) begin
        if(!hresetn)
          begin
            hwrite_r <= 1'b0;
            hsize_r  <= 3'b0;
            hburst_r <= 3'b0;         
            htrans_r <= 2'b0;
            haddr_r  <= 32'b0;
          end
        else if(hsel && hready)
          begin
            hwrite_r <= hwrite;
            hsize_r  <= hsize;       //由于sram的地址和数据在同一拍,所以需要将AH包的
            hburst_r <= hburst;      //地址和控制信号寄存一拍,使其与数据对齐
            htrans_r <= htrans;
            haddr_r  <= haddr;
          end
        else
          begin
            hwrite_r <= 1'b0;
            hsize_r  <= 3'b0;
            hburst_r <= 3'b0;         
            htrans_r <= 2'b0;
            haddr_r  <= 32'b0;
          end
    end

endmodule

3、sram_core.v

    ahb sram_core模块通过ahb slave接口模块转换为sram的数据存取与块、片选指令控制各个sram片的数据进出。

module sram_core(
    //input signals
    input			    hclk,
    input			    sram_clk,
    input			    hresetn,

    input			    sram_wen,        // =1 读sram; =0,写sram.
    input	[12:0]	    sram_addr,       //物理地址 = 系统地址 / 4
    input	[31:0]	    sram_wdata_in,   //data write into sram when "sram_wen_in" active low
    input               bank_sel,        //bank_sel为1代表bank0被访问;bank_sel为0代表bank1被访问
    input	[3:0]	    bank0_csn,       //两个bank,每个bank有四个片选
    input	[3:0]	    bank1_csn,
    input			    bist_en,         //BIST test mode//用不上
    input	    	    dft_en,          //DFT test mode//用不上
          
    //output signals
    output [7:0]	sram_q0,
    output [7:0]	sram_q1,
    output [7:0]	sram_q2,
    output [7:0]	sram_q3,
    output [7:0]	sram_q4,
    output [7:0]	sram_q5,
    output [7:0]	sram_q6,
    output [7:0]	sram_q7,
                    
    output			bist_done,  //When "bist_done" is high, it shows BIST test is over.
    output [7:0]    bist_fail   //"bist_fail" shows the results of each sram funtions.
);
 
    //data_in sram_csn
    reg [7:0] sram_cs0_data_in;
    reg [7:0] sram_cs1_data_in;
    reg [7:0] sram_cs2_data_in;
    reg [7:0] sram_cs3_data_in;
    reg [7:0] sram_cs4_data_in;
    reg [7:0] sram_cs5_data_in;
    reg [7:0] sram_cs6_data_in;
    reg [7:0] sram_cs7_data_in;
 
    //Every sram bist's work state and results output.
    wire bist_done0;
    wire bist_fail0;
    wire bist_done1;
    wire bist_fail1;
    wire bist_done2;
    wire bist_fail2;
    wire bist_done3;
    wire bist_fail3;
    wire bist_done4;
    wire bist_fail4;
    wire bist_done5;
    wire bist_fail5;
    wire bist_done6;
    wire bist_fail6;
    wire bist_done7;
    wire bist_fail7;

    wire bank0_bistdone;
    wire bank1_bistdone;

    wire [3:0] bank0_bistfail;
    wire [3:0] bank1_bistfail;

    //bist finishing state of bank0
    assign bank0_bistdone = (bist_done3 && bist_done2) && (bist_done1 && bist_done0);

    //bist results of bank0
    assign bank0_bistfail = {bist_fail3,bist_fail2,bist_fail1,bist_fail0};

    //bist finishing state of bank1
    assign bank1_bistdone = (bist_done7 && bist_done6) && (bist_done5 && bist_done4);

    //bist results of bank1
    assign bank1_bistfail = {bist_fail7,bist_fail6,bist_fail5,bist_fail4};

    //--------------------------------------------------------------------------
    //the 8 srams results of BIST test and the finishing state
    //--------------------------------------------------------------------------
    assign bist_done = bank0_bistdone && bank1_bistdone;
    assign bist_fail = {bank1_bistfail,bank0_bistfail} ;
    //write data in bank cs 
    
//    assign sram_cs0_data_in = (~sram_wen&~bank0_csn[0]&bank_sel) ?sram_wdata_in[7:0]    :{8{1'bz}};
//    assign sram_cs1_data_in = (~sram_wen&~bank0_csn[1]&bank_sel) ?sram_wdata_in[15:8]   :{8{1'bz}};
//    assign sram_cs2_data_in = (~sram_wen&~bank0_csn[2]&bank_sel) ?sram_wdata_in[23:16]  :{8{1'bz}};
//    assign sram_cs3_data_in = (~sram_wen&~bank0_csn[3]&bank_sel) ?sram_wdata_in[31:24]  :{8{1'bz}};
//    assign sram_cs4_data_in = (~sram_wen&~bank1_csn[0]&~bank_sel)?sram_wdata_in[7:0]    :{8{1'bz}};
//    assign sram_cs5_data_in = (~sram_wen&~bank1_csn[1]&~bank_sel)?sram_wdata_in[15:8]   :{8{1'bz}};
//    assign sram_cs6_data_in = (~sram_wen&~bank1_csn[2]&~bank_sel)?sram_wdata_in[23:16]  :{8{1'bz}};
//    assign sram_cs7_data_in = (~sram_wen&~bank1_csn[3]&~bank_sel)?sram_wdata_in[31:24]  :{8{1'bz}};

    
    //write data in bank cs     
    always@(*)begin
        if(!hresetn)begin
			sram_cs0_data_in = 8'd0;
			sram_cs1_data_in = 8'd0;
            sram_cs2_data_in = 8'd0;
            sram_cs3_data_in = 8'd0;
            sram_cs4_data_in = 8'd0;
            sram_cs5_data_in = 8'd0;
            sram_cs6_data_in = 8'd0;
            sram_cs7_data_in = 8'd0;
        end    
        else begin
            if(bank_sel)begin//bank_sel为1代表bank0被访问;bank_sel为0代表bank1被访问
                case(bank0_csn)
                    //8bit data in 
                    4'b1110:begin
                        sram_cs0_data_in = sram_wdata_in[7:0];
                    end
                    4'b1101:begin
                        sram_cs1_data_in = sram_wdata_in[7:0];
                    end
                    4'b1011:begin
                        sram_cs2_data_in = sram_wdata_in[7:0];
                    end
                    4'b0111:begin
                        sram_cs3_data_in = sram_wdata_in[7:0];
                    end               
                    //16bit data in 
                    4'b1100:begin
                        sram_cs0_data_in = sram_wdata_in[7:0];
                        sram_cs1_data_in = sram_wdata_in[15:8];
                    end
                    4'b0011:begin
                        sram_cs2_data_in = sram_wdata_in[7:0];
                        sram_cs3_data_in = sram_wdata_in[15:8];
                    end  
                    //32bit data in              
                    4'b0000:begin
                        sram_cs0_data_in = sram_wdata_in[7:0];
                        sram_cs1_data_in = sram_wdata_in[15:8];                
                        sram_cs2_data_in = sram_wdata_in[23:16];
                        sram_cs3_data_in = sram_wdata_in[31:24];
                    end 
                    default:;              
                endcase
            end
            else begin
                case(bank1_csn)
                    //8bit data in 
                    4'b1110:begin
                        sram_cs4_data_in = sram_wdata_in[7:0];
                    end
                    4'b1101:begin
                        sram_cs5_data_in = sram_wdata_in[7:0];
                    end
                    4'b1011:begin
                        sram_cs6_data_in = sram_wdata_in[7:0];
                    end
                    4'b0111:begin
                        sram_cs7_data_in = sram_wdata_in[7:0];
                    end               
                    //16bit data in 
                    4'b1100:begin
                        sram_cs4_data_in = sram_wdata_in[7:0];
                        sram_cs5_data_in = sram_wdata_in[15:8];
                    end
                    4'b0011:begin
                        sram_cs6_data_in = sram_wdata_in[7:0];
                        sram_cs7_data_in = sram_wdata_in[15:8];
                    end  
                    //32bit data in              
                    4'b0000:begin
                        sram_cs4_data_in = sram_wdata_in[7:0];
                        sram_cs5_data_in = sram_wdata_in[15:8];                
                        sram_cs6_data_in = sram_wdata_in[23:16];
                        sram_cs7_data_in = sram_wdata_in[31:24];
                    end 
                    default:;              
                endcase
            end
        end
    end
    //-------------------------------------------------------------------------
    //Instance 8 srams and each provides with BIST and DFT functions. 
    //Bank0 comprises of sram0~sram3, and bank1 comprises of sram4~sram7. 
    //In each bank, the sram control signals broadcast to each sram, and data
    //written per byte into each sram in little-endian style.
    //-------------------------------------------------------------------------
 
    //bank0_cs0
    sram_bist u_sram_bist0(
        .hclk             (hclk            ),
        .sram_clk         (sram_clk        ),
        .sram_rst_n       (hresetn         ),
        .sram_csn_in      (bank0_csn[0]    ),
        .sram_wen_in      (sram_wen        ),
        .sram_addr_in     (sram_addr       ),
        .sram_wdata_in    (sram_cs0_data_in),
        .bist_en          (bist_en         ),
        .dft_en           (dft_en          ),
                    
        .sram_data_out    (sram_q0         ),
        .bist_done        (bist_done0      ),
        .bist_fail        (bist_fail0      )  
        );
    //bank0_cs1
    sram_bist u_sram_bist1(
        .hclk             (hclk            ),
        .sram_clk         (sram_clk        ),
        .sram_rst_n       (hresetn         ),
        .sram_csn_in      (bank0_csn[1]    ),
        .sram_wen_in      (sram_wen        ),
        .sram_addr_in     (sram_addr       ),
        .sram_wdata_in    (sram_cs1_data_in),
        .bist_en          (bist_en         ),
        .dft_en           (dft_en          ),
                    
        .sram_data_out    (sram_q1         ),
        .bist_done        (bist_done1      ),
        .bist_fail        (bist_fail1      )  
        );
    //bank0_cs2
    sram_bist u_sram_bist2(
        .hclk             (hclk            ),
        .sram_clk         (sram_clk        ),
        .sram_rst_n       (hresetn         ),
        .sram_csn_in      (bank0_csn[2]    ),
        .sram_wen_in      (sram_wen        ),
        .sram_addr_in     (sram_addr       ),
        .sram_wdata_in    (sram_cs2_data_in),
        .bist_en          (bist_en         ),
        .dft_en           (dft_en          ),
                    
        .sram_data_out    (sram_q2),
        .bist_done        (bist_done2),
        .bist_fail        (bist_fail2)  
        );
    //bank0_cs3
    sram_bist u_sram_bist3(
        .hclk             (hclk            ),
        .sram_clk         (sram_clk        ),
        .sram_rst_n       (hresetn         ),
        .sram_csn_in      (bank0_csn[3]    ),
        .sram_wen_in      (sram_wen        ),
        .sram_addr_in     (sram_addr       ),
        .sram_wdata_in    (sram_cs3_data_in),
        .bist_en          (bist_en         ),
        .dft_en           (dft_en          ),
                    
        .sram_data_out    (sram_q3         ),
        .bist_done        (bist_done3      ),
        .bist_fail        (bist_fail3      )  
        );
    //bank1_cs4
    sram_bist u_sram_bist4(
        .hclk             (hclk            ),
        .sram_clk         (sram_clk        ),
        .sram_rst_n       (hresetn         ),
        .sram_csn_in      (bank1_csn[0]    ),
        .sram_wen_in      (sram_wen        ),
        .sram_addr_in     (sram_addr       ),
        .sram_wdata_in    (sram_cs4_data_in),
        .bist_en          (bist_en         ),
        .dft_en           (dft_en          ),
                    
        .sram_data_out    (sram_q4         ),
        .bist_done        (bist_done4      ),
        .bist_fail        (bist_fail4      )  
        );
    //bank1_cs5
    sram_bist u_sram_bist5(
        .hclk             (hclk            ),
        .sram_clk         (sram_clk        ),
        .sram_rst_n       (hresetn         ),
        .sram_csn_in      (bank1_csn[1]    ),
        .sram_wen_in      (sram_wen        ),
        .sram_addr_in     (sram_addr       ),
        .sram_wdata_in    (sram_cs5_data_in),
        .bist_en          (bist_en         ),
        .dft_en           (dft_en          ),
                    
        .sram_data_out    (sram_q5         ),
        .bist_done        (bist_done5      ),
        .bist_fail        (bist_fail5      )  
        );
    //bank1_cs6
    sram_bist u_sram_bist6(
        .hclk             (hclk            ),
        .sram_clk         (sram_clk        ),
        .sram_rst_n       (hresetn         ),
        .sram_csn_in      (bank1_csn[2]    ),
        .sram_wen_in      (sram_wen        ),
        .sram_addr_in     (sram_addr       ),
        .sram_wdata_in    (sram_cs6_data_in),
        .bist_en          (bist_en         ),
        .dft_en           (dft_en          ),
                    
        .sram_data_out    (sram_q6         ),
        .bist_done        (bist_done6      ),
        .bist_fail        (bist_fail6      )  
        );
    //bank1_cs7        
    sram_bist u_sram_bist7(
        .hclk             (hclk            ),
        .sram_clk         (sram_clk        ),
        .sram_rst_n       (hresetn         ),
        .sram_csn_in      (bank1_csn[3]    ),
        .sram_wen_in      (sram_wen        ),
        .sram_addr_in     (sram_addr       ),
        .sram_wdata_in    (sram_cs7_data_in),
        .bist_en          (bist_en         ),
        .dft_en           (dft_en          ),
                        
        .sram_data_out    (sram_q7         ),
        .bist_done        (bist_done7      ),
        .bist_fail        (bist_fail7      )  
        );

endmodule

4、sram_bist.v

    sram_bist模块如果进行bist与dft测试就转入sram_bist_8kx8内的测试设计,否的话只对数据通过RA1SH模块经行存取。

module sram_bist(
    //input signals
    input         hclk,
    input         sram_clk,
    input         sram_rst_n,
    input         sram_csn_in,   //chip select(negative) enable (0 有效)
    input         sram_wen_in,   //sram write or read enable; 0:write; 1:read
    input[12:0]   sram_addr_in,  // 物理地址 8个8K = 2^13
    input[7:0 ]   sram_wdata_in, // 每个8K x 8bit 的数据位宽
    input         bist_en,       // MBIST mode
    input         dft_en,      // DFT mode

    //output signals
    output[7:0 ]  sram_data_out, 
    output        bist_done,     // 1: test over
    output        bist_fail      // high: MBIST Fail
);
				
    //----------------------------------------------------
    //Internal signals connected the sram with bist module 
    //when "bist_en" active high.
    //----------------------------------------------------
    wire sram_csn;
    wire sram_wen;
    wire sram_oen;
    wire [12:0] sram_a;
    wire [7:0]  sram_d;
    wire [7:0]  data_out;

    //Sram output data when "dft_en" active high.
    wire [7:0] dft_data;
    reg [7:0]  dft_data_r;

    wire [12:0] sram_addr;
    wire [7:0]  sram_wdata;

    //clock for bist logic, when bist is not work, clock should be 0.
    wire bist_clk;

    genvar K;

    //block sram input when cs is diable for low power design 
    assign sram_addr = sram_csn_in ? 0 : sram_addr_in;
    assign sram_wdata = sram_csn_in ? 0 : sram_wdata_in;

    //dft test result 具体为什么这么异或,不需要太关注
    assign dft_data = (sram_d ^ sram_a[7:0]) ^ {sram_csn, sram_wen, sram_oen, sram_a[12:8]}; 

    always @(posedge hclk or negedge sram_rst_n) begin
    if(!sram_rst_n)
        dft_data_r <= 0;
    else if(dft_en)
        dft_data_r <= dft_data;
    end

    //sram data output
    assign sram_data_out = dft_en ? dft_data_r : data_out;
    // Note: Need to take place the mux using the special library cell
    /*
    generate for(K = 0; K < 8; K = K+1 )
    begin :hold
    //BHDBWP7T holdQ (.Z(data_out[K])); // 作用:把data_out做一个保持 在做DFT的时候是例化标准单元(源语)实现的,没有用RTL方式
    end 
    endgenerate
    */

    //clock for bist logic, when bist is not work, clock should be 0.
    // Note: Need to take place the mux using the special library cell
    // CKMUX2D2BWP7T U_bist_clk_mux (.I0(1'b0), .I1(hclk), .S(bist_en), .Z(bist_clk));
    assign bist_clk = bist_en ? hclk : 1'b0;

    // One sram with BIST and DFT function
    // 在整个SRAM_BIST 中实际上包含了两部分代码,一部分是存储单元,一部分是Memory Bist
    // sram_sp_hse_8kx8 : sram singleport high density 8k depth x 8bit width
    RA1SH u_RA1SH(
        .Q      (data_out), // 输出数据端口
        .CLK    (sram_clk), // hclk 取反
        .CEN    (sram_csn), // chip select 低有效
        .WEN    (sram_wen), // 写使能,低有效
        .A      (sram_a),   // Address 地址(要么是读,要么是写) 选择功能地址还是DFT测试地址
        .D      (sram_d),   // Data 数据 从下面的Bist过来的
        .OEN    (sram_oen)  // 没怎么用,只在bist的时候用了一下
    );

    //测试控制逻辑
    sram_bist_8kx8 u_sram_bist_8kx8(
        .b_clk   (bist_clk),   // 同hclk
        .b_rst_n (sram_rst_n), 
        .b_te    (bist_en),    // 外面给过来的启动使能
        //--------------------------------------------------------
        //All the input signals will be derectly connected to
        //the sram input when in normal operation; and when in
        //BIST TEST mode, there are some mux in BIST module
        //selcting all sram input signals which generated by itself:
        //sram controll signals, sram write data, etc.
        //--------------------------------------------------------

        // xx_fun 表示从ahb过来的, 需要验证的功能
        .addr_fun     (sram_addr), // 物理地址 = 系统地址 / 4
        .wen_fun      (sram_wen_in), // ahb_wen 基础上取反 1读 0写
        .cen_fun      (sram_csn_in), // ahb的address 和 size 低两比特得到的 csn
//        .oen_fun      (~sram_wen_in),        // 低电平有效,一直打开
        .oen_fun      (1'b0),        // 低电平有效,一直打开
        .data_fun     (sram_wdata),  // 写数据

        // 输出不用选,测试电路和功能电路都会送过去
        .ram_read_out (sram_data_out), //
        .data_test    (sram_d),
        .addr_test    (sram_a), // sram_addr 和 内部产生的addr进行 bist_en 选择之后输出的一个值
        .wen_test     (sram_wen), // wen 也是通过bist_en选择之后输出的
        .cen_test     (sram_csn),
        .oen_test     (sram_oen),

        .b_done       (bist_done),
        .b_fail       (bist_fail)
    );

endmodule

5、sram_bist_8kx8.v

    sram_bist_8kx8模块的大部分内容专门为bist测试与dft测试所设计,如果没有这方面需求可忽略不看。

module sram_bist_8kx8
#(parameter WE_WIDTH = 1,
  parameter ADDR_WIDTH = 13,
  parameter DATA_WIDTH = 8
 )
 (
  //input signals
  input                      b_clk,    // bist clock	
  input                      b_rst_n,  // bist resetn
  input                      b_te,     // bist enable
  input [(ADDR_WIDTH-1):0]   addr_fun, // Address
  input [(WE_WIDTH-1):0]     wen_fun,  // write enable
  input                      cen_fun,  // chip enable
  input                      oen_fun,  // ouput enable
  input [(DATA_WIDTH-1):0]   data_fun, // data input
  input [(DATA_WIDTH-1):0]   ram_read_out, //RAM data output

  //output signals
  output [(ADDR_WIDTH-1):0]  addr_test, // address of test
  output [(WE_WIDTH-1):0]    wen_test,  // writing control of bist test mode
  output                     cen_test,  // chip enable control of bist test mode
  output                     oen_test,  // output enable control of bist test mode
  output [(DATA_WIDTH-1):0]  data_test, // data input of bist test mode
  output				     b_done,    // output state of bist test mode
                                        // When "bist_done" is high, it shows BIST test is over.

  output reg                 b_fail     // output result of sram function
                                        // When "bist_fail" is high, the sram function is wrong;
                                        // else, the sram function is right.
);

  //----------------------------------------------------
  //Define 27 work states of BIST block for bist test
  //----------------------------------------------------
  `define IDEL1         5'b00000
  `define P1_WRITE0     5'b00001
  `define IDEL2         5'b00010
  `define P2_READ0      5'b00011
  `define P2_COMPARE0   5'b00100
  `define P2_WRITE1     5'b00101
  `define IDEL3         5'b00110
  `define P3_READ1      5'b00111
  `define P3_COMPARE1   5'b01000
  `define P3_WRITE0     5'b01001
  `define P3_READ0      5'b01010
  `define P3_COMPARE0   5'b01011
  `define P3_WRITE1     5'b01100
  `define IDEL4         5'b01101
  `define P4_READ1      5'b01110
  `define P4_COMPARE1   5'b01111
  `define P4_WRITE0     5'b10000
  `define IDEL5         5'b10001
  `define P5_READ0      5'b10010
  `define P5_COMPARE0   5'b10011
  `define P5_WRITE1     5'b10100
  `define P5_READ1      5'b10101
  `define P5_COMPARE1   5'b10110
  `define P5_WRITE0     5'b10111
  `define IDEL6         5'b11000
  `define P6_READ0      5'b11001
  `define P6_COMPARE0   5'b11010
  
  // sram address when in bist test mode
  reg [(ADDR_WIDTH-1):0] test_addr;
  
  // bist test end signal
  reg r_end;
  reg r_end_en;
 
  // sram address reset when in bist test mode.
  reg test_addr_rst;

  // sram read or write enable signal when in bist test mode
  reg [(WE_WIDTH-1):0] wen_test_inner;

  // bist start to work in IDLE
  reg rf_start;
  
  // compare the data read from sram with the data written into sram 
  // enable signal
  reg check_en;

  // bist test data source select signal
  // "pattern_sel == 1'b0"-----> test_pattern =  32'b0;
  // "pattern_sel == 1'b1"-----> test_pattern =  32'b1;
  reg pattern_sel;
  wire [(DATA_WIDTH-1):0] test_pattern;
  reg [4:0] cstate, nstate;
  // 1 -- address is goign upward; 0 -- address is going downward
  reg up1_down0; 
  // 1 -- address is stepping; 0 -- address remains
  reg count_en;  


  //-----------------------------------------------------------------
  //          Main Code
  //-----------------------------------------------------------------

  //-----------------------------------------------------------------
  //     Combinatorial portion
  //-----------------------------------------------------------------
  assign b_done = r_end;
  assign test_pattern = (pattern_sel == 1'b0) ? {DATA_WIDTH{1'b0}} : {DATA_WIDTH{1'b1}};

  //--------------------------------------------------------------------
  // The output values of all the mux below will be changed based on the
  // sram whether in normal operation or in bist test mode. 
  //---------------------------------------------------------------------
  // b_te 打开的话就选择测试一侧的,否则就选择功能一侧的fun
  assign data_test = (b_te == 1'b1) ? test_pattern   : data_fun;
  assign addr_test = (b_te == 1'b1) ? test_addr      : addr_fun;
  assign wen_test  = (b_te == 1'b1) ? wen_test_inner : wen_fun;
  assign cen_test  = (b_te == 1'b1) ? 1'b0           : cen_fun;
  assign oen_test  = (b_te == 1'b1) ? 1'b0           : oen_fun;

  //--------------------------------------------------------------------
  //    Sequential portion
  //--------------------------------------------------------------------

  //--------------------------------
  // Generate bist work end signal. 
  //--------------------------------
  always @(posedge b_clk , negedge b_rst_n) begin
    if (b_rst_n == 1'b0) 
       r_end<=1'b0;
    else if (r_end_en == 1'b1) 
       r_end<= 1'b1;
       else
         r_end <= 1'b0;
  end
  //----------------------------------------------------
  //          Generate the sram test address.
  // "test_addr_rst " and "up1_down0" decide the mode of 
  // variable the address(increment/decrement). 
  //-----------------------------------------------------
  always @(posedge b_clk , negedge b_rst_n) begin
    if (b_rst_n == 1'b0) 
       test_addr <= {ADDR_WIDTH{1'b0}};
    else if (b_te == 1'b1) 
  	  if (test_addr_rst == 1'b1) 
           if (up1_down0 == 1'b1)
          	  test_addr<=  {ADDR_WIDTH{1'b0}};
           else
              test_addr<=  {ADDR_WIDTH{1'b1}};
     	else
           if (count_en == 1'b1)
               if (up1_down0 == 1'b1)
          	      test_addr<=  test_addr + 1'b1; // 地址从小往大扫描
               else
                  test_addr<=  test_addr - 1'b1; // 地址从大往小扫描
  end

  always @(posedge b_clk , negedge b_rst_n)
    if (b_rst_n == 1'b0) 
       b_fail<=1'b1;
    else begin
      //---------------------------------------------------------
      //  When in bist idle1 state, "b_fail" defualt value is "0".
      // --------------------------------------------------------
      if ((b_te == 1'b1) && (rf_start == 1'b1)) // 重新启动清零
          b_fail<=  1'b0;

      //------------------------------------------------------------
      //  "b_fail" value is "1", when data read from sram is different
      // from the expected data wirtten into sram.
      //--------------------------------------------------------------
      if ((b_te == 1'b1) && (check_en == 1'b1) && !(test_pattern == ram_read_out)) // 写的跟读出的是否一致
          b_fail<=  1'b1;
     end
  
  //------------------------------------------------------------------------------
  //                    Bist test state machine(知道了解即可)
  //   write "0"(initial sram)                         test_address 0-->1fff
  //   read  "0"------> compare -------->write "1"     test_address 1fff-->0
  //   read  "1"------> compare -------->write "0"     test_address 0-->1fff
  //   write "1"------> read "1"-------->compare       test_address 1fff-->0        
  //   write "0"------> read "0"-------->compare       test_address 0-->1fff        
  //   write "1"------> read "1"-------->compare       test_address 1fff-->0        
  //   write "0"------> read "0"-------->compare       test_address 0-->1fff        
  //------------------------------------------------------------------------------
  always @(posedge b_clk , negedge b_rst_n) begin
    if (b_rst_n == 1'b0) 
          cstate<=`IDEL1;
    else
          cstate<= nstate;
  end
  
  always @(cstate or b_te or r_end or test_addr) begin
    up1_down0     = 1'b1;
    count_en      = 1'b0;
    r_end_en      = 1'b0;
    pattern_sel   = 1'b0;
    test_addr_rst = 1'b0;
    rf_start      = 1'b0;
    check_en      = 1'b0;
    wen_test_inner = {WE_WIDTH{1'b1}};
    nstate        = cstate;
    case (cstate)
      `IDEL1 :
          begin
             test_addr_rst = 1'b1;
             if (b_te == 1'b1 && r_end == 1'b0) begin
                   nstate   = `P1_WRITE0;
                   rf_start = 1'b1;
             end
          end
      `P1_WRITE0 :   //initial sram from addr 0~1fff(16K) 做bist的时候不会去考虑低功耗了,看到的就是0-16K
          begin
    	    count_en       = 1'b1;
    	    wen_test_inner = {WE_WIDTH{1'b0}};
    	    pattern_sel    = 1'b0;
             if (test_addr == {ADDR_WIDTH{1'b1}} ) begin
                  nstate        = `IDEL2;
                  test_addr_rst = 1'b1;
    	            up1_down0     = 1'b0;
             end
          end
      `IDEL2 :
          begin
    	      pattern_sel   = 1'b0;
    	      up1_down0     = 1'b0;
            test_addr_rst = 1'b1; 
            nstate        = `P2_READ0;
          end
      `P2_READ0 :
          begin
            nstate = `P2_COMPARE0;
          end
      `P2_COMPARE0 :  //compare all "0" data after read from addr 0~1fff
          begin
             pattern_sel = 1'b0;
    	       check_en    = 1'b1;
             nstate      = `P2_WRITE1;
          end
      `P2_WRITE1 :  //all "1" write test from addr 1fff~0
          begin
    	      up1_down0      = 1'b0;
    	      count_en       = 1'b1;
    	      wen_test_inner = {WE_WIDTH{1'b0}};
    	      pattern_sel    = 1'b1;
             if (test_addr == {ADDR_WIDTH{1'b0}}) begin
                  nstate        = `IDEL3;
                  test_addr_rst = 1'b1;
    	          up1_down0     = 1'b1;
             end
             else
                nstate        = `P2_READ0;
          end
      `IDEL3 :
          begin
             pattern_sel   = 1'b1;
             test_addr_rst = 1'b1;
             nstate        = `P3_READ1;
          end
      `P3_READ1 :
          begin
             nstate = `P3_COMPARE1;
          end
      `P3_COMPARE1 :  //compare all "1" data after read from addr 1fff~0
          begin
            pattern_sel = 1'b1;
            check_en    = 1'b1;
            nstate      = `P3_WRITE0;
          end
      `P3_WRITE0 :
          begin
             wen_test_inner = {WE_WIDTH{1'b0}};
             pattern_sel    = 1'b0;
             nstate         = `P3_READ0;
          end
      `P3_READ0 :
          begin
            nstate = `P3_COMPARE0;
          end
      `P3_COMPARE0 :
          begin
            pattern_sel = 1'b0;
            check_en    = 1'b1;
            nstate      = `P3_WRITE1;
          end
      `P3_WRITE1 :
          begin
             wen_test_inner = {WE_WIDTH{1'b0}};
             pattern_sel    = 1'b1;
             count_en       = 1'b1;
             if (test_addr == {ADDR_WIDTH{1'b1}}) begin
                  nstate        = `IDEL4;
                  test_addr_rst = 1'b1;
             end
             else
                nstate        = `P3_READ1;
          end
      `IDEL4 :   // read all data from addr 1fff~0 and compare with write data "1" every time 
          begin
            pattern_sel   = 1'b1;
            test_addr_rst = 1'b1;
            nstate        = `P4_READ1;
          end
      `P4_READ1 :
          begin
            nstate = `P4_COMPARE1;
          end
      `P4_COMPARE1 :
          begin
            pattern_sel = 1'b1;
            check_en    = 1'b1;
            nstate      = `P4_WRITE0;
          end
      `P4_WRITE0 :
          begin
            wen_test_inner = {WE_WIDTH{1'b0}};
            pattern_sel    = 1'b0;
            count_en       = 1'b1;
             if (test_addr == {ADDR_WIDTH{1'b1}}) begin
                   nstate        = `IDEL5;
                   test_addr_rst = 1'b1;
             end
             else         
                nstate        = `P4_READ1;
          end
      `IDEL5 :  // read all data from addr 1fff~0 and compare with write data "0" every time 
          begin
             pattern_sel   = 1'b1;
             test_addr_rst = 1'b1;
             nstate        = `P5_READ0;
          end
      `P5_READ0 :
          begin
             nstate = `P5_COMPARE0;
          end
      `P5_COMPARE0 :
          begin
             pattern_sel=1'b0;
             check_en=1'b1;
             nstate = `P5_WRITE1;
          end
      `P5_WRITE1 :
          begin
             wen_test_inner = {WE_WIDTH{1'b0}};
             pattern_sel   = 1'b1;
             nstate = `P5_READ1;
          end
      `P5_READ1 :
          begin
             nstate = `P5_COMPARE1;
          end
      `P5_COMPARE1 :
          begin
             pattern_sel=1'b1;
             check_en=1'b1;
             nstate = `P5_WRITE0;
          end
      `P5_WRITE0 :
          begin
             wen_test_inner = {WE_WIDTH{1'b0}};
             pattern_sel    = 1'b0;
             count_en       = 1'b1;
             if (test_addr == {ADDR_WIDTH{1'b1}}) begin
                   nstate        = `IDEL6;
                   test_addr_rst = 1'b1;
             end
             else
                nstate        = `P5_READ0;
          end
      `IDEL6 :
          begin
             pattern_sel   = 1'b0;
             test_addr_rst = 1'b1;
             nstate        = `P6_READ0;
          end
      `P6_READ0 :
          begin
             nstate        = `P6_COMPARE0;
          end
      `P6_COMPARE0 :
          begin
             pattern_sel = 1'b0;
             check_en    = 1'b1;
             count_en    = 1'b1;
             if (test_addr == {ADDR_WIDTH{1'b1}}) begin
                   nstate        = `IDEL1;
                   test_addr_rst = 1'b1;
                   r_end_en      = 1'b1;
             end
             else
                nstate = `P6_READ0;
          end
      default :
          begin
             nstate        = `IDEL1;
             test_addr_rst = 1'b1;
          end 
    endcase
  end
endmodule

5、RA1SH.v

    RA1SH模块应该为封装的sram IP,主要内容为mem_cycle这个任务,是通过读写使能控制mem对输入地址进行存取,然后后面是一堆路径延迟设计、建立与保持时间检测等。

`celldefine
module RA1SH ( //8K
   Q,          //data_out [7:0]
   CLK,        //时钟 hclk 取反
   CEN,        //chip select 低有效
   WEN,        //读写使能、// 写使能,低有效
   A,          //读写地址 [12:0]
   D,          //data_in [7:0]
   OEN         //
);
   parameter		   BITS = 8; // 数据位宽 8 bit
   parameter		   word_depth = 8192; // 8K = 8 x 1024
   parameter		   addr_width = 13;
   parameter		   wordx = {BITS{1'bx}}; // x 态
   parameter		   addrx = {addr_width{1'bx}};
	
   output [BITS-1:0] Q;
   input CLK;
   input CEN;
   input WEN;
   input [addr_width-1:0] A;
   input [BITS-1:0] D;
   input OEN;

   reg [BITS-1:0]	   mem [word_depth-1:0]; // SRAM 的行为本质上就是一个数组的行为 [word_depth-1:0]为深度  [BITS-1:0]为宽度

   reg			           NOT_CEN; // NOT 表示取反 为什么取反?因为代码中会用到一些BUFFER
   reg			           NOT_WEN;

   reg			           NOT_A0;
   reg			           NOT_A1;
   reg			           NOT_A2;
   reg			           NOT_A3;
   reg			           NOT_A4;
   reg			           NOT_A5;
   reg			           NOT_A6;
   reg			           NOT_A7;
   reg			           NOT_A8;
   reg			           NOT_A9;
   reg			           NOT_A10;
   reg			           NOT_A11;
   reg			           NOT_A12;
   reg [addr_width-1:0]	   NOT_A;
   reg			           NOT_D0;
   reg			           NOT_D1;
   reg			           NOT_D2;
   reg			           NOT_D3;
   reg			           NOT_D4;
   reg			           NOT_D5;
   reg			           NOT_D6;
   reg			           NOT_D7;
   reg [BITS-1:0]	       NOT_D ;
   reg			           NOT_CLK_PER;
   reg			           NOT_CLK_MINH;
   reg			           NOT_CLK_MINL;

   reg			           LAST_NOT_CEN;
   reg			           LAST_NOT_WEN;
   reg [addr_width-1:0]    LAST_NOT_A;
   reg [BITS-1:0]	       LAST_NOT_D;
   reg			           LAST_NOT_CLK_PER;
   reg			           LAST_NOT_CLK_MINH;
   reg			           LAST_NOT_CLK_MINL;


   wire [BITS-1:0]         _Q;
   wire			           _OENi;
   wire [addr_width-1:0]   _A;
   wire			           _CLK;
   wire			           _CEN;
   wire			           _OEN;
   wire                    _WEN;

   wire [BITS-1:0]   _D;
   wire                    re_flag;
   wire                    re_data_flag;


   reg			           LATCHED_CEN;
   reg	                   LATCHED_WEN;
   reg [addr_width-1:0]	   LATCHED_A;
   reg [BITS-1:0]	       LATCHED_D;

   reg			           CENi;
   reg           	       WENi;
   reg [addr_width-1:0]	   Ai;
   reg [BITS-1:0]	       Di;
   reg [BITS-1:0]	       Qi;
   reg [BITS-1:0]	       LAST_Qi;

   reg			           LAST_CLK;

task update_notifier_buses;
begin
    NOT_A = {
             NOT_A12,
             NOT_A11,
             NOT_A10,
             NOT_A9,
             NOT_A8,
             NOT_A7,
             NOT_A6,
             NOT_A5,
             NOT_A4,
             NOT_A3,
             NOT_A2,
             NOT_A1,
             NOT_A0};
    NOT_D = {
             NOT_D7,
             NOT_D6,
             NOT_D5,
             NOT_D4,
             NOT_D3,
             NOT_D2,
             NOT_D1,
             NOT_D0};
end
endtask

task mem_cycle;
begin
    casez({WENi,CENi})//WENi 0:写、1:读   CENi:片选(低有效)
        2'b10: begin//读状态
            read_mem(1,0);//读数据输出
        end
        2'b00: begin//写状态
            write_mem(Ai,Di);//写入数据
            read_mem(0,0);//将写入数据显示在读数据输出
        end
        2'b?1: ;
        2'b1x: begin
            read_mem(0,1);  //读出不定态数据
        end
        2'bx0: begin
            write_mem_x(Ai);//写入不定态数据
            read_mem(0,1);  //读出不定态数据
        end
        2'b0x,
        2'bxx: begin
            write_mem_x(Ai);//写入不定态数据
            read_mem(0,1);  //读出不定态数据
        end
    endcase
end
endtask
      

task update_last_notifiers;
begin
    LAST_NOT_A = NOT_A;
    LAST_NOT_D = NOT_D;
    LAST_NOT_WEN = NOT_WEN;
    LAST_NOT_CEN = NOT_CEN;
    LAST_NOT_CLK_PER = NOT_CLK_PER;
    LAST_NOT_CLK_MINH = NOT_CLK_MINH;
    LAST_NOT_CLK_MINL = NOT_CLK_MINL;
end
endtask

task latch_inputs;
begin
    LATCHED_A = _A ;
    LATCHED_D = _D ;
    LATCHED_WEN = _WEN ;
    LATCHED_CEN = _CEN ;
    LAST_Qi = Qi;
end
endtask


task update_logic;
begin
    CENi = LATCHED_CEN;
    WENi = LATCHED_WEN;
    Ai = LATCHED_A;
    Di = LATCHED_D;
end
endtask



task x_inputs;
    integer n;
begin
    for (n=0; n<addr_width; n=n+1)begin
        LATCHED_A[n] = (NOT_A[n]!==LAST_NOT_A[n]) ? 1'bx : LATCHED_A[n] ;
    end
    for (n=0; n<BITS; n=n+1)begin
        LATCHED_D[n] = (NOT_D[n]!==LAST_NOT_D[n]) ? 1'bx : LATCHED_D[n] ;
    end
    LATCHED_WEN = (NOT_WEN!==LAST_NOT_WEN) ? 1'bx : LATCHED_WEN ;
    LATCHED_CEN = (NOT_CEN!==LAST_NOT_CEN) ? 1'bx : LATCHED_CEN ;
end
endtask

task read_mem;
    input r_wb;
    input xflag;
begin
    if (r_wb)begin
        if (valid_address(Ai))begin
            Qi=mem[Ai];
        end
        else begin
            Qi=wordx;
        end
    end
    else begin
        if (xflag)begin
            Qi=wordx;
        end
        else begin
            Qi=Di;
        end
    end
end
endtask

task write_mem;
    input [addr_width-1:0] a;
    input [BITS-1:0] d;
begin
    casez({valid_address(a)})
        1'b0:x_mem;
        1'b1: mem[a]=d;
    endcase
end
endtask

task write_mem_x;
    input [addr_width-1:0] a;
begin
    casez({valid_address(a)})//检查地址是否有效
        1'b0:x_mem;        
        1'b1: mem[a]=wordx;
    endcase
end
endtask

task x_mem;
    integer n;
begin
    for (n=0; n<word_depth; n=n+1)
        mem[n]=wordx;
end
endtask

task process_violations;//主功能
begin
    if ((NOT_CLK_PER!==LAST_NOT_CLK_PER) ||
    (NOT_CLK_MINH!==LAST_NOT_CLK_MINH) ||
    (NOT_CLK_MINL!==LAST_NOT_CLK_MINL))begin
        if (CENi !== 1'b1)begin
            x_mem;
            read_mem(0,1);
        end
    end
    else begin
        update_notifier_buses;
        x_inputs;
        update_logic;
        mem_cycle;
    end
    update_last_notifiers;
end
endtask

function valid_address;
  input [addr_width-1:0] a;
begin
  valid_address = (^(a) !== 1'bx);
end
endfunction


bufif0 (Q[0], _Q[0], _OENi);//三态门bufif0(out, in, ctrl)enable-->ctrl=0
bufif0 (Q[1], _Q[1], _OENi);//三态门bufif1(out, in, ctrl)enable-->ctrl=1
bufif0 (Q[2], _Q[2], _OENi);
bufif0 (Q[3], _Q[3], _OENi);
bufif0 (Q[4], _Q[4], _OENi);
bufif0 (Q[5], _Q[5], _OENi);
bufif0 (Q[6], _Q[6], _OENi);
bufif0 (Q[7], _Q[7], _OENi);
buf (_D[0], D[0]);//多输出门buf(out1, out2,..., in);允许有多个输出,但只有一个输入
buf (_D[1], D[1]);
buf (_D[2], D[2]);
buf (_D[3], D[3]);
buf (_D[4], D[4]);
buf (_D[5], D[5]);
buf (_D[6], D[6]);
buf (_D[7], D[7]);
buf (_A[0], A[0]);
buf (_A[1], A[1]);
buf (_A[2], A[2]);
buf (_A[3], A[3]);
buf (_A[4], A[4]);
buf (_A[5], A[5]);
buf (_A[6], A[6]);
buf (_A[7], A[7]);
buf (_A[8], A[8]);
buf (_A[9], A[9]);
buf (_A[10], A[10]);
buf (_A[11], A[11]);
buf (_A[12], A[12]);
buf (_CLK, CLK);
buf (_WEN, WEN);
buf (_OEN, OEN);
buf (_CEN, CEN);


assign _OENi = _OEN;
assign _Q = Qi;
assign re_flag = !(_CEN);
assign re_data_flag = !(_CEN || _WEN);


always @( // Verilog 95 语法
	    NOT_A0 or // 13位地址、8位数据分为单bit的信号 (写仿真模型的一般操作)
	    NOT_A1 or
	    NOT_A2 or
	    NOT_A3 or
	    NOT_A4 or
	    NOT_A5 or
	    NOT_A6 or
	    NOT_A7 or
	    NOT_A8 or
	    NOT_A9 or
	    NOT_A10 or
	    NOT_A11 or
	    NOT_A12 or
	    NOT_D0 or
	    NOT_D1 or
	    NOT_D2 or
	    NOT_D3 or
	    NOT_D4 or
	    NOT_D5 or
	    NOT_D6 or
	    NOT_D7 or
	    NOT_WEN or
	    NOT_CEN or
	    NOT_CLK_PER or
	    NOT_CLK_MINH or
	    NOT_CLK_MINL
	    )begin
         process_violations; // 时序不满足,但是前端仿真一般不会去管时序,只管功能!
end

always@( _CLK )begin // 时钟检测 
    casez({LAST_CLK,_CLK})
	   2'b01: begin
	      latch_inputs;
	      update_logic;
	      mem_cycle;
	   end
	   2'b10,
	   2'bx?,
	   2'b00,
	   2'b11: ;
	   2'b?x: begin
	      x_mem;
          read_mem(0,1);
	   end
	 endcase
	 LAST_CLK = _CLK;
end

specify //路径延迟块
      $setuphold(posedge CLK, CEN, 1.000, 0.500, NOT_CEN); //  $setuphold 检查 setup 和 hpld 的系统函数,但是我们一般会将其关闭
      $setuphold(posedge CLK &&& re_flag, WEN, 1.000, 0.500, NOT_WEN);
      $setuphold(posedge CLK &&& re_flag, A[0], 1.000, 0.500, NOT_A0);
      $setuphold(posedge CLK &&& re_flag, A[1], 1.000, 0.500, NOT_A1);
      $setuphold(posedge CLK &&& re_flag, A[2], 1.000, 0.500, NOT_A2);
      $setuphold(posedge CLK &&& re_flag, A[3], 1.000, 0.500, NOT_A3);
      $setuphold(posedge CLK &&& re_flag, A[4], 1.000, 0.500, NOT_A4);
      $setuphold(posedge CLK &&& re_flag, A[5], 1.000, 0.500, NOT_A5);
      $setuphold(posedge CLK &&& re_flag, A[6], 1.000, 0.500, NOT_A6);
      $setuphold(posedge CLK &&& re_flag, A[7], 1.000, 0.500, NOT_A7);
      $setuphold(posedge CLK &&& re_flag, A[8], 1.000, 0.500, NOT_A8);
      $setuphold(posedge CLK &&& re_flag, A[9], 1.000, 0.500, NOT_A9);
      $setuphold(posedge CLK &&& re_flag, A[10], 1.000, 0.500, NOT_A10);
      $setuphold(posedge CLK &&& re_flag, A[11], 1.000, 0.500, NOT_A11);
      $setuphold(posedge CLK &&& re_data_flag, D[0], 1.000, 0.500, NOT_D0);
      $setuphold(posedge CLK &&& re_data_flag, D[1], 1.000, 0.500, NOT_D1);
      $setuphold(posedge CLK &&& re_data_flag, D[2], 1.000, 0.500, NOT_D2);
      $setuphold(posedge CLK &&& re_data_flag, D[3], 1.000, 0.500, NOT_D3);
      $setuphold(posedge CLK &&& re_data_flag, D[4], 1.000, 0.500, NOT_D4);
      $setuphold(posedge CLK &&& re_data_flag, D[5], 1.000, 0.500, NOT_D5);
      $setuphold(posedge CLK &&& re_data_flag, D[6], 1.000, 0.500, NOT_D6);
      $setuphold(posedge CLK &&& re_data_flag, D[7], 1.000, 0.500, NOT_D7);
    
      $period(posedge CLK, 3.000, NOT_CLK_PER);
      $width(posedge CLK, 1.000, 0, NOT_CLK_MINH);
      $width(negedge CLK, 1.000, 0, NOT_CLK_MINL);
       /
	   //在路径延时中可以说明6个延时值(0->1, 1->0, 0->Z, Z->1, 1->Z, Z->0)
	   //在路径延时中说明所有12个延时值(0->1, 1->0, 0->Z, Z->1, 1->Z, Z->0, 0->X, X->1, 1->X, X->0, X->Z, Z->X)
	   //
	   //上升延时是输出转换为1时的延时(0->1,Z->1,X->1)
	   //下降延时是输出转换为0时的延时(1->0,Z->0,X->0)
	   //关断延时输出转换为三态Z时的延时(0->Z,1->Z,X->Z,)
	   //到X的转换延时是最小延时,而从X到其它值的转换使用最坏(长)延时
	   //
	   //如果只说明了一个延时,则所有转换使用这个延时。
	   //如果只说明了上升和下降延时,则 1->X 和 X->0 使用下降延时, X->Z 使用上升和下降延时的最小延时
	   //如果说明了六个延时,则 1->X 使用 1->X 和 1->Z 中最小延时; X->0 使用 1->0 和 X->0 的最大延时; X->Z 使用 1->Z 和 0->Z 中的最大延时。
	   
      (CLK => Q[0])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
      (CLK => Q[1])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
      (CLK => Q[2])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
      (CLK => Q[3])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
      (CLK => Q[4])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
      (CLK => Q[5])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
      (CLK => Q[6])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
      (CLK => Q[7])=(1.000, 1.000, 0.500, 1.000, 0.500, 1.000);
      (OEN => Q[0])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
      (OEN => Q[1])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
      (OEN => Q[2])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
      (OEN => Q[3])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
      (OEN => Q[4])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
      (OEN => Q[5])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
      (OEN => Q[6])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
      (OEN => Q[7])=(1.000, 1.000, 1.000, 1.000, 1.000, 1.000);
endspecify 

endmodule
`endcelldefine

TestBench设计

1、tb_sramc_top.sv

    TB模块可以定义数据位宽(DATA_SIZE)与开始存取地址(START_ADDR),设计了边读边写(direct_write_during_read)任务与写定量读空(loop_wr_rd_data)任务,数据则由random_data类随机产生。如果对数字ic验证感兴趣,还可以了解基于UVM的AHB总线SRAM控制器设计验证平台设计这个资源。

`define START_ADDR   8192//32bit:0~2*8192-1、16bit:0~4*8192-1、8bit:0~8*8192-1
`define DATA_SIZE    16  
`define IS_SEQ       1   //1:SEQ write、read  0:NOSEQ write、read(STL中两种都一样)


class random_data;
    rand  bit [`DATA_SIZE-1:0] data;
    rand  bit [`DATA_SIZE-1:0] delay;
    constraint c_delay{
        delay <=50;
    }
endclass

module tb_sramc_top();

//interface define
reg           hclk       ;//产生时钟信号
wire          sram_clk   ;//hclk 的反向,与hclk属于同一个时钟沿
reg           hresetn    ;//复位
reg           hsel       ;//选中该slave
reg           hwrite     ;//读写模式0:读、1:写
reg [1:0]     htrans     ;//传输是否有效00:空闲、01:忙、10:非连续、11:连续
reg [2:0]     hsize      ;//有效传输位00:8bit、01:16bit、10:32bit
reg           hready     ;// master -> slave,一般接常高
reg [31:0]    haddr      ;//本次命令访问的地址
reg [31:0]    hwdata     ;// 写数据
wire [31:0]   hrdata     ;// 从sram读出的数据
wire          hready_resp;// slave -> master,看 slave 是否ready
wire [1:0]    hresp      ;// hresp 也只会返回0,即ok状态。

reg  [`DATA_SIZE-1:0]   rdata      ;//读出数据
reg                     r_data_en;
static int wr_iter = 0 ;
static int rd_iter = 0 ;


always #10 hclk = ~hclk;
assign     sram_clk = ~hclk;

random_data  rm_data;


initial begin
    hclk  =1;
    hresetn = 0;
    #200
    hresetn = 1;
end

initial begin:process
    rm_data = new();
    direct_write_during_read(16'd8);
    #200;
    loop_wr_rd_data(16'd18);
    
    $finish;
end

task ahb_init();
    hsel   = 1'b0 ;//未中该slave
    hwrite = 1'b1 ;//写
    htrans = `IS_SEQ?2'b11:2'b10;
    hsize  = (`DATA_SIZE==32)?2'b10:((`DATA_SIZE==16)?2'b01:((`DATA_SIZE==8)?2'b00:2'b10));//00:8bit、01:16bit、10:32bit、11:32bit
    hready = 1'b1;
    haddr  = 32'd0;
    hwdata = 32'd0;
    rdata  = 32'd0;
    r_data_en = 1'b0;
    wait(hresetn);
    repeat(3)@(posedge sram_clk);
endtask

task write_data;
input [15:0] wr_nums;
begin
    repeat(wr_nums)begin
        @(posedge hclk);
        rm_data.randomize();
        hsel   = 1'b1 ;//选中该slave
        hwrite = 1'b1 ;//写
        haddr  =  `START_ADDR + wr_iter;
        wr_iter = wr_iter +1;
        @(posedge hclk);
        hwdata = rm_data.data;
        hsel = 1;
    end
end
endtask

task read_data;
input [15:0] rd_nums;
begin
    repeat(rd_nums)begin
        @(posedge sram_clk);
        hsel   = 1'b1 ;//选中该slave
        hwrite = 1'b0;//read
        haddr  =  `START_ADDR + rd_iter;//bank1 cs0
        rd_iter = rd_iter +1;
        @(posedge sram_clk); 
        hsel   = 1'b0 ;
        //@(posedge hclk);
        rdata <= hrdata[`DATA_SIZE-1:0];
    end
end
endtask

task direct_write_during_read;
input [15:0] wr_nums;//读写次数
begin
    ahb_init();
    repeat(wr_nums)begin
        write_data(1);
        read_data(1);
    end
    @(posedge sram_clk);
    @(posedge hclk);
    ahb_init();
    #200;
end 
endtask

task loop_wr_rd_data;
input [15:0] wr_nums;
begin
    ahb_init();
    write_data(wr_nums);
    #rm_data.delay;
    read_data(wr_nums);
    @(posedge sram_clk);
    @(posedge hclk);
    ahb_init();
    #200;
end
endtask

sramc_top   u_sramc_top(                 
          .hclk           (hclk      ),    //input
          .sram_clk       (sram_clk   ),   //input
          .hresetn        (hresetn    ),   //input
          .hsel           (hsel       ),   //input
          .hwrite         (hwrite     ),   //input
          .htrans         (htrans     ),   //input [1:0]
          .hsize          (hsize      ),   //input [2:0]
          .hready         (hready     ),   //input
          .haddr          (haddr      ),   //input [31:0]
          .hwdata         (hwdata     ),   //input [31:0]
          .hrdata         (hrdata     ),   //output [31:0]
          .hready_resp    (hready_resp),   //output           
          .hresp          (hresp      ),   //output [1:0]   
             
          .hburst         (3'b0),      	   //burst没用的话就接0,在tr里面激励产生什么都关系不大了              
          .dft_en         (1'b0),      	   //不测    dft不测,写成0        
          .bist_en        (1'b0),          //不测
          .bist_done      ( ),             //不测              
          .bist_fail      ( )          	   //不测
);

endmodule

2、仿真

simulation

  • 18
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
SRAM, short for Static Random Access Memory, is a type of memory that retains data as long as power is supplied to it. Verilog is a hardware description language widely used in electronic design automation to model and simulate digital systems. To implement an SRAM module in Verilog, you can define a module with input and output ports for address, data, read/write control signals, and power supply. Here's an example of a basic 1-bit SRAM module: ```verilog module sram_1bit ( input wire clk, input wire enable, input wire write, input wire [7:0] address, input wire [7:0] data_in, output reg [7:0] data_out ); reg [7:0] memory [255:0]; // 256x8 memory array always @(posedge clk) begin if (enable) begin if (write) memory[address] <= data_in; else data_out <= memory[address]; end end endmodule ``` In this example, the SRAM module has a clock input (`clk`), an enable signal (`enable`) to enable the memory operation, a write signal (`write`) to select read or write operation, an address bus (`address`) to specify the memory location, a data input bus (`data_in`) for write operations, and a data output bus (`data_out`) for read operations. The internal memory array is declared as `reg [7:0] memory [255:0]`, representing a 256x8 memory. The data is stored or retrieved from the memory array based on the control signals and address. Note that this is a simplified example demonstrating the basic structure of an SRAM module in Verilog. In practice, you may need to add additional features like timing control, address decoding, and more robust error handling.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Iceeeewoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值