spinal HDL - 06 - 例化VHDL and Verilog IP
IP and 06 Verilog VHDL
2023-09-14 09:13:04 时间
实例化VHDL and Verilog IP
blackbox允许用户通过指定其接口将现有的 VHDL/Verilog 组件集成到设计中。由模拟器或合成器来正确地进行细化。
定义blackbox
下面显示了如何定义blackbox的示例:
// Define a Ram as a BlackBox
class Ram_1w_1r(wordWidth: Int, wordCount: Int) extends BlackBox {
// Add VHDL Generics / Verilog parameters to the blackbox
// You can use String, Int, Double, Boolean, and all SpinalHDL base
// types as generic values
addGeneric("wordCount", wordCount)
addGeneric("wordWidth", wordWidth)
// Define IO of the VHDL entity / Verilog module
val io = new Bundle {
val clk = in Bool()
val wr = new Bundle {
val en = in Bool()
val addr = in UInt (log2Up(wordCount) bit)
val data = in Bits (wordWidth bit)
}
val rd = new Bundle {
val en = in Bool()
val addr = in UInt (log2Up(wordCount) bit)
val data = out Bits (wordWidth bit)
}
}
// Map the current clock domain to the io.clk pin
mapClockDomain(clock=io.clk)
}
在VHDL中类型的信号Bool
将被转换成std_logic
和Bits
成std_logic_vector
。如果你想得到std_ulogic
,你必须使用 aBlackBoxULogic
而不是BlackBox
。在 Verilog 中,BlackBoxUlogic
没有效果。
class Ram_1w_1r(wordWidth: Int, wordCount: Int) extends BlackBoxULogic {
...
}
Generics
有两种不同的方式来声明泛型:
class Ram(wordWidth: Int, wordCount: Int) extends BlackBox {
addGeneric("wordCount", wordCount)
addGeneric("wordWidth", wordWidth)
// OR
val generic = new Generic {
val wordCount = Ram.this.wordCount
val wordWidth = Ram.this.wordWidth
}
}
实例化一个blackbox
实例化 一个BlackBox
就像实例化 一个 Component
:
// Create the top level and instantiate the Ram
class TopLevel extends Component {
val io = new Bundle {
val wr = new Bundle {
val en = in Bool()
val addr = in UInt (log2Up(16) bit)
val data = in Bits (8 bit)
}
val rd = new Bundle {
val en = in Bool()
val addr = in UInt (log2Up(16) bit)
val data = out Bits (8 bit)
}
}
// Instantiate the blackbox
val ram = new Ram_1w_1r(8,16)
// Connect all the signals
io.wr.en <> ram.io.wr.en
io.wr.addr <> ram.io.wr.addr
io.wr.data <> ram.io.wr.data
io.rd.en <> ram.io.rd.en
io.rd.addr <> ram.io.rd.addr
io.rd.data <> ram.io.rd.data
}
object Main {
def main(args: Array[String]): Unit = {
SpinalVhdl(new TopLevel)
}
}
时钟和复位映射
在黑盒定义中,必须明确定义时钟和复位线。要将 a 的信号映射ClockDomain
到黑匣子的相应输入,您可以使用mapClockDomain
或mapCurrentClockDomain
函数。mapClockDomain
具有以下参数:
name | type | default | description |
---|---|---|---|
clockDomain | ClockDomain | ClockDomain.current | 指定提供信号的时钟域 |
clock | Bool | Nothing | 黑盒输入应该连接到clockDomain的时钟 |
reset | Bool | Nothing | 黑盒输入应该连接到clockDomain的reset |
enable | Bool | Nothing | 黑盒输入应该连接到clockDomain的enable |
mapCurrentClockDomain
有几乎相同的参数,mapClockDomain
但没有clockDomain。
class MyRam(clkDomain: ClockDomain) extends BlackBox {
val io = new Bundle {
val clkA = in Bool()
...
val clkB = in Bool()
...
}
// Clock A is map on a specific clock Domain
mapClockDomain(clkDomain, io.clkA)
// Clock B is map on the current clock domain
mapCurrentClockDomain(io.clkB)
}
io前缀
为了避免黑盒的每个IO上都有前缀“io_”,可以使用noIoPrefix()
如下所示的函数:
// Define the Ram as a BlackBox
class Ram_1w_1r(wordWidth: Int, wordCount: Int) extends BlackBox {
val generic = new Generic {
val wordCount = Ram_1w_1r.this.wordCount
val wordWidth = Ram_1w_1r.this.wordWidth
}
val io = new Bundle {
val clk = in Bool()
val wr = new Bundle {
val en = in Bool()
val addr = in UInt (log2Up(_wordCount) bit)
val data = in Bits (_wordWidth bit)
}
val rd = new Bundle {
val en = in Bool()
val addr = in UInt (log2Up(_wordCount) bit)
val data = out Bits (_wordWidth bit)
}
}
noIoPrefix()
mapCurrentClockDomain(clock=io.clk)
}
重命名黑盒的所有 io
可以在编译时使用该函数重命名BlackBox
或 的IO 。此函数在编译期间采用无参数函数,对于添加重命名过程很有用,如以下示例所示:Component``addPrePopTask
class MyRam() extends Blackbox {
val io = new Bundle {
val clk = in Bool()
val portA = new Bundle{
val cs = in Bool()
val rwn = in Bool()
val dIn = in Bits(32 bits)
val dOut = out Bits(32 bits)
}
val portB = new Bundle{
val cs = in Bool()
val rwn = in Bool()
val dIn = in Bits(32 bits)
val dOut = out Bits(32 bits)
}
}
// Map the clk
mapCurrentClockDomain(io.clk)
// Remove io_ prefix
noIoPrefix()
// Function used to rename all signals of the blackbox
private def renameIO(): Unit = {
io.flatten.foreach(bt => {
if(bt.getName().contains("portA")) bt.setName(bt.getName().repalce("portA_", "") + "_A")
if(bt.getName().contains("portB")) bt.setName(bt.getName().repalce("portB_", "") + "_B")
})
}
// Execute the function renameIO after the creation of the component
addPrePopTask(() => renameIO())
}
// This code generate these names:
// clk
// cs_A, rwn_A, dIn_A, dOut_A
// cs_B, rwn_B, dIn_B, dOut_B
添加 RTL 源
使用该功能,addRTLPath()
您可以将 RTL 源与黑匣子相关联。生成 SpinalHDL 代码后,可以调用该函数mergeRTLSource
将所有源合并在一起。
class MyBlackBox() extends Blackbox {
val io = new Bundle {
val clk = in Bool()
val start = in Bool()
val dIn = in Bits(32 bits)
val dOut = out Bits(32 bits)
val ready = out Bool()
}
// Map the clk
mapCurrentClockDomain(io.clk)
// Remove io_ prefix
noIoPrefix()
// Add all rtl dependencies
addRTLPath("./rtl/RegisterBank.v") // Add a verilog file
addRTLPath(s"./rtl/myDesign.vhd") // Add a vhdl file
addRTLPath(s"${sys.env("MY_PROJECT")}/myTopLevel.vhd") // Use an environement variable MY_PROJECT (System.getenv("MY_PROJECT"))
}
...
val report = SpinalVhdl(new MyBlackBox)
report.mergeRTLSource("mergeRTL") // Merge all rtl sources into mergeRTL.vhd and mergeRTL.v files
VHDL - 无数字类型
如果你只想std_logic_vector
在你的黑盒组件中使用,你可以将标签添加noNumericType
到黑盒中。
class MyBlackBox() extends BlackBox{
val io = new Bundle {
val clk = in Bool()
val increment = in Bool()
val initValue = in UInt(8 bits)
val counter = out UInt(8 bits)
}
mapCurrentClockDomain(io.clk)
noIoPrefix()
addTag(noNumericType) // Only std_logic_vector
}
上面的代码将生成以下 VHDL:
component MyBlackBox is
port(
clk : in std_logic;
increment : in std_logic;
initValue : in std_logic_vector(7 downto 0);
counter : out std_logic_vector(7 downto 0)
);
end component;
reference
- spinal HDL官方指南
相关文章
- 爬虫(第一篇) IP代理池
- ip addr命令作用_linux带内ip
- FC-SAN与IP-SAN那些事
- 多IP服务器的部署与管理方法有哪些值得注意的地方?
- 原生IP代理有哪些优势?可以适用于哪些场景?
- 浅谈TCP/IP网络编程中socket的行为详解程序员
- ip查看Linux服务器网卡IP地址的简单方法(linux查看服务器网卡)
- Linux下实现IP转发功能(ip转发linux)
- 配置Linux下网卡多重IP配置指南(linux网卡多个ip)
- Linux系统下IP限制的实施(linuxip限制)
- 控制从Oracle中控制IP访问的安全措施(oracle访问ip)
- 查看MySQL连接IP的简单步骤(查看mysql的连接ip)
- 关于 ubuntu 设置静态IP的问题
- Linux下固定IP地址的设置方法(linux固定ip设置)
- Linux 单网卡实现双IP配置(linux单网卡双ip)
- Linux下静态IP设置指南(linux静态ip设置)
- Linux如何快速修改IP地址(linux修改ip地址)
- 限制Linux IP 访问限制实施策略(linux访问ip)
- 如何在Linux上重新获取IP地址(linux重新获取ip)
- 实践技巧:学习Linux中的IP重定向(linux的ip重定向)
- 如何设置 MySQL 的 IP 连接权限?(mysqlip设置)
- Ip查询实战之Linux操作系统(linux查看ip 网口)
- 和端口SQL Server IP 地址与端口号设置说明(sqlserver的ip)
- 深入探索Linux中设置公网IP的方法(linux设置公网ip)
- 腾讯云Redis服务外网IP支持超越界限(腾讯云redis外网ip)
- Redis投票IP限制及其必要性(redis 限制投票ip)
- 限制IP登录,全面提升Redis安全性(redis 限制ip登录)
- Oracle IP变化的可能性(oracle ip改变吗)