深入理解AMBA总线(九)AHB2SRAM设计

简介: 深入理解AMBA总线(九)AHB2SRAM设计

本篇文章给大家讲解AHB2SRAM的设计,它的作用是通过AHB接口去访问SRAM,实际上我们可以将它理解成AHB协议到SRAM的native接口的协议转换,和之前讲的apb2reg是差不多的。

设计一个东西之前首先思考一下,为什么需要这个东西?我们直接用SRAM不可以吗?还真的不可以,因为前面讲过,我们设计的SoC主体其实是基于AHB和APB总线。普通的SRAM无法直接连在AHB总线上,必须通过ahb2sram这个模块完成协议转换,才可以连接SRAM。其实SoC设计很多时候都是做这种工作,给IP做一个AHB/AXI/APB的wrapper,然后像连连看一样,把对应的信号连接即可。

1、AHB2SRAM模块简介

我们要设计的模块为紧耦合SRAM(Tightly coupled memory),不考虑等待延迟,默认一拍回数据,不考虑出错。且只支持32bit位宽的SRAM。支持按字节写,该模块除了用在IC设计中,也可以用在FPGA设计中,因为一般FPGA提供的MIG,只支持AXI或者native接口,这种情况下还是需要AHB2SRAM这个模块完成协议转换的。

我们看一下接口,非常直观,一边是AHB接口,一边是SRAM的native接口。该模块实际就是完成协议的转换。

我们要设计的AHB2SRAM的规格说明如下:

  • 完成AHB接口与SRAM接口的时序转换;
  • 支持字节、半字、字的读写操作;
  • 支持先写后读(不支持同时读写,单端口SRAM),并且读写地址相同的时候,读数据的拼接以及更新(比如对addr1进行写操作,写数据data1,下一拍马上就需要读,这个时候需要靠一个buffer,把上一拍写的数据data1作为这一拍读回的数据,因为data1有可能还没有写进SRAM);

2、AHB读写时序和SRAM读写时序

我们分别看一下两端的读写时序,这样就清楚怎么做相应的协议转换了(做任何协议的转换都是如此,要弄清楚两边各自的协议)。

2.1、AHB读时序

  • 第一拍给出读写控制以及地址信号;(CTRL包括了HTRANS和其它的一些控制信号,这里简化了,大家理解意思就行)
  • 当没有HREADY反压的时候,第二拍得到读数据信号;
  • 当有HREADY反压的时候,第2拍以后的某一拍HREADY为高的时候,说明此时HRDATA有效,得到读数据信号;

2.2、AHB写时序

  • 第一拍给出读写控制以及地址信号;
  • 第二拍给出写数据信号;

2.3、SRAM读时序

  • SRAMCS是片选信号,chip select,只有为高的时候SRAM才会真正的工作;
  • 第一拍给出读写控制,地址信号;
  • 第二拍给出读数据信号;(不考虑反压和错误的情况下,和AHB一模一样)

2.4、SRAM写时序

  • 第一拍同时给出写控制,地址,数据信号;(和AHB不一样!)

2.5、AHB2SRAM的时序转换

可以分为以下的情况:

  • 全部是读的情况:这种情况非常简单,因为本身二者就相同,第一拍给地址和控制信号,第二拍回数据,大家看下波形肯定可以理解,就不详细讲了。

  • 全部是写的情况:由于SRAM的写操作命令地址和数据是在一拍完成的,而AHB写数据要在第二拍才能写入,所以需要将AHB中的地址延迟一拍再与SRAM中的地址进行同步,这样地址数据就满足了sram接口要求

  • 先读后写:先读后写实际上不涉及数据更新,就是写跟在读后面而已,下面时序稍微有点问题,对于读这一部分ADDR和DATA。AHB和SRAM两侧应该是同一拍的。

  • 先写后读:相对来说最复杂的一种情况,当读写地址相同的时候,需要完成读数据的拼接以及更新。
  • 首先我们要判断是否是先写后读我们需要把写的控制信号打一拍。如果这一拍是读,上一拍是写同时满足,则说明出现了先写后读。buf_pend代表buffer write data valid。为什么需要这个呢?可能是先写后读再读,这个时候可能也还没有写进去,但是我们也认为是先写后读。当然也包括先写后读后读读读。。。过会看代就一目了然了
  • 然后我们判断是否读写地址相同,这个就相对简单了。上一拍的地址和这一拍的地址相同,则代表读写地址相同。

  • 接下来我们就可以对读数据更新,可以看到如果buf_hit并且buf_we有效,则代表上一拍确实写了这个字节,这种情况下我们就应该把这一字节替换成上一拍写的值,而不是用SRAM读出来的值。

接下来我们看先写后读的时序情况,可以看到addr2这个地址是先写后读。可以看到buf_data_en和~HWRITE都为1,则代表出现了先写后读。可以将buf_data_en拉高。并且地址也相同,因此buf_hit也会拉高。这个时候HRDATA返回的数据就应该是完成替换以后的值。这个时序图应该还是比较清晰的,大家好好理解一下。

