当前位置: 首页 > article >正文

【数字集成电路与系统设计】一些Chisel语法的介绍

目录

一、switch语句

二、MuxLookup

三、when

四、Vec/VecInit

Seq

Vec

VecInit

Vec 和 VecInit 的区别

五、PriorityMux

六、Reg/RegInit

七、RegEnable / RegNext

八、log2Ceil


一、switch语句

在Chisel中,switch语句是一种强大的结构,用于根据某个信号的值来选择性地执行不同的代码块。这与许多传统编程语言中的switchcase语句非常相似,但Chisel的switch语句被设计用于硬件描述领域,因此它处理的是硬件信号而不是简单的变量值。

下面是对switch语句在Chisel中的用法进行整理后的内容:

// 假设state是一个Chisel的信号,它的类型可以是UInt、Bool等  
// s0, s1, s2是state信号可能取的值,它们应该与state的类型相匹配  
// 例如,如果state是UInt(2.W),那么s0, s1, s2可能是UInt(0.U), UInt(1.U), UInt(2.U)  
  
switch(state) {  
  is(s0) {  
    // 当state的值等于s0时,执行这里的代码  
    // 这里可以放置对硬件行为的描述,如寄存器赋值、逻辑运算等  
  }  
  is(s1) {  
    // 当state的值等于s1时,执行这里的代码  
    // 类似于上面的描述,可以包含各种硬件设计元素  
  }  
  is(s2) {  
    // 当state的值等于s2时,执行这里的代码  
    // 继续描述在特定状态下的硬件行为  
  }  
  // 如果需要,还可以添加一个默认情况,类似于其他编程语言中的default:  
  // otherwise {  
  //   // 当state的值不是s0、s1、s2中的任何一个时,执行这里的代码  
  // }  
}

需要注意的是,switch语句中的is关键字用于指定每个分支的条件,即state信号应该匹配的值。

二、MuxLookup

在Chisel中,MuxLookup 函数提供了一种便捷的方式来实现基于选择信号(sel)的多路选择器(Mux),它根据sel的值从一组预定义的映射中选择一个输入信号,并将其传递到输出端。如果sel的值不匹配任何预定义的映射项,则输出一个指定的默认值。

// 假设sel是一个选择信号,其类型通常为UInt或Bool,但在这里我们假设它是UInt  
// in0, in1, in2, in3是输入信号,它们可以是任何Chisel支持的信号类型,但类型必须一致  
// default是当sel不匹配任何预定义值时的默认输出  
  
// 使用MuxLookup函数来根据sel的值选择输入信号  
val result = MuxLookup(sel, default, Array(  
  (0.U) -> in0,  // 当sel为0时,result = in0  
  (1.U) -> in1,  // 当sel为1时,result = in1  
  (2.U) -> in2,  // 当sel为2时,result = in2  
  (3.U) -> in3   // 当sel为3时,result = in3  
))  
  
// 如果sel的值不是0, 1, 2, 或3中的任何一个,则result = default

在这个例子中,sel是一个选择信号,它决定了从哪个输入信号(in0in1in2in3)中选择输出到result。每个输入信号都通过一个元组(UInt -> Signal)sel的一个可能值相关联,其中UIntsel的值,Signal是对应的输入信号。default是当sel的值不匹配任何预定义项时的输出值。

三、when

在Chisel中,when语句确实用于条件判断和执行,其工作方式类似于许多其他编程语言中的if-else结构。when语句允许你根据条件表达式的值来选择性地执行代码块。

// cond 和 otherCond 是条件表达式,它们可以是任何返回Bool类型的Chisel表达式  
// 当 cond 为 true 时,执行第一个代码块  
when (cond) {  
  // 当 cond 为 true 时执行的代码  
} .elsewhen (otherCond) {  
  // 当 cond 为 false 且 otherCond 为 true 时执行的代码  
} .otherwise {  
  // 当 cond 和 otherCond 都为 false 时执行的代码  
}

在这个例子中,when语句首先检查cond是否为真。如果cond为真,则执行紧随其后的代码块。如果cond为假,则继续检查.elsewhen后面的otherCond。如果otherCond为真,则执行.elsewhen代码块中的代码。如果condotherCond都为假,则执行.otherwise代码块中的代码。

四、Vec/VecInit

Seq

在Scala中,Seq是一个集合类,用于存储多个元素。Seq是不可变的,即一旦创建,其内容就不能被改变。在Chisel中,Seq常用于初始化Vec或进行其他类型的集合操作,因为它提供了一种灵活的方式来表示和操作一系列的元素。例如:

val mySeq = Seq(1.U, 2.U, 3.U, 4.U)

这里,mySeq是一个包含四个1位宽无符号整数元素的不可变序列。

Vec

Vec是Chisel特有的数据结构,用于定义向量(或数组)类型,可以存储多个相同类型的元素。Vec常用于需要处理多组数据的场景,如多输入多输出信号的处理。Vec是动态的,可以在运行时被修改和访问。例如:

val myVec = Wire(Vec(4, UInt(8.W)))  
myVec(0) := 10.U  
val firstElement = myVec(0)

在这个例子中,myVec是一个包含四个8位宽无符号整数的向量,可以通过索引访问和修改其元素。

VecInit

VecInit是一个方法,用于将Seq中的元素转换为Vec。这在静态初始化Vec时非常有用,因为Seq提供了一种方便的方式来定义一系列的元素。例如:

val myVec = VecInit(Seq(1.U, 2.U, 3.U, 4.U))

