当前位置:网站首页>吃透Chisel语言.07.Chisel基础(四)——Bundle和Vec
吃透Chisel语言.07.Chisel基础(四)——Bundle和Vec
2022-07-04 12:49:00 【github-3rr0r】
Chisel基础(四)——Bundle和Vec
Chisel基础的前面三篇我们学习了数据类型、组合电路操作符和寄存器,虽然已经足够实现很复杂的数字电路了,但还是不够方便。比如我需要构建一个32个寄存器的寄存器组,那么我需要写32个RegInit
吗?再比如我要将几个信号打包到一起,我又该怎么实现呢?Chisel中提供了两种构造用于给相关的信号分组,他们就是Bundle
和Vec
,其中:
Bundle
用于将不同类型的信号划分为一组;Vec
用于表示一个可索引的、相同类型的信号的集合;
这一部分我们就来详细讲解它们。
Bundle
介绍
Chisel中Bundle
用于将多个信号组合到一起,这个Bundle
没有什么好的翻译,我本人倾向于翻译为捆绑包,可以理解为将一堆信号捆绑在一起,但是为了不引起误会,后面这个词我就统一不翻译了。
整个一个bundle可以被当成一个整体来引用,而其中的个体字段都可以通过他们的命名来访问。我们通过定义一个类来定义一个bundle(也就是一组信号的集合),这个类拓展自Bundle
类,它的每个字段以val
的形式在构造块中给出,比如下面的代码:
class Channel() extends Bundle {
val data = UInt(32.W)
val valid = Bool()
}
Channel
这个bundle就将data
和valid
这两个信号捆绑到了一起。如果要使用这个bundle的话,我们可以new
一个Channel
然后把它封装到一个Wire
里面(这里的Wire
下一篇就会介绍),然后其中的每个字段用.
引用就行:
val ch = Wire(new Channel())
ch.data := 123.U
ch.valid := true.B
val b = ch.valid
.
记号是面向对象中常用的标记,x.y
就表示x
是一个对象的引用而y
这是这个对象的一个字段。因为Chisel也是面向对象的,所以我们当然可以用.
来访问bundle中的字段。
Chisel中的Bundle
跟C里面的struct
、VHDL里面的record
以及SystemVerilog里面的struct
都是类似的。一个bundle也可以作为一个整体来引用:
val channel = ch
Vec
介绍
Chisel中的Vec
表示一组相同类型信号的集合,也就是一个向量。向量中的每个元素都可以通过索引来访问。显然,Chisel里面的这个向量,和其他编程语言里面的数组是类似的,不过Ararry
已经是Scala里面的关键字了,所以Chisel里面用的就是Vec
。
创建向量通过调用Vec
的构造器来实现,这个构造器有两个参数,一个是向量中元素的个数,另一个是向量中元素的类型。向量同样也需要封装到一个Wire
里面:
val v = Wire(Vec(3, UInt(4.W)))
向量中的每个元素都可以通过(index)
来访问:
v(0) := 1.U
v(1) := 3.U
v(2) := 5.U
val idx = 1.U(2.W)
val a = v(idx)
可以这么理解,封装到Wire
里面的向量就是个多路选择器了,选择信号就对应着向量的索引,这是打包为Wire
的情况。我们也可以把向量打包成Reg
,以此来定义一组寄存器。
比如下面这个例子定义了一个处理器的寄存器组,总共有32个32位的寄存器,这是经典的32位RISC处理器的寄存器实现,比如RISC-V的32位版本。代码如下:
val registerFile = Reg(Vec(32, UInt(32.W)))
看到没有,这比傻乎乎地写32个寄存器是不是强多了?
同样,寄存器堆的元素(即某个寄存器)也可以使用索引来访问并且跟正常寄存器的使用是一样的:
registerFile(idx) := dIn
val dOur = registerFile(idx)
Bundle
和Vec
的使用
我们可以自由地把Bundle
和Vec
放到一起用。
比如我们可以用一个bundle创建一个向量,我们需要给向量字段传递一个原型,比如对于上面的Channel
,我们可以用下面的代码定义一个Channel
向量:
val vecBundle = Wire(Vec(8, new Channel()))
Bundle
里面同样也可以有向量,比如:
class BundleVec extends Bundle {
val field = UInt(8.W)
val vector = Vec(4, UInt(8.W))
}
如果我们希望创建一个有复位值的bundle类型的寄存器时,我们首先得创建那个bundle的Wire
,按需设置每个字段的初始值,然后再将它传递给RegInit
:
val initVal = Wire(new Channle())
initVal.data := 0.U
initVal.valid := false.B
val channelReg = RegInit(initVal)
通过组合使用Bundle
和Vec
等构造,我们可以定义自己的数据结构,这就是Chisel体现强大抽象能力的地方之一。
部分赋值和Bundle
在Chisel中进行部分赋值是不允许的,虽然在Chisel2中可以,在Verilog和VHDL中也是可以的,比如下面的代码就会在电路展开的时候报错:
val assignWord = Wire(UInt(16.W))
assignWord(7, 0) := lowByte
assignWord(15, 8) := highByte
在这种情况下,使用Bundle
就是个很好的解决方案。比如首先创建一个局部bundle,然后给这个bundle创建一个Wire
,然后再给每个独立的字段赋值,最后用asUInt()
把这个bundle转换成UInt
并赋值给目标UInt
。注意,我们把这个Bundle定义为局部的数据结构是因为只在这里会用到。代码如下:
val assignWord = Wire(UInt(16.W))
class Split extends Bundle {
val high = UInt(8.W)
val low = UInt(8.W)
}
val split = Wire(new Split())
split.low := lowByte
split.high := highByte
assignWord := split.asUInt
不过这种方法有个缺点,那就是我们需要知道bundle里面的字段合并成一个位向量之后的顺序是什么样的,比如这里的high
和low
就不能弄反了。
另一种方法就是用Bool
构造向量,这样的话每个值都可以独立地赋值了,最后一样地转换成UInt
就好:
val vecResult = Wire(Vec(4, Bool()))
vecResult(0) := data(0)
vecResult(1) := data(1)
vecResult(2) := data(2)
vecResult(3) := data(3)
val uintResult = vecResult.asUInt
结语
Bundle
和Vec
在Chisel中非常重要,熟练掌握可以极大提高写代码的效率,应对更复杂、更需要模块化的场景也会更游刃有余。这篇文章里还用到了另一个核心概念Wire
,也就是Verilog中的wire
,即线网。这个Wire
和前面说的UInt
、SInt
啥的不一样,它直接就是个表示硬件的类型,除Wire
外,Chisel中Reg
和IO
也是直接硬件的类型,下一部分就来谈一谈这三者,进一步说一说如何理解Chisel生成电路。
边栏推荐
猜你喜欢
Applet live + e-commerce, if you want to be a new retail e-commerce, use it!
ViewBinding和DataBinding的理解和区别
205. 同构字符串
CVPR 2022 | 大幅减少零样本学习所需的人工标注,提出富含视觉信息的类别语义嵌入(源代码下载)...
小程序直播 + 电商,想做新零售电商就用它吧!
Summary of recent days (non-technical article)
Oracle was named the champion of Digital Innovation Award by Ventana research
Fisher信息量检测对抗样本代码详解
OPPO Find N2产品形态首曝:补齐各项短板
Doctoral application | West Lake University Learning and reasoning system laboratory recruits postdoctoral / doctoral / research internship, etc
随机推荐
C语言程序设计
ViewBinding和DataBinding的理解和区别
BLOB,TEXT GEOMETRY or JSON column 'xxx' can't have a default value query 问题
学习项目是自己找的,成长机会是自己创造的
#yyds干货盘点# 解决名企真题:连续最大和
JVM 内存布局详解,图文并茂,写得太好了!
Introduction to XML III
OPPO Find N2产品形态首曝:补齐各项短板
FS7867S是一款应用于数字系统供电电源电压监控的电压检测芯片
Byte interview algorithm question
sharding key type not supported
mac redis安装与使用,连接远程服务器 redis
Flet tutorial 03 basic introduction to filledbutton (tutorial includes source code) (tutorial includes source code)
FS4059C是5V输入升压充电12.6V1.2A给三节锂电池充电芯片 输入小电流不会拉死,温度60°建议1000-1100MA
Redis —— How To Install Redis And Configuration(如何快速在 Ubuntu18.04 与 CentOS7.6 Linux 系统上安装 Redis)
go vendor 项目迁移到 mod 项目
好博医疗冲刺科创板:年营收2.6亿 万永钢和沈智群为实控人
2022 Shandong Province safety officer C certificate examination question bank and online simulation examination
Oracle was named the champion of Digital Innovation Award by Ventana research
C language staff management system