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有两个输入ab,两个输出xy,而模块B有两个输入in1in2以及一个输出out。所有的端口都是八位无符号整数类型。因为这个例子是为了解释模块是怎么连接到一起来构建层级的,所有就不展示模块内部的细节了,就用// function of xxx来代替了。因为我们没有和示例模块相关联的功能,所以我们就随便起的端口名,而在实际应用中应该起有描述性的名字,比如datavalidready等。

模块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有两个输入,也就是AB,一个功能输入,即fn,还有一个输出Y。ALU在输入AB上执行操作,然后将结果通过输出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实现相关推荐

  1. 【Python】模块详解/如何安装模块的方法

    什么是模块 一.模块.包 ①模块 Python 模块(Module) 实质上就是一个python集成文件.它是用来组织代码的,包含了 Python 对象定义和Python语句,意思就是把python代 ...

  2. python的pygame模块详解_python游戏模块学习之pygame常规操作讲解

    pygame常规操作 导入模块 import pygame # 导入pygame模块 from sys import exit # 导入退出鼠标点击事件 from math import pi # 导 ...

  3. 第五周-第11章节-Python3.5-内置模块详解之Xml模块

    Python XML操作 XML(可扩展性标记语言)是一种非常常用的文件类型,主要用于存储和传输数据.在编程中,对XML的操作也非常常见. 本文根据python库文档中的xml.etree.Eleme ...

  4. python pexpect模块详解_python pexpect模块

    Pexpect模块简介: Pexpect 是 Don Libes 的 Expect 语言的一个 Python 实现,是一个用来启动子程序,并使用正则表达式对程序输出做出特定响应,以此实现与其自动交互的 ...

  5. python logging模块详解_python logging模块使用总结

    目录 logging模块 日志级别 CRITICAL 50 ERROR 40 WARNING 30 INFO 20 DEBUG 10 logging.basicConfig()函数中的具体参数含义 f ...

  6. python中os模块详解_Python OS模块(常见文件操作示例)

    1 Python 常见文件操作示例 2. 3. os.path 模块中的路径名访问函数 4. 分隔 5. basename() 去掉目录路径 , 返回文件名 6. dirname() 去掉文件名 , ...

  7. python时间模块详解(time模块)

    time 模块 -- 时间获取和转换 time 模块提供各种时间相关的功能 在 Python 中,与时间处理有关的模块包括:time,datetime 以及 calendar 必要说明: 虽然这个模块 ...

  8. python中time模块详解_Python time模块详解

    time 模块主要包含各种提供日期.时间功能的类和函数.该模块既提供了把日期.时间格式化为字符串的功能,也提供了从字符串恢复日期.时间的功能. 在 Python 的交互式解释器中先导入 time 模块 ...

  9. python email模块详解_python email模块

    python email模块 email模块 电子邮件包是一个用于管理电子邮件消息的库.它的特殊设计不用于向SMTP (RFC 2821).NNTP或其他服务器发送任何电子邮件消息;这些是模块的函数, ...

  10. python pexpect模块详解_python Pexpect模块如何使用 python Pexpect模块使用代码示例

    python Pexpect模块如何使用?本篇文章小编给大家分享一下python Pexpect模块使用代码示例,文章代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以 ...

最新文章

  1. 【408预推免复习】计算机网络(谢希仁第七版)第一章——概述
  2. Vue+stylus实现自定义文字的loading组件
  3. MySQL--My.cnf配置文件模板 MYSQL AND MARIADB CONFIGURATION FILE TEMPLATE (MY.CNF/MY.INI)
  4. wget在进行https下载时超时不生效问题
  5. 如何才能在大数据中获取价值
  6. wordpress安装记录
  7. c语言编译器官网,C语言编译器app_c语言编译器app官网下载_c语言编译器手机版app-多特软件站安卓网...
  8. ios睡眠分析 卧床 睡眠_苹果ios14睡眠记录功能 让用户清楚的了解自己的睡眠
  9. html后代选择器的语法,后代选择器 | Descendant selectors
  10. 开放性金融中的超流动性抵押链
  11. 重要!SpringBoot一个非常蛋疼的无法启动的问题解决
  12. 浏览器设置跨域及允许携带cookie
  13. 个性化人工智能+区块链价值项目:PAI币Project PAI,威图Wetube Network
  14. 牛客Wannafly挑战赛9
  15. 音视频:12.FFmpeg-音乐播放器1
  16. 框架设计原则(梁飞)
  17. 教师资格证(中学)需要准备多长时间?
  18. Docker Ros melodic Error记录
  19. Windows 7切换语言
  20. (转)Windows远程登陆Linux桌面的方法

热门文章

  1. 测试听力软件在线,高考英语听力在线听每日测试
  2. win7启动提示:bootMGR被压缩
  3. 通过命令下载执行恶意代码的几种姿势
  4. python将文档转换成pdf_Python实现将DOC文档转换为PDF的方法
  5. 大学生毕业摆地摊月入两万的真实经历
  6. 小提琴和钢琴一起学行吗_小朋友有没有办法,同时学好钢琴和小提琴?
  7. 上海招聘java程序员有哪些要求
  8. 时过2年再读鸟哥私房菜,写一份读书笔记之第一章到第八章
  9. ARP欺骗原理及欣向路由的先天免疫(转)
  10. 欣向路由器:四大过人绝技的应用价值(转)