spinal HDL - 04 - Spinal HDL - 组件、层次结构和区域

简介: spinal HDL - 04 - Spinal HDL - 组件、层次结构和区域

写在前面


本文主要介绍了spinal HDL的组件、层次结构和区域。

组件和层次结构(Component and hierarchy)


就像在 VHDL 和 Verilog 中一样,可以定义可用于构建设计层次结构的组件。但是,在 SpinalHDL 中,不需要在实例化时绑定它们的端口:

class AdderCell extends Component {
  // Declaring external ports in a Bundle called `io` is recommended
  val io = new Bundle {
    val a, b, cin = in Bool()
    val sum, cout = out Bool()
  }
  // Do some logic
  io.sum := io.a ^ io.b ^ io.cin
  io.cout := (io.a & io.b) | (io.a & io.cin) | (io.b & io.cin)
}
class Adder(width: Int) extends Component {
  ...
  // Create 2 AdderCell instances
  val cell0 = new AdderCell
  val cell1 = new AdderCell
  cell1.io.cin := cell0.io.cout   // Connect cout of cell0 to cin of cell1
  // Another example which creates an array of ArrayCell instances
  val cellArray = Array.fill(width)(new AdderCell)
  cellArray(1).io.cin := cellArray(0).io.cout   // Connect cout of cell(0) to cin of cell(1)
  ...
}

val io = new Bundle { … }

建议在Bundle被叫方声明外部端口io。如果你命名你的 bundle io,SpinalHDL 将检查它的所有元素是否被定义为输入或输出。

输入/输出定义


定义输入和输出的语法如下:

image.png

组件互连需要遵循一些规则:

  • 组件只能读取子组件的输出和输入信号。
  • 组件可以读取自己的输出端口值(与 VHDL 不同)。

修剪信号


SpinalHDL 只生成直接或间接驱动顶级实体输出所需的东西。

所有其他信号(无用的)都从 RTL 生成中删除,并插入到修剪过的信号列表中。您可以通过生成的对象上的printPrunedprintPrunedIo函数获取此列表SpinalReport

class TopLevel extends Component {
  val io = new Bundle {
    val a,b = in UInt(8 bits)
    val result = out UInt(8 bits)
  }
  io.result := io.a + io.b
  val unusedSignal = UInt(8 bits)
  val unusedSignal2 = UInt(8 bits)
  unusedSignal2 := unusedSignal
}
object Main {
  def main(args: Array[String]) {
    SpinalVhdl(new TopLevel).printPruned()
    //This will report :
    //  [Warning] Unused wire detected : toplevel/unusedSignal : UInt[8 bits]
    //  [Warning] Unused wire detected : toplevel/unusedSignal2 : UInt[8 bits]
  }
}

如果您出于调试原因想在生成的 RTL 中保留修剪后的信号,您可以使用该keep信号的函数:

class TopLevel extends Component {
  val io = new Bundle {
    val a, b = in UInt(8 bits)
    val result = out UInt(8 bits)
  }
  io.result := io.a + io.b
  val unusedSignal = UInt(8 bits)
  val unusedSignal2 = UInt(8 bits).keep()
  unusedSignal  := 0
  unusedSignal2 := unusedSignal
}
object Main {
  def main(args: Array[String]) {
    SpinalVhdl(new TopLevel).printPruned()
    // This will report nothing
  }
}

参数化硬件(VHDL 中的“Generic”,Verilog 中的“Parameter”)


如果你想参数化你的组件,你可以给组件的构造函数提供参数,如下所示:

class MyAdder(width: BitCount) extends Component {
  val io = new Bundle {
    val a, b   = in UInt(width)
    val result = out UInt(width)
  }
  io.result := io.a + io.b
}
object Main {
  def main(args: Array[String]) {
    SpinalVhdl(new MyAdder(32 bits))
  }
}

如果有多个参数,那么给出一个具体的配置类是一个很好的做法,如下所示:

case class MySocConfig(axiFrequency  : HertzNumber,
                       onChipRamSize : BigInt,
                       cpu           : RiscCoreConfig,
                       iCache        : InstructionCacheConfig)
