吃透Chisel语言.15.Chisel模块详解(二)——Chisel模块嵌套和ALU实现

2023-10-29

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和模块B
    val compA = Module(new CompA())
    val compB = Module(new CompB())
    // 连接A
    compA.io.a := io.in_a
    compA.io.b := io.in_b
    io.out_x := compA.io.x
    // 连接B
    compB.io.in1 := compA.io.y
    compB.io.in2 := io.in_c
    io.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())
    
    // 连接C
    c.io.in_a := io.in_a
    c.io.in_b := io.in_b
    c.io.in_c := io.in_c
    io.out_m := c.io.out_x
    // 连接D
    d.io.in := c.io.out_y
    io.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),在连接模块的时候很好用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

吃透Chisel语言.15.Chisel模块详解(二)——Chisel模块嵌套和ALU实现 的相关文章

  • 数码管电子时钟

    文章目录 前言 一 回顾数码管 二 任务描述 三 系统框图 四 模块调用 五 模块原理图 六 工程源码 6 2 时钟计数模块代码 6 2 数码管驱动模块代码 6 3 顶层模块代码 七 仿真测试 7 1 测试代码 7 2 仿真结果 八 管脚信
  • 【Xilinx DDR3 MIG】Xilinx FPGA DDR3读写实验相关用户接口引脚解释

    目录 DDR3读写实验 实验框图 时钟模块 DDR3读写及LED指示模块 MIG IP核 用户接口解释
  • 【DDR3 控制器设计】(3)DDR3 的写操作设计

    写在前面 本系列为 DDR3 控制器设计总结 此系列包含 DDR3 控制器相关设计 认识 MIG 初始化 读写操作 FIFO 接口等 通过此系列的学习可以加深对 DDR3 读写时序的理解以及 FIFO 接口设计等 附上汇总博客直达链接 DD
  • 【Xilinx Vivado时序分析/约束系列4】FPGA开发时序分析/约束-实验工程上手实操

    目录 建立工程 添加顶层 模块1 模块2 添加约束文件 编辑时钟约束 打开布线设计 代码代表的含义 时序报告 进行时序分析 Summary 包含了汇总的信息量 Source Clock Path 这部分是表示Tclk1的延时细节 Data
  • [从零开始学习FPGA编程-28]:进阶篇 - 基本组合电路-奇偶校验生成器(Verilog语言版本)

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 目录 第1章 奇偶校验生成器 1 1 什么是奇校验 1 2 Verilog语言描述
  • [HDLBits] Exams/ece241 2014 q7a

    Design a 1 12 counter with the following inputs and outputs Reset Synchronous active high reset that forces the counter
  • PAJ7620U2手势识别——配置0x00寄存器(3)

    文章目录 前言 一 为啥要配置0x00寄存器 二 配置步骤 1 单个读操作步骤图 2 模块状态转移图绘制 3 模块波形图绘制 4 上板验证 5 参考代码 总结 前言 在前面的教程中 小编带领各位读者学习了如何通过I2C协议去唤醒PAJ762
  • 【FPGA】通俗理解从VGA显示到HDMI显示

    注 大部分参考内容来自 征途Pro FPGA Verilog开发实战指南 基于Altera EP4CE10 2021 7 10 上 贴个下载地址 野火FPGA Altera EP4CE10征途开发板 核心板 野火产品资料下载中心 文档 hd
  • 了解用于函数调用的 auipc+jalr 序列

    我试图阅读RISC V生成的程序集gcc我发现gcc创建序列auipc jalr对于某些函数调用 我不明白它是如何工作的 这是一个简单的例子 考虑以下C源文件 unsigned long id unsigned long x return
  • 串口通信知识点总结

    串口是串行接口 serial port 的简称 也称为串行通信接口或COM接口 串口通信是指采用串行通信协议 serial communication 在一条信号线上将数据一个比特一个比特地逐位进行传输的通信模式 串口按电气标准及协议来划分
  • 基于FPGA的简易BPSK和QPSK

    1 框图 2 顶层 3 m generator M序列的生成 输出速率为500Kbps 4 S2P是串并转换模块 将1bit的m序列转换到50M时钟下的2bit M序列数据 就有4个象限 5 my pll是生成256M的时钟作为载波 因为s
  • 凿子3.功能模块Mux4

    我正在按照文档学习 Chisel在 Github 上 https github com ucb bar chisel3 wiki Short 20Users 20Guide 20to 20Chisel 到目前为止 一切都完美无缺 但我还是卡
  • Matlab图像处理系列——图像复原之噪声模型仿真

    微信公众号上线 搜索公众号 小灰灰的FPGA 关注可获取相关源码 定期更新有关FPGA的项目以及开源项目源码 包括但不限于各类检测芯片驱动 低速接口驱动 高速接口驱动 数据信号处理 图像处理以及AXI总线等 本节目录 一 图像复原的模型 二
  • Vivado ILA的debug信息保存与读取

    保存 write hw ila data D Project FPGA ILA Debug Data 202401041115 ila upload hw ila data hw ila 1 读取 display hw ila data r
  • RISC-V 使用 LUI 和 ADDI 构建 32 位常量

    LUI 加载立即数 用于构建32位常量并使用U型格式 LUI 将 U 立即数放入目标寄存器 rd 的高 20 位 并用零填充最低 12 位 我在手册中找到了这个 但是如果我想将 0xffffffff 移动到寄存器 我需要的所有代码是 LUI
  • DSCA190V 57310001-PK

    DSCA190V 57310001 PK DSCA190V 57310001 PK 具有两个可编程继电器功能 并安装在坚固的 XP 外壳中 DSCA190V 57310001 PK 即可使用 只需最少的最终用户校准 DSCA190V 573
  • 为定制 RISC-V imafd SOC 移植 Linux

    我正在尝试构建一个 yocto演示 coreip cli我的自定义 risc v SOC 的图像仅支持imafd指示 对于 Bitbake 使用的交叉工具链的编译 我尝试更改 openembedded core 层中的 cross binu
  • RISC-V 调用约定的 ABI 寄存器名称

    我对 RISC V ABI 寄存器名称感到困惑 例如 第 85 页的 RISC V 指令集手册 第一卷 用户级 ISA 版本 2 0 中的表 18 2 指定堆栈指针sp正在注册x14 然而 指令 addi sp zero 0 由 riscv
  • RISC-V 规范引用了“hart”一词 - “hart”是什么意思?

    我找到了参考文献hart在第 35 页RISC V 2 1 规范 https content riscv org wp content uploads 2016 06 riscv spec v2 1 pdf 但是 我找不到它的定义hart在
  • 为什么 RISC-V S-B 和 U-J 指令类型以这种方式编码?

    我正在读一本书 计算机组织与设计RISC V版 我遇到了 S B 和 U J 指令类型的编码 我上面提到的那些类型有奇怪的编码立即字段 S B 类型将直接字段分为两部分 这是有道理的 因为所有指令编码都必须相似 但我无法理解为什么立即字段以