需要注意的是,addr2写操作不会在下一拍就写进去SRAM,因为出现了先写后读,这个写SRAM的操作会被暂时的pending住!当addr3来的时候,这个时候addr对应的data2才能够写进去。大家看后面的代码就知道了。

3、AHB2SRAM代码

完整代码链接在下:

https://link.zhihu.com/?target=https%3A//github.com/sergeykhbr/arm_vhdl/blob/master/rtl/armlib/periph/cmsdk_ahb_to_sram.v

首先我们看控制信号:我直接在代码后面注释,大家结合着看即可。

wire        ahb_access   = HTRANS[1] & HSEL & HREADY; //HTRANS为1表示连续或者非连续传输,HSEL拉高代表发起传输
   wire        ahb_write    = ahb_access &  HWRITE;      //写控制信号
   wire        ahb_read     = ahb_access & (~HWRITE);    //读控制信号
   // Stored write data in pending state if new transfer is read
   //   buf_data_en indicate new write (data phase)
   //   ahb_read    indicate new read  (address phase)
   //   buf_pend    is registered version of buf_pend_nxt
   //发生了先写后读的情况,注意buf_pend或buf_data_en
   //意味着如果是先写后读再读,也会拉高buf_pend_nxt,当然再读也是一样的会拉高。
   wire        buf_pend_nxt = (buf_pend | buf_data_en) & ahb_read;
   // RAM write happens when
   // - write pending (buf_pend), or
   // - new AHB write seen (buf_data_en) at data phase,
   // - and not reading (address phase)
   //注意,buf_data_en是ahb_write打了一拍,按照之前的逻辑设计。我们写操作控制信号本身就需要打一拍,并且新来的一拍不能是读
   //如果新来的一拍是读,上一拍是写,那么就是先写后读,这个时候会一直不写,直到新来的也是写,这个才能真正的写进去SRAM
   //所以也叫buf_pend,意思为暂停,因此是buf_pend和buf_data_en相或。
   //为什么要这么设计呢?我也不知道,我觉得有可能是写的这个数据本身就已经存好了,暂时代替了SRAM的作用,因此没必要着急直接写
  //进去SRAM,可以节省一点逻辑资源。大家对其进行修改当然也是可以的。
   wire        ram_write    = (buf_pend | buf_data_en)  & (~ahb_read); // ahb_write
   // RAM WE is the buffered WE
   assign      SRAMWEN  = {4{ram_write}} & buf_we[3:0];
   // RAM address is the buffered address for RAM write otherwise HADDR
   assign      SRAMADDR = ahb_read ? HADDR[AW-1:2] : buf_addr;
   // RAM chip select during read or write
   assign      SRAMCS   = ahb_read | ram_write;

然后我们看一下读回数据的情况,这个实际上和上面的电路图保持一致。当buffer_hit即读写地址相同,并且上一拍真的写进去了。就用写的数据代替从SRAM回来的数据作为读回数据即可。

wire [ 3:0] merge1  = {4{buf_hit}} & buf_we; // data phase, buf_we indicates data is valid
   assign HRDATA =
              { merge1[3] ? buf_data[31:24] : SRAMRDATA[31:24],
                merge1[2] ? buf_data[23:16] : SRAMRDATA[23:16],
                merge1[1] ? buf_data[15: 8] : SRAMRDATA[15: 8],
                merge1[0] ? buf_data[ 7: 0] : SRAMRDATA[ 7: 0] };

剩下的代码比较简单,大家直接去看源码即可,有不懂的可以问我。

欢迎和我一起学习AMBA总线,完整的专栏在这里:

https://www.zhihu.com/column/c_1663245806869291008

目录
相关文章
|
XML 数据格式 SoC
深入理解AMBA总线(十)AHB Bus Matrix以及AHB的局限性
深入理解AMBA总线(十)AHB Bus Matrix以及AHB的局限性
769 0
|
存储 安全
深入理解AMBA总线(四)AHB-lite总线
深入理解AMBA总线(四)AHB-lite总线
1162 0
|
芯片
深入理解AMBA总线(一)APB总线入门(上)
深入理解AMBA总线(一)APB总线入门
1097 0
|
存储 网络性能优化 vr&ar
深入理解AMBA总线(十七)AXI是如何提高性能的
深入理解AMBA总线(十七)AXI是如何提高性能的
2097 1
|
安全 物联网 数据安全/隐私保护
深入理解AMBA总线协议(AXI总结篇)
深入理解AMBA总线协议(AXI总结篇)
1596 1
|
vr&ar 内存技术
深入理解AMBA总线(十八)一个简单的AXI2SRAM设计
深入理解AMBA总线(十八)一个简单的AXI2SRAM设计
629 0
深入理解AMBA总线(一)APB总线入门(下)
深入理解AMBA总线(一)APB总线入门(下)
942 0
|
缓存 SoC
深入理解AMBA总线(八)AHB2APB同步桥设计
深入理解AMBA总线(八)AHB2APB同步桥设计
777 0
第 2 章 微处理器与总线
第 2 章 微处理器与总线
183 1