spinal HDL - 08 - 赋值

简介: spinal HDL - 08 - 赋值

赋值


赋值操作


有多个赋值操作符:

image.png

// Because of hardware concurrency, `a` is always read as '1' by b and c
val a, b, c = UInt(4 bits)
a := 0
b := a
a := 1  // a := 1 "wins"
c := a
var x = UInt(4 bits)
val y, z = UInt(4 bits)
x := 0
y := x      // y read x with the value 0
x \= x + 1
z := x      // z read x with the value 1
// Automatic connection between two UART interfaces.
uartCtrl.io.uart <> io.uart

在 SpinalHDL 中,信号(组合/顺序)的本质是在它的声明中定义的,而不是通过它被赋值的方式,理解这一点很重要。所有数据类型实例都将定义一个组合信号,而Reg (…)的数据类型实例将定义一个时序(寄存器)信号。

val a = UInt(4 bits) // Define a combinational signal
val b = Reg(UInt(4 bits)) // Define a registered signal
val c = Reg(UInt(4 bits)) init(0) // Define a registered signal which is set to 0 when a reset occurs

宽度检查


检查赋值的左侧和右侧的位计数是否匹配。有多种方法可以调整给定 BitVector 的宽度(Bits,UInt,SInt) :

调整大小的技巧 描述
x := y.resized x用 y 的调整大小的副本分配 x,将自动推断调整大小值以匹配 x
x := y.resize(newWidth) 用 y 的调整大小的副本分配 x,大小是手动计算的

在一个案例中,Spinal 会自动调整一个值:

Assignment Problem SpinalHDL action
myUIntOf_8bit := U(3) 创建了一个2位的 UInt,它与左边(8位)不匹配 由于 u (3)是一个“弱”位计数推断信号,SpinalHDL 自动调整它的大小

组合循环


检查你的设计中是否没有组合循环(锁存)。如果检测到一个,就会产生一个错误,然后 SpinalHDL 将打印循环的路径。

When/Switch/Mux


When


正如在 VHDL 和 Verilog 中一样,信号可以在满足特定条件时有条件地分配:

when(cond1) {
  // Execute when cond1 is true
}.elsewhen(cond2) {
  // Execute when (not cond1) and cond2
}.otherwise {
  // Execute when (not cond1) and (not cond2)
}

Switch


正如在 VHDL 和 Verilog 中一样,当信号有一个确定的值时,可以有条件地对信号进行分配:

switch(x) {
  is(value1) {
    // Execute when x === value1
  }
  is(value2) {
    // Execute when x === value2
  }
  default {
    // Execute if none of precedent conditions met
  }
}

Local declaration


可以在 when/switch 语句中定义新信号:

val x, y = UInt(4 bits)
val a, b = UInt(4 bits)
when(cond) {
  val tmp = a + b
  x := tmp
  y := tmp + 1
} otherwise {
  x := 0
  y := 0
}

检查定义在作用域内的信号只分配给作用域内的信号。

Mux


如果你只需要一个带 Bool 选择信号的 Mux,有两个等价的语法:

image.png

val cond = Bool
val whenTrue, whenFalse = UInt(8 bits)
val muxOutput  = Mux(cond, whenTrue, whenFalse)
val muxOutput2 = cond ? whenTrue | whenFalse

Bitwise selection


按位选择在语法上类似于 VHDL。

Example 例子


val bitwiseSelect = UInt(2 bits)
val bitwiseResult = bitwiseSelect.mux(
  0 -> (io.src0 & io.src1),
  1 -> (io.src0 | io.src1),
  2 -> (io.src0 ^ io.src1),
  default -> (io.src0)
)

另外,如果所有可能的值都包含在你的 mux 中,你可以省略默认值:

val bitwiseSelect = UInt(2 bits)
val bitwiseResult = bitwiseSelect.mux(
  0 -> (io.src0 & io.src1),
  1 -> (io.src0 | io.src1),
  2 -> (io.src0 ^ io.src1),
  3 -> (io.src0)
)

muxLists (…)是另一种以元组序列作为输入的按位选择。下面是一个将128位分成32位的例子:

image.png

val sel  = UInt(2 bits)
val data = Bits(128 bits)
// Dividing a wide Bits type into smaller chunks, using a mux:
val dataWord = sel.muxList(for (index <- 0 until 4) yield (index, data(index*32+32-1 downto index*32)))
// A shorter way to do the same thing:
val dataWord = data.subdivideIn(32 bits)(sel)

规则


学习 SpinalHDL 背后的语义很重要,这样你才能理解幕后真正发生了什么,以及如何控制它。这些语义由多个规则定义:

  • 信号和寄存器并发运行(并行行为,如 VHDL 和 Verilog)。
  • 对一个组合信号的赋值就像表示一个总是正确的规则。
  • 对寄存器的赋值就像表示一个应用于其时钟域的每个周期的规则。
  • 对于每个信号,最后一个有效的赋值才有效。
  • 在硬件开发过程中,每个信号和寄存器都可以以 OOP 方式作为对象进行操作。

并发性


分配每个组合或寄存器信号的顺序对行为没有影响。

例如,下面两段代码是等价的:

val a, b, c = UInt(8 bits) // Define 3 combinational signals
c := a + b  // c will be set to 7
b := 2      // b will be set to 2
a := b + 3  // a will be set to 5

这相当于:

