0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何根据自己设计中的寄存器配置总线定义来生成一套寄存器配置模版

Spinal FPGA 来源:Spinal FPGA 2024-03-04 13:56 次阅读

编 者 按

无论是FPGA还是ASIC,系统设计中总会存在配置寄存器总线的使用,我们会将各种功能、调试寄存器挂载在寄存器总线上使用。在SpinalHDL中,BusIf那套总线模型库写的还是相当不错的,能够同时生成对应的代码和文档(在公司里也做过一些修改,能够直接生成整个系统的寄存器文档而不仅仅是单个模块的寄存器文档)。今天就手把手来基于SpinalHDL中的BusIf来看如何根据自己设计中的寄存器配置总线定义来生成一套寄存器配置模版。

HPI总线

今天以下面一套简单的寄存器总线为例进行设计:

caseclass Hpi(addrWidth:Int,dataWidth:Int,useStrb:Boolean) extends Bundle with IMasterSlave {
val wr,rd=Bool()
val addr=UInt(addrWidth bits)
val wdata=Bits(dataWidth bits)
val strb= useStrb generate(Bits(dataWidth/8bits))
val rvalid=Bool()
val rdata=Bits(dataWidth bits)

overridedef asMaster(): Unit = {
out(wr,rd,addr,wdata)
in(rvalid,rdata)
if(useStrb) out(strb)
}
}

HPI总线很简单,wr用于标识写指令、rd用于标识读指令。addr用于指示读/写地址。wdata用于输入待写入的数据。strb如果使能则用于标识对应写指令的位选信号。而rvalid则用于指示读返回数据有效,rdata则表示读返回数据(这里就不画时序图了)。

设计一套自己的HpiInterface

针对上面的HPI总线,这里我们基于BusIf设计一套自己的配置寄存器总线模板。

BusIf都做了什么

对于寄存器配置总线,其总线信号定义,协议交互定义总是各有千秋的,BusIf无法对寄存器配置总线的这些定义做提前预知。然而对于寄存器配置总线的用途,则相对明确,无非就是实现不同数据类型(像UVM中定义的寄存器模型)的读写操作。那么,当我们基于BusIf定义一套自己的配置寄存器模板时,所需要做的就无非是:

实现配置寄存器交互协议的逻辑实现

告诉BusIf如何什么情况下触发了某个寄存器的读/写操作

HpiInterface

这里先贴上一个完整的代码,随后进行逐行解析

faef404e-d8a9-11ee-a297-92fbcf53809c.png

这里我们定义的寄存器总线相对来讲较为简单,故只有30~31行是用来进行配置寄存器总线协议时序的处理的。

line3

override defgetModuleName:String = moduleName.name

利用隐式参数获取模块名,BusIf中并无显示使用。

line5~6

override defwriteAddress():UInt = bus.addr
override defreadAddress():UInt = bus.addr

这里用来告知BusIf配置寄存器总线的写地址,读地址分别是什么,在HPI总线中均为bus.addr

line8~9

override defreadHalt():Unit = {}
override defwriteHalt():Unit = {}

这里用来填写发生读阻塞或者写阻塞时的响应动作,HPI总线中没有阻塞的概念,直接不做任何处理即可(由于配置寄存器总线接口层协议我们会自己实现,BusIf中当前版本内部无使用的地方,故直接填空即可)。

line11

override defbusDataWidth:Int = bus.dataWidth

这里用来告知BusIf配置寄存器总线的数据位宽

line13~18

override val withStrb:Boolean = bus.useStrb
val wstrb:Bits = withStrb generate(Bits(strbWidth bit))
val wmask: Bits = withStrb generate(Bits(busDataWidth bit))
val wmaskn: Bits = withStrb generate(Bits(busDataWidth bit))
initStrbMasks()
if(bus.useStrb){wstrb:=bus.strb}

这里用于设置配置寄存器总线是否有使用掩码功能。line13用于告知BusIf是否使用掩码,而line14~17则是一套针对掩码的BusIf设置(直接copy即可)。在line18行如果使能了掩码功能,则通过用bus.strb来驱动 wstrb来告知BusIf配置寄存器总线对应的写掩码。

line20~26

overrideval askRead: Bool = bus.rd
overrideval askWrite: Bool = bus.wr
overrideval doWrite: Bool = bus.wr
overrideval doRead: Bool = bus.rd
overrideval readData: Bits = Bits(bus.dataWidth bits)
overrideval writeData: Bits =bus.wdata
overrideval readError: Bool = Bool()

