• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

AHB 总线的 SRAM 控制器设计

武飞扬头像
Iceeeewoo
帮助1


一、基于 AHB 的 sram 设计

1、总体设计框架

学新通

2、AHB总线传输协议

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

学新通

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

学新通

③连续读写操作

学新通

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

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

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

学新通

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

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

学新通

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

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

学新通

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

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

学新通

三、程序设计

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、仿真

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgkiijh
系列文章
更多 icon
同类精品
更多 icon
继续加载