AHB RAM验证【一】

发布时间 2023-08-05 22:33:15作者: Fireworks、

设计代码理解

AHBRAM是一个以AHB协议通信的RAM存储模块。RAM内部含有4块BRAM模块,每块BRAM均能存储8bit的数据,存储空间为16KB,整块RAM存储空间为64KB。通过AHB协议对RAM进行写操作时,根据接口上传输位宽和传输地址逻辑判断后,使能对应的BRAM块,并存入数据;通过AHB协议对RAM进行读操作时,根据接口上传输地址,对4个BRAM模块相应地址的数据进行拼接并读出。

其中,通信协议AHB采用了简化版:
1、只有一个master和一个slave,hgrant = 1;
2、模块预置条件:每次传输均正确且传输完成,hready = 1,hresp = okay;
3、单时钟沿变化;
4、支持burst传输,但只考虑single传输,即hburst = single,htrans = idle / Nonseq两种状态;
5、burst传输支持最大位宽为32bit。

AHB总线传输数据位宽有8/16/32(HSIZE[1:0]:00-8bits,01-16bits,10-32bits),而ram不一定支持(这里每个ram支持数据位宽为8位),所以用了4块ram,每块ram对应一个byte。
当AHB传来8bit数据时,可以选择四个ram中的任何一个进行存放;传来16bit数据时,可以选择BRAM0/1或者BRAM2/3这两种组合进行存放;传来32bit时,BRAM0~3依次存放第1-4byte。
增加一个输入信号HSELBRAM——该信号控制使能ram块。
存储器写入控制信号reg_wr_en[3:0]由下一次写入使能信号nxt_wr_en[3:0]赋值得到,决定要将数据写进哪个ram中。

存储单元定义

parameter ADDRESSWIDTH = 14;
parameter AW = (ADDRESSWIDTH - 1);
parameter AWT = ((1<<(AW-1))-1);

reg     [7:0] BRAM0 [0:AWT];
reg     [7:0] BRAM1 [0:AWT];
reg     [7:0] BRAM2 [0:AWT];
reg     [7:0] BRAM3 [0:AWT];

这里假设地址长度为14,然后用地址的低二位的四种情况00, 01, 10, 11指示一个字的4个字节, 则可用的字地址范围为[0 : 2^12-1];然后分别用4个reg类型的存储块存储一个字的四个字节.
如果是使用字节地址,则字节地址的范围响应的是[0: 2^14-1]

写入到AHB RAM

  // HTRAN[1] = 1对应NONSEQ和SEQ
  assign trn_valid = HSELBRAM & HREADY & HTRANS[1];

  assign wr_en_actv   = (trn_valid & HWRITE) | (|reg_wr_en);

  // 这里分析地址和要传输的数据长度,获知需要对字的哪几个字节做写入 
  assign nxt_wr_en[0] = (((HADDR[1:0]==2'b00) && (HSIZE[1:0]==2'b00)) ||
                         ((HADDR[1]==1'b0)    && (HSIZE[1:0]==2'b01)) ||
                         ((HSIZE[1:0]==2'b10)))? trn_valid & HWRITE : 1'b0;

  assign nxt_wr_en[1] = (((HADDR[1:0]==2'b01) && (HSIZE[1:0]==2'b00)) ||
                         ((HADDR[1]==1'b0)    && (HSIZE[1:0]==2'b01)) ||
                         ((HSIZE[1:0]==2'b10)))? trn_valid & HWRITE : 1'b0;

  assign nxt_wr_en[2] = (((HADDR[1:0]==2'b10) && (HSIZE[1:0]==2'b00)) ||
                         ((HADDR[1]==1'b1)    && (HSIZE[1:0]==2'b01)) ||
                         ((HSIZE[1:0]==2'b10)))? trn_valid & HWRITE : 1'b0;

  assign nxt_wr_en[3] = (((HADDR[1:0]==2'b11) && (HSIZE[1:0]==2'b00)) ||
                         ((HADDR[1]==1'b1)    && (HSIZE[1:0]==2'b01)) ||
                        ((HSIZE[1:0]==2'b10))) ? trn_valid & HWRITE : 1'b0;
  // 同步更新下一个周期要写入的字节位置
  always @ (negedge HRESETn or posedge HCLK)
  begin
    if (~HRESETn)
      reg_wr_en <= 4'b0000;
    else if (wr_en_actv)
      reg_wr_en <= nxt_wr_en;
  end

  // 进行写入
  always @ (posedge HCLK)
    begin
      if (reg_wr_en[0])
        BRAM0[reg_haddr] <= HWDATA[7:0];
      if (reg_wr_en[1])
        BRAM1[reg_haddr] <= HWDATA[15:8];
      if (reg_wr_en[2])
        BRAM2[reg_haddr] <= HWDATA[23:16];
      if (reg_wr_en[3])
        BRAM3[reg_haddr] <= HWDATA[31:24];
      // do not use enable on read interface.
      reg_haddr <= HADDR[AW:2];
    end

读出数据

  assign HRESP     = RSP_OKAY;
  assign HREADYOUT = 1'b1;
  assign HRDATA    = {BRAM3[reg_haddr],BRAM2[reg_haddr],BRAM1[reg_haddr],BRAM0[reg_haddr]};

大致框图

参考:
https://blog.csdn.net/weixin_41975611/article/details/129001145
https://blog.csdn.net/fenggang2333/article/details/127744888