askRead:告知BusIf什么情况下配置寄存器产生了读请求(如果总线类型是Stream那种握手型的,则只需填valid即可,可参照regif下的AxiLite4BusInterface)。在当前版本中,askRead在BusIf中并未有使用

askWrite:告知BusIf什么情况下配置寄存器产生了写请求,同上

doWrite:告知BusIf当前时钟是否出发了寄存器写操作

doRead:告知BusIf当前时钟是否发生了寄存器读操作

readData:为BusIf声明一个对应总线数据位宽的信号,BusIf会将读结果返回到当前信号上。

writeData:告知BusIf如果发生写数据,写入的数据是什么

readError:声明一个Bool类型,BusIf会将是否有读错误发生通过该信号进行表示。

line28

setReservedAddressReadValue(BigInt("deaddead",16))

此处用于设置当总线读了未使用的地址时,应当返回何值。当然也可以不必在这里进行统一设置,可以在真正的例化位置为每个模块设置一个不同的值。

line30~31

bus.rdata:=RegNext(readData)
bus.rvalid:=RegNext(bus.rd,False)

该处则用于处理Hpi总线的协议时序,我们仅需处理接口层面上的时序即可。

使用HpiInterface

定义好之后,使用就和regif文档里的例子一样了,下面给出一个例子:

fafef476-d8a9-11ee-a297-92fbcf53809c.png

这里定义了data0,data1,data2三个寄存器。data0,data1可读可写,data2只读。

值得注意的是这里针对data0,data1采用了不同形式的API,对于data0,使用field来注册会生成reg0_data0,其是带有复位处理的,这里不希望其有复位逻辑,故这里添加了removeInitAssignments()

DIY时间

来看下在BusIf中针对读逻辑是怎么处理的:

fb19a42e-d8a9-11ee-a297-92fbcf53809c.png

从FPGA的角度来看的话,这个askRead判断是没有必要,徒增延迟,看起来不那么优雅,而且在Hpi总线使用时往往是要求地址按位宽对齐的,所以完全可以将地址判断抹去低比特,由于这里readGenerator定义成了private,外部无法重载,这里给出一个在HpiInterface中进行DIY的例子:

val discardAddrWidth = log2Up(busDataWidth / 8)

def hitDoWriteOverride() = {
orderdRegInsts.foreach(regInst => {
regInst.hitDoWrite.removeAssignments()
regInst.hitDoWrite := writeAddress()(bus.addrWidth - 1downto discardAddrWidth) === regInst.addr / (busDataWidth / 8) && doWrite
})
}

def reworkReadGenerate() = {
readError.removeAssignments()
readData.removeAssignments()
switch(readAddress()(bus.addrWidth - 1downto discardAddrWidth)) {
orderdRegInsts.foreach(regInst => {
if(!regInst.allIsNA) {
is(regInst.addr / (busDataWidth / 8)) {
readData := regInst.readBits
readError := Bool(regInst.haveWO)
}
}
})
default{
readData := getReservedAddressReadValue
readError := True
}
}
}

component.addPrePopTask(() => {
hitDoWriteOverride()
reworkReadGenerate()
})

这里对读和写均做了一些优化。对于写操作进行地址判定时将会抹去地址相应地比特的判断。而对于读操作,也会抹去相应地址位,同时也删除了askRead的判断。

感兴趣的小伙伴可自行扩展定制,比如将HPI的读返回拆成两排分级译码以获取更好的时序等等。



审核编辑:刘清
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1602

    文章

    21320

    浏览量

    593192
  • 寄存器
    +关注

    关注

    30

    文章

    5028

    浏览量

    117719
  • UVM
    UVM
    +关注

    关注

    0

    文章

    181

    浏览量

    18964
  • HPI
    HPI
    +关注

    关注

    0

    文章

    30

    浏览量

    14378

原文标题:手把手创建自己的寄存器配置模版

