当前位置:网站首页>吃透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生成电路。
边栏推荐
- C语言中学生成绩管理系统
- Xilinx/system-controller-c/boardui/ unable to connect to the development board, the solution of jamming after arbitrary operation
- JVM 内存布局详解,图文并茂,写得太好了!
- 基于STM32+华为云IOT设计的酒驾监控系统
- 2022g3 boiler water treatment examination question simulation examination question bank and simulation examination
- mac redis安装与使用,连接远程服务器 redis
- Haproxy high availability solution
- 舔狗舔到最后一无所有(状态机)
- 程序员的焦虑
- SQL language
猜你喜欢
Huahao Zhongtian sprint Technology Innovation Board: perte annuelle de 280 millions de RMB, projet de collecte de fonds de 1,5 milliard de Beida Pharmaceutical est actionnaire
sharding key type not supported
博士申请 | 西湖大学学习与推理系统实验室招收博后/博士/研究实习等
面试官:Redis中哈希数据类型的内部实现方式是什么?
Install Trinity and solve error reporting
Redis —— How To Install Redis And Configuration(如何快速在 Ubuntu18.04 与 CentOS7.6 Linux 系统上安装 Redis)
2022年山东省安全员C证考试题库及在线模拟考试
硬件基础知识-二极管基础
德明利深交所上市:市值31亿 为李虎与田华夫妻档
1200. Minimum absolute difference
随机推荐
高质量软件架构的唯一核心指标
吃透Chisel语言.09.Chisel项目构建、运行和测试(一)——用sbt构建Chisel项目并运行
Node の MongoDB安装
Introduction to reverse debugging PE structure resource table 07/07
1200. 最小绝对差
Worried about "cutting off gas", Germany is revising the energy security law
xshell/bash/zsh 等终端鼠标滚轮乱码问题(转)
Fisher信息量检测对抗样本代码详解
C语言宿舍管理查询软件
.Net之延迟队列
392. 判断子序列
忠诚协议是否具有法律效力
C language programming topic reference
程序员转方向
吃透Chisel语言.05.Chisel基础(二)——组合电路与运算符
Byte interview algorithm question
程序员的焦虑
gorm 之数据插入(转)
OpenHarmony应用开发之如何创建DAYU200预览器
HAProxy高可用解决方案