chisel学习笔记——根本类型
Chisel学习笔记(二)——根本类型
由于是对着chisel book学的,这篇实践上是加上我的了解的chisel book的翻译
1.信号类型与常量
Chisel供给了三种根本的类型来描绘信号、寄存器、组合逻辑:
- Bits
- SInt
- UInt
此外,还界说了逻辑类型Bool。
1.1类型界说
一个Chisel类型的界说有两部分:位宽与类型
比方看下面的比方:
Bits(7.W)
SInt(8.W)
UInt(9.W)
别离界说了7bits的Bits类型,8bits的有符号数,9bits的无符号数
1.2 常量界说
而一个Chisel常量类型的界说则有三部分:位宽、类型和值
比方看下面的比方:
-3.S(4.W)
这个界说代表一个4bits的有符号数3,其间-3、4都是Scala原生的整型,而经过.S、.W转化为Chisel界说的有符号数与宽度类型
关于上面的比方应该这样了解,首要4.W将Scala整型4转化为Chisel width,然后作为参数传入.S构成Chisel四位有符号数类型,然后把Scala整型-3转化为Chisel四位有符号数-3。
关于常量的界说,还能够运用其它的进制(16、8、2),这种情况下应该用Scala的字符串类型来表达,如:
"hff".U
"o377".U
"b1111_1111".U
都代表十进制的255
2. 组合逻辑
首要有必要介绍Scala的一个特性——类型揣度,相似C++的auto,对应的关键字为val。这个特性使得咱们能够不必像Verilog相同,对每一个变量显式声明它的类型、位宽(位宽实践上作为Bits、SInt、UInt类型的一项特点存在)。
先看一个比方:
val logic = a & b | c
上面的代码描绘了下面这样一个电路:
代码中,logic的类型为val,如前述,这不是一个实践的类型,仅仅表明logic是一个变量,而logic的变量由Scala揣度得出。
别的,还能够先将一个变量界说为Wire,然后再用一种继续赋值的办法来进行“衔接”:
val w = Wire(UInt())
w := a & b
能够经过相似下标拜访的办法来提取某一位或一个区间:
val bit31 = x(31)
val bit0to7 = x(7, 0)
还能够进行拼接:
val word = bits1 ## bits2
下面两张表介绍了Chisel中界说的一些硬件算子:
Operator | Description | Data Types |
---|---|---|
*、/、% | 乘、除、取模 | UInt、SInt |
+、- | 加、减 | UInt、SInt |
===、=/= | 等于、不等于 | UInt、SInt,回来Bool |
>、>=、<、<= | 大于、不小于、小于、不大于 | UInt、SInt,回来Bool |
<<、>> | 左移、右移(UInt逻辑移位、SInt算术移位) | UInt、SInt |
~ | 非 | UInt、SInt、Bool |
&、|、^ | 与、或、非 | UInt、SInt、Bool |
! | 逻辑非 | Bool |
&&、|| | 逻辑与、或 | Bool |
Function | Description | Data Types |
---|---|---|
v.andR、v.orR、v.xorR | AND、OR、XOR reduction | UInt、SInt、returns Bool |
v(n) | 提取1bit | UInt、SInt |
v(end, start) | 提取区间 | UInt、SInt |
Fill(n, v) | 将v仿制n遍 | UInt、SInt |
a ## b | 拼接 | UInt、SInt |
Cat(a, b, ...) | 拼接 | UInt、SInt |
Mux(sel, a, b) | 多路选择器 | sel:Bool,a、b:任何相同的Chisel类 |
3. 寄存器
Chisel供给的寄存器接口是高度笼统和封装的。寄存器的时钟被衔接到一个大局时钟,复位被衔接到一个大局同步复位,只留下了输入、输出两个接口供运用。尽管自由度变低了,但运用也相对简化了,实践上只要初始化、衔接输入、衔接输出三件事要做:
val reg = RegInit(0.U(8.W))
reg := d
val q = reg
或许也能够这样写:
val reg = RegNext(d, 0.U(8.W))
val q = reg
4. Bundle和Vec
Bundle是异构的类型调集,能够经过承继Bundle类来界说:
class MyBundle extends Bundle{
val d1 = UInt(8.W)
val d2 = Bool()
}
然后在运用前进行声明,Bundle内数据的拜访实践上便是对类特点的拜访:
val mb = Wire(new MyBundle())
mb.d1 := 2.U
mb.d2 := true.B
Vec是同构的类型调集,经过Vec类界说,下标拜访:
val vec = Wire(Vec(3, UInt(4.W)))
vec(0) := 1.U
vec(1) := 2.U
vec(2) := 3.U
val q = vec(0)
还能够经过初始化函数界说,这种办法直接发生Wire,不需要再转化:
val d = 3.U(4.W)
val vec = VecInit(1.U(4.W), 2.U, d)
Vec默许是一组Wire,但也有RegFile型的:
val rf = Reg(Vec(32, 0.U(32.W)))
val rf = RegInit(VecInit(Seq.fill(32)(0.U(32.W))))
Bundle与Vec能够相互包括:
class VecBundle extends Bundle{
val d1 = UInt(8.W)
val v1 = Vec(3, UInt(4.W))
}
BundleVec = Wire(Vec(3, new VecBundle()))
别的,Bundle与Vec还有一个重要的用处。Chisel3不支撑对一个变量部分赋值,比方说这样写是会报错的:
val dat = Wire(UInt(8.W))
dat(7:4) := "h1".U(4.W)
dat(3:0) := "h2".U(4.W)
作为代替,能够用Vec和Bundle完成分段
5. Wire、Reg、IO
上面说到的各种类型支撑了多样的规划,但许多还不能直接对应到硬件结构。Wire、Reg、IO别离对应了连线,寄存器,输入输出端口。组合逻辑的信号需要用Wire显式声明,Reg与前述是相同的,IO是输入输出端口。
Wire与IO的用法与Reg相似:
val w = Wire(UInt(8.W))
w := 8.U(8.W)
val v = WireDefault(8.U(8.W))