FAQ
一、SpinalHDL生成的RTL与手工书写VHDL/Verilog相比额外硬件开销有多少?
开销为零, 因为SpinalHDL不是HLS方法。它的目标不是将任何任意代码翻译成RTL, 而是提供一种强大的语言来描述RTL并提高抽象级别。
二、SpinalHDL未来可能会不支持吗?
这个问题有两个方面:
1). SpinalHDL生成VHDL/Verilog文件, 这意味着SpinalHDL将在几十年内得到所有EDA工具的支持。
2). 如果SpinalHDL中存在一个错误, 并且不再支持修复它, 那么这不是一个致命的情况, 因为SpinalHDL编译器是完全开源的。对于简单的问题, 你可以在几个小时内自己解决问题。请记住EDA公司在其封闭工具中修复问题或添加新功能需要多长的时间。
三、SpinalHDL生成的VHDL/Verilog是否保持备注?
不, 没有。生成的文件应视为网表。例如, 在编译C代码时, 你是否关心生成的汇编代码中的注释?
四、SpinalHDL可以扩展到大工程吗?
是的, 已经做了一些实验, 它在生成带缓存的数百个3KLUT CPU只需要12秒左右, 与模拟或综合此类设计所需的时间相比, 这是一个非常短的时间。
五、SpinalHDL如何产生的?
2014年12月至2016年4月, 这是一个个人爱好项目。但自2016年4月以来, 有一个人全职从事这项工作, 其他一些人也会定期为该项目做出贡献。
六、为什么有VHDL/Verilog/SystemVerilog还要开发新语言?
VHDL/Verilog/SystemVerilog不是硬件描述语言
这些语言最初是为仿真/文档目的创建的事件驱动语言。只是后来, 它们被用作综合工具的输入语言。这解释了本页下面许多要点的根源。
这些事件驱动范式对RTL没有任何意义
仔细想想, 用process/always块描述数字硬件(RTL)没有任何实际意义。为什么我们要担心敏感度列表?为什么我们必须在不同性质的process/always块(组合逻辑/无重置寄存器/异步重置寄存器)之间拆分设计?
等价的VHDL/SpinalHDL的例子:
VHDL:
signal mySignal : std_logic; signal myRegister : unsigned(3 downto 0); signal myRegisterWithReset : unsigned(3 downto 0); process(cond) begin mySignal <= '0'; if cond = '1' then mySignal <= '1'; end if; end process; process(clk) begin if rising_edge(clk) then if cond = '1' then myRegister <= myRegister + 1; end if; end if; end process; process(clk,reset) begin if reset = '1' then myRegisterWithReset <= 0; elsif rising_edge(clk) then if cond = '1' then myRegisterWithReset <= myRegisterWithReset + 1; end if; end if; end process;
SpinalHDL
val mySignal = Bool() val myRegister = Reg(UInt(4 bits)) val myRegisterWithReset = Reg(UInt(4 bits)) init(0) mySignal := False when(cond) { mySignal := True myRegister := myRegister + 1 myRegisterWithReset := myRegisterWithReset + 1 }
对于一切, 你都可以尝试这种事件驱动语言, 知道你尝试到更好的。
VHDL和Verilog的最新版本不可用。
EDA行业在其工具中实现VHDL 2008和SystemVerilog综合功能的速度非常慢。此外, 完成后, 似乎只实现了语言的一个约束子集(不涉及模拟特性)。这导致使用这些语言版本中任何有趣的功能都是不安全的, 因为:
这可能会使你的代码与许多EDA工具不兼容。
其他公司可能不会接受你的IP, 因为他们的流程还没有准备好。
让我告诉你, 我已经厌倦了等待昂贵的封闭源代码工具。
VHDL和Verilog的最新版本没有那么好。
请参阅VHDL 2008参数化包和无约束记录, 确保它可以编写更好的VHDL源代码, 但从面向对象的角度来看, 它们让我感到恶心(请参阅下一个主题, 了解SpinalHDL示例)。
尽管如此, 这些修订并没有改变HDL问题的核心:它们基于一种事件驱动的范式, 描述数字硬件是没有意义的。
VHDL记录(records), Verilog结构(struct)是破碎的(如果你可以使用, SystemVerilog在这方面做的很好)
你不能用它们来定义接口, 因为你不能定义它们的内部信号方向。 更糟糕的是, 你不能给他们构造参数! 所以, 定义你的 RGB 记录/结构一次, 并希望你永远不必将它与更大/更小的颜色通道一起使用……
VHDL 的另一个奇特之处在于, 如果你想将一个数组添加到一个组件实体中, 你必须将这个数组的类型定义到一个包中……它不能被参数化……
以下是SpinalHDL下APB3总线的定义:
//Class which can be instantiated to represent a given APB3 configuration case class Apb3Config( addressWidth : Int, dataWidth : Int, selWidth : Int = 1, useSlaveError : Boolean = true ) //Class which can be instantiated to represent a given hardware APB3 bus case class Apb3(config: Apb3Config) extends Bundle with IMasterSlave { val PADDR = UInt(config.addressWidth bits) val PSEL = Bits(config.selWidth bits) val PENABLE = Bool() val PREADY = Bool() val PWRITE = Bool() val PWDATA = Bits(config.dataWidth bits) val PRDATA = Bits(config.dataWidth bits) val PSLVERROR = if(config.useSlaveError) Bool() else null //Optional signal //Can be used to setup a given APB3 bus into a master interface of the host component override def asMaster(): Unit = { out(PADDR,PSEL,PENABLE,PWRITE,PWDATA) in(PREADY,PRDATA) if(config.useSlaveError) in(PSLVERROR) } }
关于VHDL2008的部分解决方法和SystemVerilog接口/模组端口, 如果你的EDA工具/公司流程/公司规定允许你使用他们, 你很幸运。
VHDL和Verilog非常冗长。
实际上, 使用VHDL和Verilog, 当它开始涉及组件实例互连时, 需要考虑复制过去的产品。
为了更深入地理解它, 有一个SpinalHDL示例, 它执行一些外围设备实例化, 并添加访问它们所需的APB3解码器。
//Instanciate an AXI4 to APB3 bridge val apbBridge = Axi4ToApb3Bridge( addressWidth = 20, dataWidth = 32, idWidth = 4 ) //Instanciate some APB3 peripherals val gpioACtrl = Apb3Gpio(gpioWidth = 32) val gpioBCtrl = Apb3Gpio(gpioWidth = 32) val timerCtrl = PinsecTimerCtrl() val uartCtrl = Apb3UartCtrl(uartCtrlConfig) val vgaCtrl = Axi4VgaCtrl(vgaCtrlConfig) //Instanciate an APB3 decoder //- Drived by the apbBridge //- Map each peripherals in a memory region val apbDecoder = Apb3Decoder( master = apbBridge.io.apb, slaves = List( gpioACtrl.io.apb -> (0x00000, 4 KiB), gpioBCtrl.io.apb -> (0x01000, 4 KiB), uartCtrl.io.apb -> (0x10000, 4 KiB), timerCtrl.io.apb -> (0x20000, 4 KiB), vgaCtrl.io.apb -> (0x30000, 4 KiB) ) )
这样, 当你实例化一个模块/组件时, 你不必逐个绑定每个信号, 因为你可以以面向对象的方式访问它们的接口。
同样关于VHDL/Verilog 的struct/records, 我只想说它们真的是肮脏的把戏, 没有真正的参数化和可重用性功能, 一些拐杖试图掩盖这些语言设计拙劣的事实。
元硬件描述的功能和能力
好的, 这是一大块。基本上, VHDL/Verilog/SystemVerilog将为你提供一些精化工具, 这些工具不会直接映射到硬件中, 例如loops/generate语句/macro/function/process/task。但仅此而已。
甚至它们也非常有限。举例来说, 为什么不能将process/alwasys/compents/module块定义为task/process?这真的是许多新奇事物的瓶颈。如果你在总线调用一个用户定义的task/procedure, 比如myHandshakeBus.quequ(depth=64)?这不是很爽吗?
//Define the concept of handshake bus class Stream[T <: Data](dataType: T) extends Bundle { val valid = Bool() val ready = Bool() val payload = cloneOf(dataType) //Define an operator to connect the left operand (this) to the right operand (that) def >>(that: Stream[T]): Unit = { this.valid := that.valid that.ready := this.ready this.payload := that.payload } //Return a Stream connected to this via a FIFO of depth elements def queue(depth: Int): Stream[T] = { val fifo = new StreamFifo(dataType, depth) this >> fifo.io.push return fifo.io.pop } }
然后让我们进一步了解, 假设你想要定义一个状态机, 你必须编写原始VHDL/Verilog和一些开关语句来完成。你不能定义一种“状态机”抽象, 这种抽象会给你一种奇特的语法来定义它们, 相反, 你必须使用第三方工具来绘制你的状态机, 然后生成与VHDL/Verilog等效的代码。这真的很乱。
因此, 所谓元硬件描述能力, 我指的是通过使用原始SpinalHDL语法, 你可以定义工具, 然后允许你以抽象的方式定义事物, 比如状态机。
这里还有一个简单的定义在顶层SpinalHDL的状态机抽象使用的例子:
//Define a new state machine val fsm = new StateMachine{ //Define all states val stateA, stateB, stateC = new State //Set the state machine entry point setEntry(stateA) //Define a register used into the state machine val counter = Reg(UInt(8 bits)) init (0) //Define the state machine behavioural stateA.whenIsActive (goto(stateB)) stateB.onEntry(counter := 0) stateB.onExit(io.result := True) stateB.whenIsActive { counter := counter + 1 when(counter === 4){ goto(stateC) } } stateC.whenIsActive (goto(stateA)) }
同样, 如果你想生成CPU的指令解码, 可能需要一些花哨的精化时间算法来生成尽可能少的逻辑。但是, 在VHDL/Verilog/SystemVerilog中, 执行此类操作的唯一选择是编写一个脚本, 生成所需的.vhd/.v。
关于元硬件描述确实有很多话要说, 但要理解它并获得它真正的味道, 唯一真正的方法是对它进行实验。它的目标是停止像猴子一样玩弄电线和门, 开始与那些低级的东西保持一定距离, 思考更大和可重用的东西。
七、如何使用未发布(但是已经提交到git)的SpinalHDL版本?
例如, 如果你想尝试dev
分支, 在dummy文件夹中做如下操作:
git clone https://github.com/SpinalHDL/SpinalHDL.git -b dev
cd SpinalHDL
sbt clean publishLocal
在你的工程中, 不要忘记更新build.sbt选定的SpinalHDL的版本, 应该是”dev”而不是”?.?.?”
支持(Support)
一、联系渠道(Communication channels)
支持错误报告和功能请求的通信渠道, 毫不犹豫地创建github问题: https://github.com/SpinalHDL/SpinalHDL/
有关SpinalHDL语法和现场对话的问题, 可以使用Gitter频道: https://gitter.im/SpinalHDL/SpinalHDL
如果问题你还可以使用带有标签StackOverflow的论坛: spinalhl:https://StackOverflow.com/
也可以通过谷歌查询。你可以随意发布与SpinalHDL相关的任何主题: https://groups.google.com/forum/#!forum/spinalhdl-hardware-description-language