本文作为SpinalHDL学习笔记第二十二篇,介绍SpinalHDL RegIf相关API。
SpinalHDL学习笔记总纲链接如下:
目录:
6.典型例子
7.中断生成器
8.默认读取值
6.典型例子
批量创建 REG-Address 和字段寄存器:
import spinal.lib.bus.regif._
class RegBank extends Component {
val io = new Bundle {
val apb = slave(Apb3(Apb3Config(16, 32)))
val stats = in Vec(Bits(16 bit), 10)
val IQ = out Vec(Bits(16 bit), 10)
}
val busif = Apb3BusInterface(io.apb, (0x000, 100 Byte), regPre = "AP")
(0 to 9).map { i =>
//here use setName give REG uniq name for Docs usage
val REG = busif.newReg(doc = s"Register${i}").setName(s"REG${i}")
val real = REG.field(SInt(8 bit), AccessType.RW, 0, "Complex real")
val imag = REG.field(SInt(8 bit), AccessType.RW, 0, "Complex imag")
val stat = REG.field(Bits(16 bit), AccessType.RO, 0, "Accelerator status")
io.IQ(i)( 7 downto 0) := real.asBits
io.IQ(i)(15 downto 8) := imag.asBits
stat := io.stats(i)
}
def genDocs() = {
busif.accept(CHeaderGenerator("regbank", "AP"))
busif.accept(HtmlGenerator("regbank", "Interupt Example"))
busif.accept(JsonGenerator("regbank"))
busif.accept(RalfGenerator("regbank"))
busif.accept(SystemRdlGenerator("regbank", "AP"))
}
this.genDocs()
}
SpinalVerilog(new RegBank())
7.中断生成器
手动写中断:
class cpInterruptExample extends Component {
val io = new Bundle {
val tx_done, rx_done, frame_end = in Bool()
val interrupt = out Bool()
val apb = slave(Apb3(Apb3Config(16, 32)))
}
val busif = Apb3BusInterface(io.apb, (0x000, 100 Byte), regPre = "AP")
val M_CP_INT_RAW = busif.newReg(doc="cp int raw register")
val tx_int_raw = M_CP_INT_RAW.field(Bool(), W1C, doc="tx interrupt enable␣
,→register")
val rx_int_raw = M_CP_INT_RAW.field(Bool(), W1C, doc="rx interrupt enable␣
,→register")
val frame_int_raw = M_CP_INT_RAW.field(Bool(), W1C, doc="frame interrupt enable register")
val M_CP_INT_FORCE = busif.newReg(doc="cp int force register\n for debug use")
val tx_int_force = M_CP_INT_FORCE.field(Bool(), RW, doc="tx interrupt␣
,→enable register")
val rx_int_force = M_CP_INT_FORCE.field(Bool(), RW, doc="rx interrupt␣
,→enable register")
val frame_int_force = M_CP_INT_FORCE.field(Bool(), RW, doc="frame interrupt␣
,→enable register")
val M_CP_INT_MASK = busif.newReg(doc="cp int mask register")
val tx_int_mask = M_CP_INT_MASK.field(Bool(), RW, doc="tx interrupt mask␣
,→register")
val rx_int_mask = M_CP_INT_MASK.field(Bool(), RW, doc="rx interrupt mask␣
,→register")
val frame_int_mask = M_CP_INT_MASK.field(Bool(), RW, doc="frame interrupt␣
,→mask register")
val M_CP_INT_STATUS = busif.newReg(doc="cp int state register")
val tx_int_status = M_CP_INT_STATUS.field(Bool(), RO, doc="tx interrupt␣
,→state register")
val rx_int_status = M_CP_INT_STATUS.field(Bool(), RO, doc="rx interrupt␣
,→state register")
val frame_int_status = M_CP_INT_STATUS.field(Bool(), RO, doc="frame interrupt␣
,→state register")
rx_int_raw.setWhen(io.rx_done)
tx_int_raw.setWhen(io.tx_done)
frame_int_raw.setWhen(io.frame_end)
rx_int_status := (rx_int_raw || rx_int_force) && (!rx_int_mask)
tx_int_status := (tx_int_raw || rx_int_force) && (!rx_int_mask)
frame_int_status := (frame_int_raw || frame_int_force) && (!frame_int_mask)
io.interrupt := rx_int_status || tx_int_status || frame_int_status
}
这是一项非常繁琐且重复的工作,更好的方法是使用“生成器 (factory)”范例来自动生成每个信号的文档。现在 InterruptFactory 可以做到这一点。
创建中断的简单方法:
class EasyInterrupt extends Component {
val io = new Bundle {
val apb = slave(Apb3(Apb3Config(16,32)))
val a, b, c, d, e = in Bool()
}
val busif = BusInterface(io.apb,(0x000,1 KiB), 0, regPre = "AP")
busif.interruptFactory("T", io.a, io.b, io.c, io.d, io.e)
busif.accept(CHeaderGenerator("intrreg","AP"))
busif.accept(HtmlGenerator("intrreg", "Interupt Example"))
busif.accept(JsonGenerator("intrreg"))
busif.accept(RalfGenerator("intrreg"))
busif.accept(SystemRdlGenerator("intrreg", "AP"))
}
IP 级中断生成器
寄存器 |
访问类型 |
描述 |
---|---|---|
RAW |
W1C |
中断原始状态 (int raw) 寄存器,由 int 事件设置,总线写 1 时清零 |
FORCE |
RW |
中断强制寄存器,用于软件调试 |
MASK |
RW |
中断掩码寄存器, 1:关闭; 0:打开;默认 1 中断关闭 |
STATUS |
RO |
中断状态,只读, status = raw && ! mask |
Spinal 用法:
busif.interruptFactory("T", io.a, io.b, io.c, io.d, io.e)
SYS 级中断合并
寄存器 |
访问类型 |
描述 |
---|---|---|
MASK |
RW |
中断掩码寄存器, 1:关闭; 0:打开;默认 1 中断关闭 |
STATUS |
RO |
中断状态, RO, status = int_level && ! mask |
busif.interruptLevelFactory("T", sys_int0, sys_int1)
Spinal 的生成器
总线接口方法 |
描述 |
---|---|
InterruptFactory(regNamePre: String,triggers: Bool*) |
为 脉 冲 事 件 创 建RAW/FORCE/MASK/STATUS |
InterruptFactoryNoForce(regNamePre: String, |
为 脉 冲 事 件 创 建RAW/MASK/STATUS |
InterruptFactory(regNamePre: String,triggers: Bool*) |
为 level_int 合 并 创 建MASK/STATUS |
InterruptFactoryAt(addrOffset: Int,regNamePre: String, triggers: Bool*) |
在 addrOffset 处 为 脉 冲 事 件 创 建RAW/FORCE/MASK/STATUS |
InterruptFactoryNoForceAt(addrOffset: Int, |
在 addrOffset 处 为 脉 冲 事 件 创 建RAW/MASK/STATUS |
InterruptFactoryAt(addrOffset: Int,regNamePre: String, triggers: Bool*) |
在 addrOffset 处为 level_int 合并创建MASK/STATUS |
示例:
class RegFileIntrExample extends Component {
val io = new Bundle {
val apb = slave(Apb3(Apb3Config(16,32)))
val int_pulse0, int_pulse1, int_pulse2, int_pulse3 = in Bool()
val int_level0, int_level1, int_level2 = in Bool()
val sys_int = out Bool()
val gpio_int = out Bool()
}
val busif = BusInterface(io.apb, (0x000,1 KiB), 0, regPre = "AP")
io.sys_int := busif.interruptFactory("SYS",io.int_pulse0, io.int_pulse1, io.
,→int_pulse2, io.int_pulse3)
io.gpio_int := busif.interruptLevelFactory("GPIO",io.int_level0, io.int_level1,␣
,→io.int_level2, io.sys_int)
def genDoc() = {
busif.accept(CHeaderGenerator("intrreg","Intr"))
busif.accept(HtmlGenerator("intrreg", "Interupt Example"))
busif.accept(JsonGenerator("intrreg"))
busif.accept(RalfGenerator("intrreg"))
busif.accept(SystemRdlGenerator("intrreg", "Intr"))
this
}
this.genDoc()
}
8.默认读取值
当软件读取保留地址时,当前的策略是正常返回, readerror=0。为了方便软件调试,可以配置回读值,默
认为 0。
busif.setReservedAddressReadValue(0x0000EF00)
default: begin
busif_rdata <= 32'h0000EF00 ;
busif_rderr <= 1'b0 ;
end