class MySoc(config: MySocConfig) extends Component {
  ...
}

合成成分名称


在一个模块中,每个组件都有一个名称,称为“部分名称”。“完整”名称是通过用“_”连接每个组件的父名称来构建的,例如:io_clockDomain_reset。您可以使用setName自定义名称替换此约定。这在与外部组件接口时特别有用。其他的方法被称为getNamesetPartialNamegetPartialName分别。

合成时,每个模块都会获得定义它的 Scala 类的名称。您也可以使用setDefinitionName.

区域(Area)


有时,创建一个Component来定义一些逻辑是矫枉过正的,因为你:

  • 需要定义所有的构造参数和IO(verbosity,duplication)
  • 拆分您的代码(超出需要)

对于这种情况,您可以使用 anArea来定义一组信号/逻辑:

class UartCtrl extends Component {
  ...
  val timer = new Area {
    val counter = Reg(UInt(8 bit))
    val tick = counter === 0
    counter := counter - 1
    when(tick) {
      counter := 100
    }
  }
  val tickCounter = new Area {
    val value = Reg(UInt(3 bit))
    val reset = False
    when(timer.tick) {          // Refer to the tick from timer area
      value := value + 1
    }
    when(reset) {
      value := 0
    }
  }
  val stateMachine = new Area {
    ...
  }
}

Reference


  1. spinal HDL官方文档
目录
相关文章
|
异构计算
【数字电路】Y图 | 逻辑操作符 | 布尔函数 | Combinational systems
【数字电路】Y图 | 逻辑操作符 | 布尔函数 | Combinational systems
65 0
|
6月前
|
存储 数据安全/隐私保护 芯片
基于VHDL语言的8路彩灯控制器的设计_kaic
基于VHDL语言的8路彩灯控制器的设计_kaic
|
算法 关系型数据库 MySQL
FPGA:Verilog HDL程序的基本结构
FPGA:Verilog HDL程序的基本结构
163 0
FPGA:Verilog HDL程序的基本结构
|
存储 算法 异构计算
基于Verilog HDL的状态机描述方法
⭐本专栏针对FPGA进行入门学习,从数电中常见的逻辑代数讲起,结合Verilog HDL语言学习与仿真,主要对组合逻辑电路与时序逻辑电路进行分析与设计,对状态机FSM进行剖析与建模。
155 0
基于Verilog HDL的状态机描述方法
|
算法 异构计算
Verilog HDL函数与任务的使用
⭐本专栏针对FPGA进行入门学习,从数电中常见的逻辑代数讲起,结合Verilog HDL语言学习与仿真,主要对组合逻辑电路与时序逻辑电路进行分析与设计,对状态机FSM进行剖析与建模。
116 0
Verilog HDL函数与任务的使用
|
Scala
spinal HDL - 05 - Spinal HDL - 函数和时钟域
spinal HDL - 05 - Spinal HDL - 函数和时钟域
293 0
spinal HDL - 05 - Spinal HDL - 函数和时钟域
|
算法 异构计算
Verilog HDL数据流建模与运算符
⭐本专栏针对FPGA进行入门学习,从数电中常见的逻辑代数讲起,结合Verilog HDL语言学习与仿真,主要对组合逻辑电路与时序逻辑电路进行分析与设计,对状态机FSM进行剖析与建模。
199 0
Verilog HDL数据流建模与运算符
|
算法 异构计算
Verilog HDL门级建模
⭐本专栏针对FPGA进行入门学习,从数电中常见的逻辑代数讲起,结合Verilog HDL语言学习与仿真,主要对组合逻辑电路与时序逻辑电路进行分析与设计,对状态机FSM进行剖析与建模。
137 0
Verilog HDL门级建模
spinal HDL - 10 - 状态机
spinal HDL - 10 - 状态机
246 0
spinal HDL - 10 - 状态机
spinal HDL - 09 - 时序逻辑
spinal HDL - 09 - 时序逻辑
342 0
spinal HDL - 09 - 时序逻辑