随机推荐

  • C++ STL之vector用法总结

    转自 https www cnblogs com zhonghuasong p 5975979 html 介绍 vector是表示可变大小数组的序列容器 就像数组一样 vector也采用的连续存储空间来存储元素 也就是意味着可以采用下标对v
  • java总结(不断更新)

    总结一句话 基础很重要 记得时而复习之 一轮人事 人事初步了解情况并推给技术部 二轮技术部 技术部电话面试 三轮面试技术以及对应客户 面试情况如下 自我介绍 项目经历 碰到的技术难点 java某个类的使用情况 字符串 长短值 类的加载机制
  • swagger-02-配置swagger

    1 4 配置swagger package com example config import org springframework context annotation Bean import org springframework c
  • Android UI 模板

    简单学习了Android UI 模板 自定义的UI模板 在自己设计的app中可以进行有效的代码复用 在这里做个流程整理 之后再添加漂亮的效果 首先加个在线阅读Android 源码的链接 点击打开链接 花个时间阅读一下系统的封装方法对学习An
  • 基于SSM框架的百货中心供应链管理系统

    社会发展日新月异 用计算机应用实现数据管理功能已经算是很完善的了 但是随着移动互联网的到来 处理信息不再受制于地理位置的限制 处理信息及时高效 备受人们的喜爱 本次开发一套百货中心供应链管理系统有管理员 人事 财务 销售 采购 服务六个角色
  • 突破对银河系的传统认知 大量超高能宇宙加速器被发现

    宇宙无限 信使有痕 5月17日 国家重大科技基础设施 高海拔宇宙线观测站 LHAASO 公布在银河系内发现大量超高能宇宙加速器 并记录到能量达1 4拍电子伏的伽马光子 拍 千万亿 这是人类观测到的最高能量光子 突破了人类对银河系粒子加速的传
  • C# 实现生成一维码、二维码

    注意 需要使用以下库文件 using ThoughtWorks QRCode Codec using ZXing using ZXing Common using ZXing QrCode 具体实现如下所示 帮助类一 using Syste
  • ES学习——ES评分简单介绍

    当我们能使用match来搜索匹配数据的时候 es会给每一个文档进行评分 匹配度 并根据评分的大小对结果文档进行排序 介绍 es的实时评分机制是基于 Lucene 的基础上实现的 最常见的是 TF IDF和BM25这两种评分模型 TF IDF
  • ElasticSearch配置

    2 搭建ElasticSearch环境 2 1 拉取镜像 docker pull elasticsearch 7 4 0 2 2 创建容器 docker run id name elasticsearch d restart always
  • JavaScript和jQuery的基础知识和使用

    初识JavaScript 首先对于JavaScript和Java两种语言 除了语法和Java有些类似 其他部分没有任何关系 由于当时Java很火 为了推广才在名字中加了Java 也就是所谓的蹭热度 另外 与JavaScript共同提起的还有
  • ModuleNotFoundError: No module named ‘forms‘

    问题 导入自定模块的时候报错 找不到模块 解决办法 将导入模块的代码写在靠近应用该模块的地方
  • MPLS实验

    MPLS第一次试验 公网地址配置 R2 GigabitEthernet0 0 1 23 1 1 1 24 LoopBack0 2 2 2 2 24 R3 GigabitEthernet0 0 0 23 1 1 2 24 GigabitEth
  • C语言文件读入---跳过第一行和最后一行

    include
  • 【FreeRtos学习笔记】STM32 CubeMx——Timers(定时器)

    目录 1 软件定时器 2 示例程序 2 1 例程功能 2 2 步骤 2 3 实验结果 2 4 函数讲解 1 软件定时器 定时器是MCU常用的外设 我们在学习各种单片机时必然会学习它的硬件定时器 但是 MCU自带的硬件定时器资源是有限的 而且
  • Android Fragment 生命周期图

    http www cnblogs com purediy p 3276545 html
  • 开发技术--浅谈python数据类型

    开发 浅谈python数据类型 在回顾Python基础的时候 遇到最大的问题就是内容很多 而我的目的是回顾自己之前学习的内容 进行相应的总结 所以我就不玩基础了 很多在我实际生活中使用的东西 我会在文章中提一下 并且我自己会根据这些内容进行
  • C++从入门到放弃之:Hello.cpp

    C 从入门到放弃 Hello cpp 1 创建c 程序源代码 2 C 程序的编译 3 C 扩展名 4 C 头文件 5 C 输入输出流 Hello cpp 1 创建c 程序源代码 vim hello cpp include
  • Unity3D+EasyAR实现AR效果的案例

    1 下载EasyAR的压缩包以及下面我要用到的霸王龙模型 链接 https pan baidu com s 12q4Jp11BMxnIW1DB48yy0Q 密码 1y3y 2 新建一个Unity3D的项目 然后双击下载好的EasyAR 将其
  • 分支-07. 比较大小(10)

    本题要求将输入的任意3个整数从小到大输出 输入格式 输入在一行中给出3个整数 其间以空格分隔 输出格式 在一行中将3个整数从小到大输出 其间以 gt 相连 输入样例 4 2 8 输出样例 2 gt 4 gt 8 程序 include int
  • 吃透Chisel语言.15.Chisel模块详解(二)——Chisel模块嵌套和ALU实现

    Chisel模块详解 二 Chisel模块嵌套和ALU实现 稍微复杂点的硬件设计就需要用嵌套的模块层级来构建了 上一篇文章中实现的计数器其实就是个例子 计数器内部嵌套了一个寄存器 一个Mux和一个加法器 这一篇文章就仔细讲解模块之间是怎么连