吃蒜的好处与功效(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 = reg4. 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.BVec是同构的类型集合,通过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))创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!