吃透Chisel语言.15.Chisel模块详解(二)——Chisel模块嵌套和ALU实现
Chisel模块详解(二)——Chisel模块嵌套和ALU实现
稍微复杂点的硬件设计就需要用嵌套的模块层级来构建了,上一篇文章中实现的计数器其实就是个例子,计数器内部嵌套了一个寄存器、一个Mux和一个加法器。这一篇文章就仔细讲解模块之间是怎么连接到一起的,又是怎么组合成层级的大规模模块的,最后用Chisel实现一个ALU模块来实际应用一下Chisel模块实现的基本方法。
Chisel模块的连接和层级嵌套
下图就是一个模块嵌套的设计:
模块C有三个输入端口和一个输出端口,而C模块本身由两个子模块A和B组成,他们也都连接到了C的输入和输出上,而A的一个输出连接到了B上。模块D和模块C是同一个层级的,他们之间也是相互连接的。
下面的代码展示了上图中模块A和模块B的定义的示例:
class CompA extends Module {val io = IO(new Bundle {val a = Input(UInt(8.W))val b = Input(UInt(8.W))val x = Output(UInt(8.W))val y = Output(UInt(8.W))})// function of A
}class CompB extends Module {val io = IO(new Bundle {val in1 = Input(UInt(8.W))val in2 = Input(UInt(8.W))val out = Output(UInt(8.W))})// function of B
}
其中,模块A有两个输入a
和b
,两个输出x
和y
,而模块B有两个输入in1
和in2
以及一个输出out
。所有的端口都是八位无符号整数类型。因为这个例子是为了解释模块是怎么连接到一起来构建层级的,所有就不展示模块内部的细节了,就用// function of xxx
来代替了。因为我们没有和示例模块相关联的功能,所以我们就随便起的端口名,而在实际应用中应该起有描述性的名字,比如data
、valid
和ready
等。
模块C的代码如下所示:
class CompC extends Module {val io = IO(new Bundle {val in_a = Input(UInt(8.W))val in_b = Input(UInt(8.W))val in_c = Input(UInt(8.W))val out_x = Output(UInt(8.W))val out_y = Output(UInt(8.W))})// 创建模块A和模块Bval compA = Module(new CompA())val compB = Module(new CompB())// 连接AcompA.io.a := io.in_acompA.io.b := io.in_bio.out_x := compA.io.x// 连接BcompB.io.in1 := compA.io.ycompB.io.in2 := io.in_cio.out_y := compB.io.out
}
可以看到,C模块有三个输入端口和两个输出端口,它是用模块A和模块B构建的。代码中描述了A和B是怎么连接到C的端口的,A和B之间又是怎么连接到一起的。
模块通过new
来创建,比如new CompA()
,然后需要通过调用Module()
来封装,上一篇文章中已经使用过这种用法。对模块的引用存放在局部变量里面,本例中就是val compA = Module(new CompA())
。通过这个引用,我们可以通过间接访问该模块的io
字段和IO Bundle中的每个单独的字段来访问模块的IO端口。
最后是模块D的代码:
class CompD extends Module {val io = IO(new Bundle {val in = Input(UInt(8.W))val out = Output(UInt(8.W))})// function of D
}
D的模块的代码最简单了,只有一个输入端口in
和一个输出端口out
。而最后确实的内容就是顶层模块的代码了,它本身通过C模块和D模块组合而成,代码如下:
class TopLevel extends Module {val io = IO(new Bundle {val in_a = Input(UInt(8.W))val in_b = Input(UInt(8.W))val in_c = Input(UInt(8.W))val out_m = Output(UInt(8.W))val out_n = Output(UInt(8.W))})// 创建C模块和D模块val c = Module(new CompC())val d = Module(new CompD())// 连接Cc.io.in_a := io.in_ac.io.in_b := io.in_bc.io.in_c := io.in_cio.out_m := c.io.out_x// 连接Dd.io.in := c.io.out_yio.out_n := d.io.out
}
好的模块设计和软件设计中好的方程或方法是类似的。一个最主要的问题就是我们应该在一个模块中放入多少功能,一个模块应该有多大。比如两个极端,一个是极小的模块,比如一个加法器,一个是极大的模块,比如一个完全的处理器。
硬件设计的新手一般从小的模块开始,问题是数字设计相关的书都用的是小的模块来展示基本原理,但是代码行数因为页面限制所以通常不会太多,自然也不会包含太多细节。
模块的接口一般是有点冗长的,因为需要指定类型、命名、方向并构造IO。有个经验之谈,就是模块的核心,也就是功能部分的代码,应该至少跟模块的接口差不多长。
而对于一些比较小规模的常用模块,比如说计数器,Chisel中也内置了相关类型,我们可以用调用函数返回硬件这种简单的方法来描述一个计数器,后面还会对Chisel中已经内置了的常用模块进行讲解。
用Chisel实现一个ALU
微处理器中,用于计算的核心组件之一就是算术逻辑单元(ALU,Arithmetic-Logic Unit),通常在示意图中,ALU的符号是这样的:
图中ALU有两个输入,也就是A
和B
,一个功能输入,即fn
,还有一个输出Y
。ALU在输入A
和B
上执行操作,然后将结果通过输出Y
来提供。输入fn
用于选择执行的操作,这个操作通常是算术的,比如加法、减法等,也可以是逻辑操作,比如与、或、异或等,因此这个单元叫作ALU,即算术逻辑单元。
输入fn
用于选择操作,而ALU通常是个没有任何状态信息的组合电路,不过也有可能不止一个输出,有时候还可以有零输出或符号位输出,这个就看需求了。
下面的代码是一个十六位输入输出的ALU,支持加法、减法、或运算以及与运算,这四种运算通过一个两位的fn
信号来选择:
class ALU extends Module {val io = IO(new Bundle {val a = Input(UInt(16.W))val b = Input(UInt(16.W))val fn = Input(UInt(2.W))val y = Output(UInt(16.W))})// ALU的默认输出值io.y := 0.U// 选择ALU的功能switch(io.fn) {is(0.U) {io.y := io.a + io.b}is(1.U) {io.y := io.a - io.b}is(2.U) {io.y := io.a | io.b}is(3.U) {io.y := io.a & io.b}}
}
在这个例子中,我们使用了一个新的Chisel结构,即switch
/is
结构,用于描述ALU的选择信号对应的输出,为了使用switch
/is
结构,应该带入下面的Chisel包:
import chisel3.util._
输出的Verilog代码如下:
module ALU(input clock,input reset,input [15:0] io_a,input [15:0] io_b,input [1:0] io_fn,output [15:0] io_y
);wire [15:0] _io_y_T_1 = io_a + io_b; // @[hello.scala 64:31]wire [15:0] _io_y_T_3 = io_a - io_b; // @[hello.scala 65:31]wire [15:0] _io_y_T_4 = io_a | io_b; // @[hello.scala 66:31]wire [15:0] _io_y_T_5 = io_a & io_b; // @[hello.scala 67:31]wire [15:0] _GEN_0 = 2'h3 == io_fn ? _io_y_T_5 : 16'h0; // @[hello.scala 60:10 63:19 67:23]wire [15:0] _GEN_1 = 2'h2 == io_fn ? _io_y_T_4 : _GEN_0; // @[hello.scala 63:19 66:23]wire [15:0] _GEN_2 = 2'h1 == io_fn ? _io_y_T_3 : _GEN_1; // @[hello.scala 63:19 65:23]assign io_y = 2'h0 == io_fn ? _io_y_T_1 : _GEN_2; // @[hello.scala 63:19 64:23]
endmodule
可以看到,ALU中对四种运算结果分别进行了计算,然后利用四个Mux选择选择信号对应的操作的计算结果,将输出给io_y
,和预期是一致的。
结语
这一篇就是对Chisel中模块的嵌套给出了更详细的说明,还以ALU的例子展现了Chisel模块的实现方法,其中新引入了switch
/is
结构,这在Chisel中是和Scala中是有所区别的,Scala的match
/case
结构和这个类型,但并不会映射到硬件,所以在数字设计中应该使用switch
/is
结构。下一篇文章我们会学习端口的整体连接(Bulk Connection),在连接模块的时候很好用。
吃透Chisel语言.15.Chisel模块详解(二)——Chisel模块嵌套和ALU实现相关推荐
- 【Python】模块详解/如何安装模块的方法
什么是模块 一.模块.包 ①模块 Python 模块(Module) 实质上就是一个python集成文件.它是用来组织代码的,包含了 Python 对象定义和Python语句,意思就是把python代 ...
- python的pygame模块详解_python游戏模块学习之pygame常规操作讲解
pygame常规操作 导入模块 import pygame # 导入pygame模块 from sys import exit # 导入退出鼠标点击事件 from math import pi # 导 ...
- 第五周-第11章节-Python3.5-内置模块详解之Xml模块
Python XML操作 XML(可扩展性标记语言)是一种非常常用的文件类型,主要用于存储和传输数据.在编程中,对XML的操作也非常常见. 本文根据python库文档中的xml.etree.Eleme ...
- python pexpect模块详解_python pexpect模块
Pexpect模块简介: Pexpect 是 Don Libes 的 Expect 语言的一个 Python 实现,是一个用来启动子程序,并使用正则表达式对程序输出做出特定响应,以此实现与其自动交互的 ...
- python logging模块详解_python logging模块使用总结
目录 logging模块 日志级别 CRITICAL 50 ERROR 40 WARNING 30 INFO 20 DEBUG 10 logging.basicConfig()函数中的具体参数含义 f ...
- python中os模块详解_Python OS模块(常见文件操作示例)
1 Python 常见文件操作示例 2. 3. os.path 模块中的路径名访问函数 4. 分隔 5. basename() 去掉目录路径 , 返回文件名 6. dirname() 去掉文件名 , ...
- python时间模块详解(time模块)
time 模块 -- 时间获取和转换 time 模块提供各种时间相关的功能 在 Python 中,与时间处理有关的模块包括:time,datetime 以及 calendar 必要说明: 虽然这个模块 ...
- python中time模块详解_Python time模块详解
time 模块主要包含各种提供日期.时间功能的类和函数.该模块既提供了把日期.时间格式化为字符串的功能,也提供了从字符串恢复日期.时间的功能. 在 Python 的交互式解释器中先导入 time 模块 ...
- python email模块详解_python email模块
python email模块 email模块 电子邮件包是一个用于管理电子邮件消息的库.它的特殊设计不用于向SMTP (RFC 2821).NNTP或其他服务器发送任何电子邮件消息;这些是模块的函数, ...
- python pexpect模块详解_python Pexpect模块如何使用 python Pexpect模块使用代码示例
python Pexpect模块如何使用?本篇文章小编给大家分享一下python Pexpect模块使用代码示例,文章代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以 ...
最新文章
- 【408预推免复习】计算机网络(谢希仁第七版)第一章——概述
- Vue+stylus实现自定义文字的loading组件
- MySQL--My.cnf配置文件模板 MYSQL AND MARIADB CONFIGURATION FILE TEMPLATE (MY.CNF/MY.INI)
- wget在进行https下载时超时不生效问题
- 如何才能在大数据中获取价值
- wordpress安装记录
- c语言编译器官网,C语言编译器app_c语言编译器app官网下载_c语言编译器手机版app-多特软件站安卓网...
- ios睡眠分析 卧床 睡眠_苹果ios14睡眠记录功能 让用户清楚的了解自己的睡眠
- html后代选择器的语法,后代选择器 | Descendant selectors
- 开放性金融中的超流动性抵押链
- 重要!SpringBoot一个非常蛋疼的无法启动的问题解决
- 浏览器设置跨域及允许携带cookie
- 个性化人工智能+区块链价值项目:PAI币Project PAI,威图Wetube Network
- 牛客Wannafly挑战赛9
- 音视频:12.FFmpeg-音乐播放器1
- 框架设计原则(梁飞)
- 教师资格证(中学)需要准备多长时间?
- Docker Ros melodic Error记录
- Windows 7切换语言
- (转)Windows远程登陆Linux桌面的方法