• AMBA总线协议之AHB学习记录(1)—ahb_bus(附verilog代码)


     

    0.前言

    前段时间粗略过了一下riscv指令集相关内容,并对开源项目tinyriscv进行了一些学习,主要是对cpu指令集架构有个感性认识。最近在学习soc中amba总线协议相关内容,本着不能只输入不输出的原则,打算通过公众号做一下学习记录。
    目前是打算先学习,然后独立写一个小项目:
    master1(假装它是个CPU)控制DMA实现两个SRAM的数据搬运,所以需要两个master(CPU、DMAC)和三个slave(SRAMC1、SRAMC2、DMAC),slave地址范围我是这样定义的:
    在这里插入图片描述

    DMAC(DMA Controller)既做master又是一个slave。这篇文章先记录目前的学习进度:ahb_bus(我把它叫做ahb_connect)的rtl级实现。其中所有代码都会开源在个人gitee账户上。

    1.AHB简介

           
    (1)基于AMBA总线的架构图

    在这里插入图片描述
           
    (2)基本特性
    ①支持Burst传输;
    ②支持Split事务处理;
    ③无三态(ASB有三态);
    ④单一时钟沿操作(上升沿,ASB支持双边沿);
    ⑤更宽的数据总线配置(64/128 bits);
    ⑥流水线操作(第一个时钟传地址,第二个时钟传数据,同时传下一次地址);
    ⑦支持多个总线主设备(最多16个,master越多IO资源用的越多)。
           
    (3)AHB组成
    AHB总线支持多个主设备、多个从设备同时挂载在总线上,通过寻址方式。从我理解上来说我把一个完整的ahb系统分成ahb_master、ahb_connect、ahb_slave。画了个图
    在这里插入图片描述

    看着挺复杂但是master和slave的接口是一样的。ahb_connect就是ahb_bus了,连接主、从设备之间的数据交换。

    (4)AHB信号
    在这里插入图片描述
    在这里插入图片描述

    各个信号是干什么的,从下一节理解起来比较轻松。
           

    2.ahb_bus实现(verilog)

           AHB信号从模块角度更好理解,HCLK全局时钟信号,AHB规定上升沿进行操作,HRESETn表示低电平有效,n=negedge。这需要将ahb_connect模块进一步划分:

    ahb_connect = ahb_arbiter + ahb_mux + ahb_decoder
            即ahb_connect是由一个仲裁器arbiter、一个多路选择器mux、一个译码器decoder。理解了各个模块的信号以及通信的过程,总模块的信号就...         a.ahb_arbiter        有很多主设备和很多从设备,但是同一时刻只能一个主设备和一个从设备来通过总线进行通信。那么哪个主设备来使用?和哪个从设备进行通信?

           HBUSREQx1是master1申请总线信号,HGRANTx1为高表示总线权限授权给master1,HMASTER是需要split事务的时候传给具有split功能的slave的,但是我没有用到这样的slave,所以这个信号其实是不需要的。但是我还是写了,我用它是传给mux判断哪个主设备被授权了。

    实现核心代码 & rtl模块图如下
    在这里插入图片描述

           
           对主设备的授权是比较简单的,有一个申请就授权,两个master的申请信号都为高就先判断是同时申请还是本来有个申请到了,另一个过来抢占,如果是抢占,我用了一种简单的方法,等待(但是ahb总线是支持总线抢占的),如果是同时申请,授权给master1(我令CPU优先级高)。
    在这里插入图片描述

    关于arbiter涉及到的信号还有以下:
    HLOCKx:master发出此信号表示不想被抢占总线,我设计时默认让其他申请的master等待,因此没有用到此信号;
    HMASTERLOK & HSPLIT:需要slave具有分块能力,没用到。
           
    b.ahb_decoder
    decoder译码模块的功能简单,arbiter授权某个master后,mux多路选择模块将master输入的HADDRx1、HADDRx2等信号对应复制给HADDR,之后译码器它是根据主机想要建立从机的通信地址,来给对应的slave选通信号HSEL。
    实现核心代码 & rtl模块图如下
    在这里插入图片描述

    在这里插入图片描述

    c.ahb_mux
           mux我把它分为四个部分,有一个是地址mux,一个是控制mux,一个是写数据mux,一个是读数据mux。
           上述AHB特性饿流水线想必各位还有印象,说的是第一个周期写地址,第二个周期写数据,同时写下一个地址。当一个master掌管总线后,它首先要干的事就是发送一堆东西:首先地址HADDRx1(表示master1发送的HADDR),表示我想找地址为HADDRx1的slave通信;假定是slave1吧;
           然后是一些控制信号:传输类型HTRANSx1、传输方向HWRITEx1(1表示master向slave写数据,0表示从slave读数据)、每一个传输的数据大小HSIZEx1、以及burst类型HBURSTx1;
           然后slave当前能传输数据的时候把它的HREADYx1(表示slave1的HREADY)信号拉高;
           然后master接收到HREADY信号知道了slave1能通信,然后发送数据HWDATAx1;或者接收数据HRDATA;
           最后传输完之后slave发送HRESPx1响应信号。

           那么问题来了,虽然master1和slave1在通信,master2和slave2比较调皮,你master1发HADDR,叫HADDRx1,那我master2我也要发,我发个HADDRx2吧,这时候ahb_connect应该选哪个呢?这就是mux的作用了。
           mux从arbiter知道了HGRANTx1为高,说明master1被授权,那我多路选择器你俩HADDRx1、HADDRx2都输入进来,那我就把HADDRx1赋值给HADDR。其他同理。

    总结如下
    地址信号mux:把master的地址信号HADDRx1选择正确的送到slave;
    控制信号mux:把master的控制信号HTRANSx1、HWRITEx1、HSIZEx1以及HBURSTx1选择正确的送到slave;
    写数据mux:把master的写数据值HWRITEx1选择正确的送到slave;
    读数据mux:把slave读出的数据值HRDATAx1选择正确的送到master。

    实现核心代码 & rtl模块图如下
    在这里插入图片描述
    在这里插入图片描述

           
    对传输类型HTRANS、每次传输位宽HSIZE以及burst类型HBURST信号补充如下
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

           至此,AHB的信号就清晰明了了,附一张ahb_connect顶层模块综合rtl图。
    在这里插入图片描述

           

    3.总结反思 & 后面学习计划

           有些代码设计的并不规范,比如说slave地址我直接在decoder模块里定义的,是不是设计成parameter传递参数由顶层模块定义更好?Whatever,本意就是cpu控制dma来搬运两个sram数据,所以没考虑后面的可拓展性,下次注意。

           本次学习没有涉及具体的几种传输方法的读写时序,也还没有对ahb_connect进行testbench仿真,接下来就是结合传输时序对几种传输方法进行学习,然后完成对ahb_connect的仿真,没问题之后就继续后续SRAMC和DMAC的编写。如果后续仿真发现已经写的模块存在问题的话会特别说明。

           如果有可能的话后期会拿这个修改来做我基于riscv指令集架构的soc的总线(但是AMBA总线好吃资源啊啊啊啊啊啊啊啊啊啊啊!)走一步看一步吧。

     
     

  • 相关阅读:
    现在学Oracle是49年入国军么?
    Flutter开发桌面应用的一些探索分享
    【软件测试】LoadRunner与JMeter工具安装教程
    手把手教你做测开:开发Web平台之用户信息
    Linux内核驱动开发的需要掌握的知识点
    给容灾找对象!数据流转更自由,拓宽云上更多场景
    docker启动mysql服务
    C# 删除图片,不影响程序运行
    一文掌握根轨迹法
    10.第十部分 Scrapy框架
  • 原文地址:https://blog.csdn.net/weixin_43894786/article/details/127658820