val a, b, c = UInt(8 bits) // Define 3 combinational signals
b := 2      // b will be set to 2
a := b + 3  // a will be set to 5
c := a + b  // c will be set to 7

更一般地说,当您使用: = 赋值运算符时,就像为左侧信号/寄存器指定一个新规则。

Last valid assignment wins


如果一个组合信号或寄存器被分配多次,最后一个有效的赢。

举个例子:

val x, y = Bool()           // Define two combinational signals
val result = UInt(8 bits)   // Define a combinational signal
result := 1
when(x) {
  result := 2
  when(y) {
    result := 3
  }
}

这将产生下列真相表:

image.png

信号和寄存器与 Scala 的交互(OOP 引用 + 函数)


在 SpinalHDL 中,每个硬件元素都由一个类实例来建模。这意味着您可以通过使用实例的引用来操作它们,例如将它们作为参数传递给函数。例如,下面的代码实现了一个寄存器,当 inc 为 True 时递增,当 clear 为 True 时清除(clear 优先于 inc) :

val inc, clear = Bool()          // Define two combinational signals/wires
val counter = Reg(UInt(8 bits))  // Define an 8 bit register
when(inc) {
  counter := counter + 1
}
when(clear) {
  counter := 0    // If inc and clear are True, then this  assignment wins (Last valid assignment rule)
}

你可以通过混合前面的例子和赋值给 counter 的函数来实现完全相同的功能:

val inc, clear = Bool()
val counter = Reg(UInt(8 bits))
def setCounter(value : UInt): Unit = {
  counter := value
}
when(inc) {
  setCounter(counter + 1)  // Set counter with counter + 1
}
when(clear) {
  counter := 0
}

你也可以在函数中集成条件检查:

val inc, clear = Bool()
val counter = Reg(UInt(8 bits))
def setCounterWhen(cond : Bool,value : UInt): Unit = {
  when(cond) {
    counter := value
  }
}
setCounterWhen(cond = inc,   value = counter + 1)
setCounterWhen(cond = clear, value = 0)

并且指定应该为函数赋值的内容:

val inc, clear = Bool()
val counter = Reg(UInt(8 bits))
def setSomethingWhen(something : UInt, cond : Bool, value : UInt): Unit = {
  when(cond) {
    something := value
  }
}
setSomethingWhen(something = counter, cond = inc,   value = counter + 1)
setSomethingWhen(something = counter, cond = clear, value = 0)

前面所有的例子在 RTL 生成和 SpinalHDL 编译器的角度上都是严格等价的。这是因为SpinalHDL 只关心 Scala 运行时和在那里实例化的对象,而不关心 Scala 语法本身。换句话说,从生成的 RTL 生成/SpinalHDL 透视图来看,当您在 Scala 中使用生成硬件的函数时,就像函数是内联的一样。对于 Scala 循环也是如此,因为它们将以展开的形式出现在生成的 RTL 中。

目录
相关文章
|
存储 NoSQL 测试技术
SystemVerilog学习-05-数组
SystemVerilog学习-05-数组
1022 0
SystemVerilog学习-05-数组
|
异构计算
【数字电路】Y图 | 逻辑操作符 | 布尔函数 | Combinational systems
【数字电路】Y图 | 逻辑操作符 | 布尔函数 | Combinational systems
87 0
|
8月前
|
存储 C语言
【学习笔记】verilog HDL之二:数据类型与表达式
本文介绍了Verilog语言中的常量、变量和表达式。Verilog有四种基本值:0、1、x(未知)和z(高阻)。整型常量有十进制和基数两种格式,实数型常量包括浮点数,字符串常量由双引号括起的字符序列构成。变量分为线网型和寄存器型,线网型包括wire、tri等11种类型,寄存器型有reg、integer、time等,其中reg可声明存储器。表达式中的操作数包括常数、参数、线网等8种类型,操作符包括算术、关系、逻辑等9种类型。
|
9月前
|
算法 关系型数据库 计算机视觉
基于FPGA的9/7整数小波变换和逆变换verilog实现,包含testbench
基于FPGA的9/7整数小波变换和逆变换verilog实现,包含testbench
|
算法
如何将算法翻译成RTL(三):Verilog中的Signed本质及用法
如何将算法翻译成RTL(三):Verilog中的Signed本质及用法
378 0
|
算法 异构计算
通过状态机方法实现基于FPGA的维特比译码器,包含testbench测试文件
通过状态机方法实现基于FPGA的维特比译码器,包含testbench测试文件
173 0
|
Scala
spinal HDL - 05 - Spinal HDL - 函数和时钟域
spinal HDL - 05 - Spinal HDL - 函数和时钟域
320 0
spinal HDL - 05 - Spinal HDL - 函数和时钟域
|
算法 异构计算
Verilog HDL函数与任务的使用
⭐本专栏针对FPGA进行入门学习,从数电中常见的逻辑代数讲起,结合Verilog HDL语言学习与仿真,主要对组合逻辑电路与时序逻辑电路进行分析与设计,对状态机FSM进行剖析与建模。
132 0
Verilog HDL函数与任务的使用
|
算法 异构计算
Verilog HDL数据流建模与运算符
⭐本专栏针对FPGA进行入门学习,从数电中常见的逻辑代数讲起,结合Verilog HDL语言学习与仿真,主要对组合逻辑电路与时序逻辑电路进行分析与设计,对状态机FSM进行剖析与建模。
227 0
Verilog HDL数据流建模与运算符