spinal HDL - 06 - 例化VHDL and Verilog IP

简介: spinal HDL - 06 - 例化VHDL and Verilog IP

实例化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_logicBitsstd_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到黑匣子的相应输入,您可以使用mapClockDomainmapCurrentClockDomain函数。mapClockDomain具有以下参数:

image.png

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


  1. spinal HDL官方指南
目录
相关文章
|
6月前
|
存储 编译器 索引
Verilog基础【一】
Verilog基础【一】
203 0
|
4月前
|
算法 异构计算
FPGA入门(2):Verilog HDL基础语法
FPGA入门(2):Verilog HDL基础语法
33 0
|
5月前
|
监控 算法 编译器
初识 Verilog HDL , 什么是verilog HDL?
这是一篇关于Verilog HDL的学习笔记摘要。Verilog是一种硬件描述语言,用于数字系统的多层抽象设计,包括行为、数据流和结构。设计流程包括功能设计、Verilog描述、软件模拟、逻辑综合和硬件实现。模块是Verilog的基本单元,代表逻辑实体,通过并行运行和分层连接实现复杂系统。模块包含端口列表和定义,通过模块调用(实例化)实现子模块连接。Verilog的参数声明和预处理指令(如`define、`include和`timescale)增加了代码的可读性和灵活性。笔记指出Verilog与C语言有相似之处,易于学习。
|
6月前
|
存储 人工智能 安全
Verilog基础【二】
Verilog基础【二】
199 1
|
6月前
|
C++
Verilog 函数和任务
Verilog 函数和任务
|
算法 关系型数据库 MySQL
FPGA:Verilog HDL程序的基本结构
FPGA:Verilog HDL程序的基本结构
163 0
FPGA:Verilog HDL程序的基本结构
|
算法
|
算法 异构计算
Verilog HDL函数与任务的使用
⭐本专栏针对FPGA进行入门学习,从数电中常见的逻辑代数讲起,结合Verilog HDL语言学习与仿真,主要对组合逻辑电路与时序逻辑电路进行分析与设计,对状态机FSM进行剖析与建模。
116 0
Verilog HDL函数与任务的使用
|
存储 算法 异构计算
基于Verilog HDL的状态机描述方法
⭐本专栏针对FPGA进行入门学习,从数电中常见的逻辑代数讲起,结合Verilog HDL语言学习与仿真,主要对组合逻辑电路与时序逻辑电路进行分析与设计,对状态机FSM进行剖析与建模。
155 0
基于Verilog HDL的状态机描述方法