设计代码理解
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