文章出处:【微信号:Spinal FPGA,微信公众号:Spinal FPGA】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    关于ARM编程寄存器配置的问题

    学习ARM不久,感觉实现些功能需要配置读写很多寄存器自己记性又不太好,用的不熟的话,总是要翻着别人的或者官方的例程,根据别人的
    发表于 09-05 14:12

    TI lmx2594配置寄存器代码实现

    如何编写LMX2594配置寄存器,不采用TI官方的软件生成寄存器自己如何实现生成
    发表于 11-05 19:25

    怎样去配置FMC总线寄存器

    目录1、硬件2、初始化时序3、配置FMC总线寄存器3.1 控制寄存器3.2 时序寄存器3.3 命令寄存
    发表于 01-26 07:35

    ARM I2C 总线接口的寄存器设置

    ARM I2C 总线接口的寄存器设置 控制ARM 12C总线接口需要配置总线控制寄存器(rII
    发表于 03-14 18:00 1650次阅读

    寄存器,寄存器是什么意思

    寄存器,寄存器是什么意思 寄存器定义  寄存器是中央处理器内的组成部分。寄存器是有限存贮容量
    发表于 03-08 14:26 2.1w次阅读

    MAXQ3180入门:寄存器配置

    MAXQ3180入门:寄存器配置 虽然多相、多功能电能计量AFE芯片MAXQ3180具有很多配置寄存器,但仅需配置几个
    发表于 03-28 09:20 1126次阅读

    MAXQ3180入门:寄存器配置

    MAXQ3180入门:寄存器配置 虽然多相、多功能电能计量AFE芯片MAXQ3180具有很多配置寄存器,但仅需配置几个
    发表于 03-28 09:20 834次阅读

    MPC860寄存器配置

    MPC860 的系统接口单元(SIU)控制系统启动、初始化、运行、保护和外部系统总线。这些功能是靠许多寄存器实现的。这篇文档将详细说明各个寄存器配置情况。
    发表于 06-08 17:54 53次下载
    MPC860<b class='flag-5'>寄存器</b><b class='flag-5'>配置</b>

    SC130GS寄存器配置问题

    思特威的sensor芯片SC130GS在配置寄存器的时候需要注意,如果配置了0103寄存器的bit[0]位,在IIC写数据的时候会出现没有ACK的现象,原因是这个0103
    发表于 01-24 09:23 2623次阅读

    STM32 I/O口配置寄存器

    如下表新手看这个图 还是很懵的,CNF1/CNF0; MODE1/MODE0;PxODR寄存器这些是什么?答案是:控制I/O的寄存器。第二:STM32 I/O口寄存器STM32 每个I/O 都由7个
    发表于 11-15 12:51 17次下载
    STM32 I/O口<b class='flag-5'>配置</b>和<b class='flag-5'>寄存器</b>

    IO口配置常用的8个寄存器 1.6

    IO 配置常用的 8 个寄存器: MODER、OTYPER、OSPEEDR、PUPDR、ODR、IDR 、AFRH 和 AFRL。MODER 寄存器(输入状态寄存器):STM32F4
    发表于 11-29 13:51 10次下载
    IO口<b class='flag-5'>配置</b>常用的8个<b class='flag-5'>寄存器</b> 1.6

    GPIO寄存器

    每组IO口有10个寄存器组成,如果芯片有GPIOA~GPIOI,9个组那么一共有90个寄存器如果配置一个IO口需要2个位,那么刚好32位寄存器配置
    发表于 12-08 17:06 5次下载
    GPIO<b class='flag-5'>寄存器</b>

    STM32寄存器点灯

    配置寄存器使STM32最小系统板上的LED灯点亮根据原理图,要使D2点亮,需要将PC13拉低,分为以下步骤:使能GPIO的时钟配置GPIO13为输出模式
    发表于 12-08 17:21 3次下载
    STM32<b class='flag-5'>寄存器</b>点灯

    配置STM32寄存器控制GPIO点亮LED

    STM32点亮LED 寄存器方式IO简介1、每个IO可以自由编程,但是IO口寄存器必须按照32位字被访问。2、每个IO端口都有7个寄存器来控制。CRL 【0-7】端口配置
    发表于 01-13 16:15 3次下载
    <b class='flag-5'>配置</b>STM32<b class='flag-5'>寄存器</b>控制GPIO点亮LED

    振弦采集模块配置工具VMTool生成寄存器

    振弦采集模块配置工具VMTool生成寄存器
    的头像 发表于 01-16 10:45 476次阅读
    振弦采集模块<b class='flag-5'>配置</b>工具VMTool<b class='flag-5'>生成</b><b class='flag-5'>寄存器</b>值