本文记录了 SpinalHDL 中 RegIf 模块的源码阅读笔记,基于 SpinalHDL 1.11.0。
# 实现细节
该模块的代码生成主要分为两个部分:用户调用 RegInst.field*
时,创建数据写入逻辑,并在 component.addPrePopTask
中调用 readGenerator
生成数据、错误的读取逻辑及写入错误逻辑。
component.addPrePopTask(() => { | |
this.readGenerator() // 生成所有读取逻辑 | |
if(withSecFireWall) this.writeErrorGenerator() // 如果启用了安全防火墙,则生成写入错误逻辑 | |
}) |
# 写入数据
写入数据在用户调用 RegInst.field*
时按需生成。
TODO
# 读取数据及错误
读取逻辑最终生成的变量为 bus_rdata
与 reg_rderr
两个变量。其中, reg_rderr
仅会在未开启 withStrb
,且 readAddress
未对齐时,置为 True
。
readGenerator
定义在第 296 行,定义如下。该函数会优先生成寄存器及 fifo 的读取逻辑,将 reg_rdata
赋值为寄存器读取结果,然后生成 RAM 及寄存器读取逻辑,并使用 bus_rdata
输出最终的读取结果。
private def readGenerator(): Unit = { | |
this.regReadGenerator() // 生成寄存器及 fifo 的读取逻辑,将 reg_rdata 赋值为寄存器读取结果 | |
// 接下来枚举所有的 RAM,如果 RAM 被选中读取,则生成 RAM 读取逻辑,将 bus_rdata 赋值为 RAM 读取结果 | |
val mux = WhenBuilder() | |
RamInsts.foreach{ ram => | |
mux.when(ram.ram_rdvalid) { //ram_rdvalid 定义为 readAddress 在所定义的范围内,askRead 有效,且通过安全校验 | |
bus_rdata := ram.readBits | |
} | |
} | |
// 如果没有 RAM 被选中读取,则将 bus_rdata 赋值为寄存器读取结果 | |
mux.otherwise { | |
bus_rdata := reg_rdata | |
} | |
} |
regReadGenerator
定义在 296 行,定义如下。该函数会在 askRead 有效时,处理寄存器及 fifo 的读取逻辑,将 reg_rdata
赋值为寄存器读取结果。否则,会将 red_rdata
赋值为 readDefaultValue
, reg_rderr
赋值为 False
。
private def regReadGenerator() = { | |
when(askRead){ | |
regReadPart() | |
}.otherwise{ | |
// 为了避免数据泄露,在读取后,将 reg_rdata 置为默认值,reg_rderr 置为 False | |
//do not keep readData after read for the reason of security risk | |
reg_rdata := readDefaultValue | |
reg_rderr := False | |
} | |
} |
其中, regReadPart
定义在第 278 行,该函数及内部使用的相关函数的源码如下。该函数会枚举所有的寄存器和 Fifo,在 readAddress
等于该实例时,将 reg_rdata
赋值为寄存器读取结果,并在该寄存器包含 WO 属性的域时将 reg_rderr
赋值为 True
。如果没有寄存器或 Fifo 被选中读取,则将 reg_rdata
赋值为 readDefaultValue
,并在启用 withStrb
时将 reg_rderr
赋值为 False
,未启用时则将 reg_rderr
赋值为 True
。
private def regReadPart() = { | |
switch(readAddress()) { | |
RegAndFifos.foreach{ (x: RegSlice) => | |
if(!x.allIsNA) x.readGenerator() | |
} | |
default { | |
reg_rdata := readDefaultValue | |
//Reserved Address Set False, True is too much strict for software | |
if (withStrb) { | |
reg_rderr := False | |
} else { | |
val alignreadhit = readAddress.take(log2Up(wordAddressInc)).orR | |
reg_rderr := Mux(alignreadhit, True, False) | |
} | |
} | |
} | |
} | |
// RegInst.scala:392, 生成寄存器读取逻辑 | |
override def readGenerator() = { | |
is(addr) { | |
bi.reg_rdata := rdSecurePassage(this.rdata()) | |
bi.reg_rderr := rdSecureError(Bool(this.haveWO)) | |
} | |
} |
# 写入错误逻辑生成
TODO