这里,myVec是一个包含四个1位宽无符号整数元素的向量,这些元素是通过VecInitSeq转换而来的。

Vec 和 VecInit 的区别

  1. 定义方式的区别
    • Vec在定义时需要指定其长度和元素的类型,通常用于动态创建和定义一个向量。
    • VecInit则用于静态初始化一个向量,其元素在初始化时已经确定,并且是从一个Seq中转换而来的。
  2. 使用场景
    • 当需要一个可以动态操作和修改的向量时,使用Vec更为灵活。
    • 当需要一个预定义的、固定的向量时,使用VecInit更为简洁和方便。

五、PriorityMux

PriorityMux 在 Chisel 中用于实现优先级选择器,它根据输入信号的优先级顺序选择第一个有效的输入信号并将其传递到输出端。下面是一个 PriorityMux 的示例:

 val selSignals = Seq(cond0, cond1, cond2, cond3)
 val inputs = Seq(in0, in1, in2, in3)
 val result = PriorityMux(selSignals zip inputs)

在这个例子中,selSignals 是一组条件信号,当 cond0 为真时,result 输出 in0;如果cond0 为假且 cond1 为真,result 输出 in1,依此类推。如果所有条件信号都为假,PriorityMux 将输出默认值 default。

六、Reg/RegInit

在 Chisel 中,Reg 和 RegInit 用于定义和初始化寄存器。寄存器是一个存储单元,可以在时钟边沿存储和输出数据。
Reg 用于定义一个寄存器,可以存储一个指定类型的数据,但在定义时不会初始化寄存器的值,需要在电路运行过程中进行赋值。例如:

val myReg = Reg(UInt(8.W))

在这个例子中,myReg 是一个 8 位宽的无符号整数寄存器。
RegInit 用于定义并初始化寄存器,它在定义寄存器的同时为寄存器赋予一个初始值。例如:

val myRegInit = RegInit(0.U(8.W))

在这个例子中,myRegInit 是一个 8 位宽的无符号整数寄存器,并且初始值为 0。
Reg 和 RegInit 的区别主要体现在两个地方:
1)初始化:Reg 定义的寄存器在初始化时没有指定值,而 RegInit 定义的寄存器在初始化时有一个指定的初始值。
2)使用场景:Reg 适用于需要在电路运行过程中动态赋值的场景,而 RegInit 适用于需要在电路初始化时指定初始值的场景。

七、RegEnable / RegNext

RegEnable 用于定义一个带使能信号的寄存器。使能信号用于控制寄存器的更新,只有当使能信号为真时,寄存器才会在时钟边沿更新其值(注意:Chisel 中默认的有效时钟边沿是上升沿)。

val enable = true.B
val myRegEnable = RegEnable(next = 3.U, init = 0.U, enable = enable)

在这个例子中,myRegEnable 是一个带使能信号的寄存器,初始值为 0,当 enable 为真时,寄存器更新值为 3。

RegNext 用于创建一个时钟周期延迟的寄存器,它将当前周期的输入值在下一个时钟周期输出。

val myRegNext = RegNext(next = 3.U, init = 0.U)

在这个例子中,myRegNext 是一个寄存器,初始值为 0,每个时钟周期将输入值 3 存储并在下一个时钟周期输出。

RegEnable 和 RegNext 的区别主要体现在:RegEnable 需要一个使能信号来控制寄存器是否更新,适用于需要在特定条件下更新寄存器的场景。RegNext 则是实现时钟周期延迟,不需要使能信号,每个时钟周期都会更新寄存器的值。

八、log2Ceil

log2Ceil 是 Chisel 中的一个实用函数,用于计算一个给定整数的以 2 为底的对数,并向上取整。这个函数在设计硬件时尤其有用,因为它可以帮助确定存储某个最大值所需的最小位宽。它位于 chisel3.util 这个 package 中,需要 import chisel3.util._ 来导入。
例如,如果我们需要计数到 15,那么计数器的位宽至少要是 4 位,因为 2^4 = 16 是大于或等于 15 的最小 2 的幂。log2Ceil 可以帮助我们自动计算出这个位宽,而不需要手动计算。对应到下面的代码中,如果 value=15,那么 width=4。

val width = log2Ceil(value)

http://www.kler.cn/a/301650.html

相关文章:

  • 基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
  • C++之内存管理
  • 使用 Ant Design Vue 自定渲染函数customRender实现单元格合并功能rowSpan
  • 遇到 mysql_config not found 错误
  • Shell基础(4)
  • 力扣题目解析--括号生成
  • 二、Maven工程的创建--JavaSEJavaEE
  • Element UI按钮组件:构建响应式用户界面的秘诀
  • vue3 ref
  • ffmpeg7.0 AVFrame的分配与释放
  • 使用 DBeaver 创建 MySQL 数据库
  • 第十五届蓝桥杯图形化省赛题目及解析
  • 前端 PDF 预览技巧:标签 vs 插件,如何优雅地展示 PDF 文件
  • 6、多线程
  • 如何使用python运行Flask开发框架并实现无公网IP远程访问
  • 力扣刷题之2555.两个线段获得的最多奖品
  • 装杯 之 Linux 指令1
  • 哈希表及算法
  • xLSTM模型学习笔记
  • 高性能计算机A100会带有BMC功能 ;BMC;SSH
  • Thinkphp5实现一周签到打卡功能
  • 前端算法(持续更新)
  • Linux_kernel移植rootfs10
  • 普发Pfeiffer TCP600TCP5000手侧
  • Python——贪吃蛇
  • JAVA基础:抽象类,接口,instanceof,类关系,克隆