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
    +关注

    关注

    1628

    文章

    21711

    浏览量

    602769
  • 寄存器
    +关注

    关注

    31

    文章

    5332

    浏览量

    120197
  • UVM
    UVM
    +关注

    关注

    0

    文章

    181

    浏览量

    19161
  • HPI
    HPI
    +关注

    关注

    0

    文章

    35

    浏览量

    14511

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

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

收藏 人收藏

    评论

    相关推荐

    怎样去配置FMC总线寄存器

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

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

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

    MAXQ3180入门:寄存器配置

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

    MPC860寄存器配置

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

    寄存器的使用技巧及定义

    寄存器是中央处理内的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。在中央处理的控制部件,包含的
    发表于 09-12 16:16 2次下载
    <b class='flag-5'>寄存器</b>的使用技巧及<b class='flag-5'>定义</b>

    采用PCI9052芯片的配置寄存器及加载其驱动程序的开发

    的大小为256字节,分为头标区和设备有关区。直接影响设备特性的配置寄存器在头标区,其他部分则因设备而异。PCI总线配置空间通常与PCI接口芯片相关。该
    发表于 04-04 18:14 1635次阅读
    采用PCI9052芯片的<b class='flag-5'>配置</b><b class='flag-5'>寄存器</b>及加载其驱动程序的开发

    GC1064寄存器配置参考文件下载

    GC1064寄存器配置参考文件下载
    发表于 05-21 16:17 9次下载

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

    IO,分别用大写字母表示,即 x=A/B/C/D/E/F/G/H/I,端口X配置位0~15。OTYPER 寄存器,该寄存器仅用于输出模式,在输入模式(MODER[1:0]=00/11 时)下不起作用。该
    发表于 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>点灯

    2021-04-17 STM32串口寄存器库函数配置

    STM32串口寄存器库函数配置方法STM32常用寄存器和库函数串口配置般步骤(串口实例)常用的串口相关
    发表于 12-28 19:13 7次下载
    2021-04-17  STM32串口<b class='flag-5'>寄存器</b>库函数<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

    如何在VHDL实现个简单的寄存器

    存储的位数上有所不同,具体取决于系统的配置。在本教程,我们将学习如何在 VHDL 实现个简单的寄存器
    发表于 07-29 16:48 4600次阅读
    如何在VHDL<b class='flag-5'>中</b>实现<b class='flag-5'>一</b>个简单的<b class='flag-5'>寄存器</b>

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

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

    寄存器分为基本寄存器和什么两种

    寄存器是计算机中用于存储数据的高速存储单元,它们是CPU内部的重要组成部分。寄存器可以分为基本寄存器和扩展寄存器两种类型。 、基本
    的头像 发表于 07-12 10:31 1260次阅读