【数字集成电路与系统设计】基本的组合逻辑电路
目录
一、简单例子引入
1.1 端口声明
1.1.2 Verilog实现
1.1.3 Chisel实现
逐行解释
1.2 内部逻辑实现
1.2.1 Verilog实现
1.2.2 Chisel实现
Chisel 关键点解释
1.3 常用的硬件原语
二、Chisel主要数据类型介绍
2.1 数据类型
2.2 数据宽度
2.3 数据转换
2.4 运算类型
逻辑运算
位操作运算符
关系运算符
算数运算符
2.5 向量(Vec)和包裹(Bundle)类型
2.5.1 Vec 类型
2.5.2 Bundle 类型
2.5.3 Vec 和 Bundle 的结合使用
三、主要硬件类型和连线
3.1 模块(Module)定义
3.2 端口
3.3 硬件类型
3.4 赋值方法
3.5 选择器Mux
3.5.1. Mux(二输入多路选择器)
3.5.2. MuxCase(多路选择器)
3.5.3. MuxLookup(查找表多路选择器)
3.5.4. Mux1H(独热码多路选择器)
一、简单例子引入
1.1 端口声明

1.1.2 Verilog实现
在Verilog中,一个2-1选择器的模块定义如下:
module mux( input S, input D0, input D1, output Y
); // 内部逻辑实现(这里未展示)
endmodule
这个模块名为mux,它有四个端口:选择信号S和两个数据输入D0、D1,以及一个数据输出Y。每个端口的方向通过input和output关键字指定。
1.1.3 Chisel实现
在Chisel中,实现相同的2-1选择器模块如下:
import chisel3._ class mux extends Module { val io = IO(new Bundle { val S = Input(Bool()) val D0 = Input(Bool()) val D1 = Input(Bool()) val Y = Output(Bool()) }) // 内部模块连线(这里未展示具体的逻辑实现)
}
逐行解释
-
定义模块:
class mux extends Module { ... }定义了一个名为mux的类,该类继承自Module。在Chisel中,所有硬件模块都是通过继承Module类来定义的。 -
声明端口:
val io = IO(new Bundle { ... })定义了模块的输入输出端口。IO是Chisel中用于定义模块接口的方法,它接受一个Bundle对象作为参数。Bundle可以看作是Chisel中的结构体,用于组合多个信号。 -
端口方向和数据类型:在
Bundle内部,使用Input和Output方法指定端口的方向,并通过传递数据类型(如Bool())来指定端口的数据类型。这里S、D0、D1为输入端口,Y为输出端口,它们的数据类型都是Bool,表示1位的布尔信号。 -
数据类型:Chisel支持多种数据类型,如
Bool和UInt。Bool表示1位的二进制信号,而UInt(x.W)表示宽度为x的无符号整数,其中W是宽度的缩写。在本例中,我们只使用了Bool类型,但Chisel也支持更复杂的数据类型,以满足不同的设计需求。 -
内部逻辑实现:虽然在本例中未展示具体的内部逻辑实现,但通常会在
class定义的最后部分添加逻辑,以根据输入信号S、D0、D1计算输出信号Y的值。
这样,我们就完成了在Verilog和Chisel中定义一个2-1选择器模块的基本步骤。注意,在Chisel中,由于它基于Scala语言,所以语法和Verilog有所不同,但基本的设计思想是一致的。
1.2 内部逻辑实现
1.2.1 Verilog实现
在Verilog中,2选1选择器的实现可以直接根据逻辑表达式编写:
module mux( input S, input D0, input D1, output Y
); wire X = ~S;
wire Y1 = D0 & X;
wire Y2 = D1 & ~X; // 注意这里应该是 ~X 而不是 X,因为我们需要选择 D0 或 D1
assign Y = Y1 | Y2; // 这里实际上应该使用 Y2 = D1 & ~X 来确保逻辑正确
// 或者更直接地,使用 Y = (S ? D1 : D0); endmodule
1.2.2 Chisel实现
在Chisel中,我们可以使用Wire类型来定义中间信号,并使用Scala的运算符来实现逻辑表达式。以下是完整的Chisel实现:
import chisel3._ class mux extends Module { val io = IO(new Bundle { val S = Input(Bool()) val D0 = Input(Bool()) val D1 = Input(Bool()) val Y = Output(Bool()) }) val X = Wire(Bool()) // 定义Wire类型,用于中间信号 X := !io.S // 将io.S的值取反后赋值给X val Y1 = io.D0 & X // 定义并赋值Y1,使用&运算符进行位与操作 val Y2 = io.D1 & !X // 定义并赋值Y2,注意这里应该是!X io.Y := Y1 | Y2 // 将Y1和Y2进行位或操作,结果赋值给输出Y // 或者,更简洁地使用Chisel的Mux方法: // io.Y := Mux(io.S, io.D1, io.D0)
}
Chisel 关键点解释
- Wire 类型:在Chisel中,
Wire类型用于表示硬件单元之间的物理连线。Wire的值由其连接的器件输出端连续驱动。 - 类型推断:在Chisel中,如果直接写出运算式(如
io.D0 & X),Chisel会自动推断结果的类型。但显式声明类型(如val X = Wire(Bool()))可以提高代码的可读性和健壮性。 - 赋值操作符:在Chisel中,
:=用于表示电路的连接,而=则通常用于Scala中的值赋值。但在某些情况下,如直接定义Wire的运算表达式时,可以使用=,因为Chisel会处理这种情况下的类型推断和连接。 - Mux 方法:Chisel提供了
Mux方法,这是一个高级抽象,可以直接实现多路选择器功能,无需手动编写所有底层逻辑。
1.3 常用的硬件原语
Chisel的一大优势在于它提供了许多常用的硬件模块库,这些库中的模块可以直接被调用,从而大大简化了硬件设计的复杂度。对于上述实现的2选1多路选择器(mux),Chisel已经定义好了一个名为Mux的函数,该函数位于chisel3包中。因此,我们不需要从头开始编写选择器的底层逻辑,而是可以直接使用Mux函数来实现。
以下是使用Mux函数实现的2选1多路选择器的代码示例:
import chisel3._ class mux_2 extends Module { val io = IO(new Bundle { val S = Input(Bool()) // 选择信号 val D0 = Input(Bool()) // 数据输入0 val D1 = Input(Bool()) // 数据输入1 val Y = Output(Bool()) // 数据输出 }) // 使用Mux函数实现多路选择器 // 当io.S为true(即高电平)时,选择io.D0作为输出;当io.S为false(即低电平)时,选择io.D1作为输出 io.Y := Mux(io.S, io.D0, io.D1)
}
在这段代码中,Mux函数接收三个参数:第一个参数是选择信号io.S,它是一个布尔类型的输入;第二个和第三个参数分别是两个数据输入io.D0和io.D1,它们也都是布尔类型的输入。Mux函数根据选择信号的值来决定输出io.Y是接收io.D0的值还是io.D1的值。
Mux函数是硬件描述中非常常用的一个组件,它简化了多路选择逻辑的实现,使得硬件设计更加简洁和高效。在Chisel中,通过使用这些封装好的模块,开发者可以更加专注于系统级的设计,而不是陷入底层硬件逻辑的细枝末节中。
二、Chisel主要数据类型介绍
2.1 数据类型
在Chisel中,常用的数据类型包括UInt、SInt和Bool。这些数据类型用于表示电路中的信号,其中UInt用于无符号整数,SInt用于有符号整数(按补码解读),而Bool则用于表示单个位的布尔值。
-
UInt:可以表示电路中任意位宽的线网或寄存器。在Chisel中,
UInt字面量可以通过在整数值后添加.U后缀来构造,例如1.U表示字面值为1的UInt对象。此外,还可以使用Scala的BigInt、Int、Long类型的字面量,并通过隐式转换来构造UInt对象,这些字面量默认是十进制的,但可以通过前缀0x或0X指定为十六进制。 -
SInt:在Chisel中按补码解读,转换成Verilog后使用系统函数
$signed。SInt字面量可以通过在整数值(包括负数)后添加.S后缀来构造,例如-8.S表示字面值为-8的SInt对象。 -
Bool:用于表示1位宽的布尔信号。在Chisel中,
Bool字面量可以通过Scala的Boolean类型字面量(true或false)来构造,然后调用.B方法进一步得到Bool类型的对象,例如true.B。
Chisel定义了一系列隐式类来支持从Scala基本类型到Chisel数据类型的隐式转换,如fromBigIntToLiteral、fromIntToLiteral等。这些隐式类提供了U和S方法,分别用于构造等值的UInt和SInt对象。此外,Chisel还支持从字符串字面量构造UInt对象,字符串可以包含前缀h、o、b来分别表示十六进制、八进制和二进制,且可以使用下划线进行分隔以提高可读性。
示例:
1.U// 字面值为1的UInt对象0xd.U// 字面值为13(十六进制)的UInt对象-8.S// 字面值为-8的SInt对象"b01_01".U// 字面值为5(二进制)的UInt对象true.B// 字面值为true的Bool对象
这些字面量表示方法使得在Chisel中定义电路信号时更加直观和方便。
2.2 数据宽度
在Chisel中,数据宽度的处理非常灵活。默认情况下,字面量构造的UInt和SInt对象的宽度会根据字面值自动选择最小可能的位宽,例如字面值为8的UInt对象默认为4位宽(因为2^3 = 8,但考虑到符号位,实际上不会这样,这里可能是个误导,通常直接表示为4位的二进制表示,即00001000),而SInt对象由于需要表示负数,位宽会相应增加。然而,也可以显式指定数据的宽度。
Chisel通过Width类以及隐式类fromIntToWidth来支持宽度的显式指定。fromIntToWidth允许将Int对象隐式转换为fromIntToWidth类型的对象,进而通过W方法返回一个Width对象。UInt和SInt的构造方法(如U、asUInt、S、asSInt)都有重载版本,这些版本接收一个Width类型的参数来构造指定宽度的对象。
需要注意的是,Bool类型固定为1位宽,因此不能显式指定其宽度。
以下是一些示例:
1.U// 字面值为1,宽度为1bit的UInt对象1.U(32.W)// 字面值为1,但显式指定宽度为32bit的UInt对象1.U(32)// 这里有一个错误,因为.U方法不接受单个整数作为宽度参数,正确的方式是使用32.W1.U(0)// 这同样是不正确的,因为.U后面不能直接跟整数0作为宽度,应使用0.W(但通常不会这样做,因为0宽没有意义)
关于无字面量的对象构造,UInt和SInt的apply工厂方法允许通过指定宽度来构造对象,这对于声明端口、构造向量等场景非常有用。同时,也存在无参版本的apply方法,它们会尝试自动推断宽度(但通常用于字面量构造)。
结合数据类型和赋值方法,我们可以在模块内部进行如下声明和赋值:
val v0 = Wire(UInt(2.W)) // 声明一个2位宽的Wire,类型为UInt
val v1 = Wire(UInt(4.W)) // 声明一个4位宽的Wire,类型为UInt
val b0 = Wire(Bool()) // 声明一个Bool类型的Wire,固定为1位宽
val b1 = Wire(Bool()) // 另一个Bool类型的Wire v0 := 2.U // 将v0赋值为字面值2的UInt对象,自动推断为最小宽度,但这里明确是2位宽
v1 := "b01_01".U // 将v1赋值为二进制字面值"01_01"的UInt对象,这里显式指定了v1的位宽为4位
b0 := 1.U // 将b0赋值为字面值1的UInt对象,由于Bool是1位宽,这里实际上是将UInt值截断到最低位
b1 := true.B // 将b1赋值为Boolean字面量true的Bool对象,与1.U等价
请注意,尽管Bool可以被视为1位宽的UInt,但在实际使用中应保持类型的明确性,特别是在涉及到位宽敏感的场合。
2.3 数据转换
在Chisel中,UInt、SInt和Bool类型提供了asUInt、asSInt、asBool和asBools方法用于类型转换。这些方法允许在不同数据类型之间进行转换,但需要注意转换过程中可能发生的符号位和数值变化。
asUInt:将对象转换为无符号整数(UInt)。如果原始对象是SInt,则转换时保留其二进制表示不变,但解释方式变为无符号,可能会导致数值上的变化(如正负数表示)。asSInt:将对象转换为有符号整数(SInt)。如果原始对象是UInt,则直接按照其二进制表示解释为有符号数,可能需要考虑扩展符号位。asBool:仅当对象为1位宽时有效,将UInt或SInt的1或0值转换为Bool类型的true或false。asBools:将多位宽的UInt或SInt对象的每一位转换成一个Bool序列(Seq[Bool]),用于逐位操作。
示例中的类型转换如下:
-
"ha".asUInt(8.W)// 这里有一个错误,因为"ha"不是Chisel直接支持的字符串字面量格式。正确的十六进制表示应该使用前缀0x,如0xha(但注意ha不是有效的十六进制数,这里假设是0xa的误写)。正确的代码是:"0xa".U(8.W),这将构造一个字面值为0xa(即十进制中的10),宽度为8bit的UInt对象。 -
1.S(3.W).asUInt// 正确。这表示构造一个字面值为1,宽度为3bit的有符号整数(SInt),然后将其转换为无符号整数(UInt)。由于原始值是正数且位宽未超过表示范围,转换后的值仍然是1,但类型为UInt。
注意:在Chisel中,字符串到UInt或SInt的转换通常通过前缀(如0x表示十六进制,0b或b表示二进制,0o或o表示八进制,但八进制前缀在Chisel中可能不完全支持,具体取决于版本和上下文)和.U或.S后缀来实现,而不是直接调用asUInt或asSInt方法(这些方法用于类型之间的转换,而不是从字符串构造对象)。字符串"ha"在Chisel中不能直接转换为数字,因为它不是一个有效的数字表示。如果意图是表示十六进制数a(即十进制中的10),则应该使用"0xa"或0xa.U(指定宽度时加上.W后缀)。
2.4 运算类型
在Chisel中,对硬件描述语言(HDL)中的常见运算进行了抽象,以支持更高级别的硬件设计。以下是您提供的运算类型及其在Chisel中的解释,包括它们如何影响信号或值的位宽,以及(如果适用)这些运算在Verilog中的等价表示。
逻辑运算
!x:逻辑非,结果为1位宽。在Chisel中,直接对信号使用!运算符。x && y:逻辑与,但在Chisel中通常使用x & y进行位与操作,逻辑与在布尔上下文中使用。结果位宽为1,但在位运算中,结果位宽取决于操作数的最大位宽。x || y:逻辑或,同样,在Chisel中布尔上下文中使用|进行位或操作。结果位宽为1。
位操作运算符
~x:位反,结果位宽与x相同。在Verilog中为~signal_x。x & y:位与,结果位宽为max(w(x), w(y))。在Verilog中为signal_x & signal_y。x | y:位或,结果位宽同样为max(w(x), w(y))。在Verilog中为signal_x | signal_y。x ^ y:按位异或,结果位宽也为max(w(x), w(y))。在Verilog中为signal_x ^ signal_y。x(n):位索引,获取x的第n位(从0开始计数,0是最低位)。在Chisel中直接使用索引语法。x(n, m):字段提取,提取x中从n到m的位(包含n和m),结果位宽为n - m + 1。在Verilog中为signal_x[n:m]。x << n:左移,结果位宽为w(x) + n。在Verilog中为signal_x << n。x >> n:右移(补零),结果位宽为w(x) - n(但实际操作中可能保持原位宽,并丢弃高位)。在Verilog中为signal_x >> n,但注意Verilog中的右移可能依赖于信号的符号。Fill(n, x):重复拼接x,结果位宽为n * w(x)。在Verilog中没有直接等价,但可以用重复拼接的语法{n{signal_x}}表示。Cat(x, y):拼接x和y,结果位宽为w(x) + w(y)。在Verilog中为{signal_x, signal_y}。Mux(c, x, y):三元操作(多路选择器),结果位宽为max(w(x), w(y))。在Verilog中为signal_c ? signal_x : signal_y。
关系运算符
这些运算符通常用于布尔表达式,结果位宽为1。
x === y:相等(triple equals,在Chisel中可能用于精确匹配,包括位宽和值)。在Verilog中为signal_x == signal_y,但注意===在Verilog中有不同的含义(通常用于比较四个状态的值)。x != y、x =/= y:不等,结果相同。在Verilog中为signal_x != signal_y。x > y、x >= y、x < y、x <= y:大于、大于等于、小于、小于等于。
算数运算符
x + y:加,结果位宽为max(w(x), w(y))。在Verilog中为signal_x + signal_y。x +& y、x -& y:位扩加和位扩减,这些在Chisel中可能不直接对应,但在某些上下文(如固定点运算)中可能使用。Verilog中没有直接等价。x - y:减,结果位宽同样为max(w(x), w(y))。在Verilog中为signal_x - signal_y。x * y:乘,结果位宽为w(x) + w(y)(但可能需要额外的位宽以避免溢出)。在Verilog中为signal_x * signal_y。x / y:除,结果位宽通常与x相同(但可能依赖于实现和精度要求)。在Verilog中为signal_x / signal_y,但注意Verilog的除法可能与硬件实现有关。x % y:取余,结果位宽取决于y的最大可能值减1的位数。在Verilog中为signal_x % signal_y。
2.5 向量(Vec)和包裹(Bundle)类型
2.5.1 Vec 类型
Vec[T] 是一个固定大小的向量(或数组),其中 T 是向量的元素类型,如 UInt、SInt 或 Bool 等。所有元素的类型和位宽必须相同。Vec 提供了对元素的索引访问,使得在硬件设计中处理多个相同类型的信号变得非常方便。
使用场景:
- 当你需要处理多个相同类型和位宽的信号时(如多个数据通道、寄存器组等)。
- 在实现多路选择器(MUX)、寄存器文件或其他需要选择多个输入之一的逻辑时。
val myVec = Wire(Vec(3, UInt(2.W)))
myVec(0) := 0.U
myVec(1) := 1.U
myVec(2) := 2.U
在这个例子中,myVec 是一个包含3个2位宽无符号整数的向量。通过索引可以直接访问和修改这些元素。
2.5.2 Bundle 类型
Bundle 类似于C语言中的结构体,它允许你将多个不同类型的字段组合成一个单一的复合类型。Bundle 非常适合用于定义模块的端口列表或模块内部需要一起管理的信号集合。
使用场景:
- 定义模块的IO端口。
- 在模块内部组织相关信号,以提高代码的可读性和可维护性。
示例:
class MyModule extends Module { val io = IO(new Bundle { val in = Input(UInt(32.W)) val out = Output(UInt(32.W)) val enable = Input(Bool()) }) // 模块逻辑...
}
在这个例子中,MyModule 的端口列表被定义为一个 Bundle,包含了输入信号 in 和 enable,以及输出信号 out。这种方式使得端口的组织更加清晰,同时也便于在模块内部引用这些端口。
2.5.3 Vec 和 Bundle 的结合使用
在更复杂的设计中,Vec 和 Bundle 可以结合使用来构建更加复杂的数据结构和模块接口。例如,你可以定义一个 Vec,其元素类型为自定义的 Bundle,从而在一个向量中管理多个具有复杂结构的元素。
示例:
class ComplexSignal extends Bundle { val data = UInt(32.W) val valid = Bool()
} val signals = Vec(3, new ComplexSignal())
signals(0).data := 0.U
signals(0).valid := true.B
// ...
在这个例子中,signals 是一个包含3个 ComplexSignal 元素的向量。每个 ComplexSignal 都包含了一个32位宽的数据字段和一个有效标志位。这种方式允许你在单个向量中管理多个复杂信号,从而提高了设计的模块化和可重用性。
三、主要硬件类型和连线
3.1 模块(Module)定义
// 定义一个名为 AndModule 的类,它继承自 Chisel 的 Module 类
class AndModule extends Module { // 实现 Module 类的抽象成员 io,它是一个 Bundle,用于定义模块的接口 val io = IO(new Bundle { // 在 Bundle 内部声明输入端口 a 和 b,它们都是 Bool 类型 val a = Input(Bool()) val b = Input(Bool()) // 声明输出端口 c,它也是 Bool 类型 val c = Output(Bool()) }) // 在模块的体内部,使用 Chisel 的硬件赋值语句将输出端口 c 赋值为输入端口 a 和 b 的逻辑与 io.c := io.a & io.b
}
关键点说明:
-
继承 Module 类:
AndModule类通过继承Module类成为了一个 Chisel 模块。 -
隐式时钟和复位:虽然在这个简单的组合逻辑示例中没有直接使用到时钟(
clock)和复位(reset)信号,但它们是Module类的一部分,可以在需要时通过构造函数参数或其他方式引入。 -
实现抽象成员 io:每个
Module都必须实现一个名为io的抽象成员,它是一个Bundle,用于定义模块的接口。在这个Bundle中,你可以声明输入(Input)和输出(Output)端口,以及其他任何你需要的信号。 -
输入和输出端口:在
Bundle内部,你声明了两个输入端口a和b,以及一个输出端口c。输入端口用于接收外部信号,而输出端口用于向外部发送信号。虽然在这个例子中你“使用”了输入端口(通过将它们与输出端口进行逻辑与操作),但理论上即使你声明了输入端口而不直接使用它们,Chisel 也不会报错。然而,对于输出端口,你必须为它们赋值,因为它们是模块向外部世界提供信息的唯一途径。 -
硬件赋值:在模块的体内部,你使用
:=操作符将io.c赋值为io.a & io.b。这是 Chisel 中的硬件赋值语句,它表示在硬件层面上,输出c的值将始终等于输入a和b的逻辑与结果。
3.2 端口
在Chisel中,定义一个模块前首先需要定义好端口。整个端口列表是通过调用IO法来定义的,其中参数通常是一个Bundle类型的对象。对于继承自Module的模块,这个端口列表被引用为io。由于端口具有方向性(输入或输出),因此需要Input和Output方法来为每个端口指定具体的方向。注意,这里的source参数是数据类型,而不是已经实例化的硬件对象。
一旦端口列表定义完成,就可以通过io.xxx来访问和使用这些端口。输入端口可以被用来驱动模块内部的信号,而输出端口则可以被其他模块或信号驱动。
例如,定义一个包含向量输入和单个输出的Bundle:
class MyIO extends Bundle { val in = Input(Vec(5, UInt(32.W))) // 5个32位无符号整数组成的向量输入 val out = Output(UInt(32.W)) // 32位无符号整数的输出
}
然后,使用这个Bundle来定义模块的端口列表:
class MyModule extends Module { val io = IO(new MyIO) // 使用MyIO作为模块的端口列表 // 在这里可以添加模块的逻辑
}
对于两个相连的模块,如果它们的端口名称相同但方向相反,为了避免重复定义端口,Chisel提供了Flipped方法。这个方法可以翻转Bundle中所有端口的方向,即将输入端口转换为输出端口,将输出端口转换为输入端口。
例如,使用前面定义的MyIO,但翻转其端口方向:
class MyModule_1 extends Module { val io = IO(new MyIO) // in 是输入,out 是输出 // 模块逻辑...
} class MyModule_2 extends Module { val io = IO(Flipped(new MyIO)) // 此时,原MyIO中的out变为输入,in变为输出 // 模块逻辑,可能需要适应翻转后的端口方向
}
3.3 硬件类型
模块内部主要有 Wire(线网)和 Reg(寄存器)两种数据类型,他们分别用于描述数字电路里的组合逻辑和时序逻辑。Wire 之间的连线是不具有周期延迟,而 Reg 的输出和输出之间有一周期的延迟时间。
3.4 赋值方法
在Chisel中,由于硬件电路的本质是不可变的,因此所有的硬件对象都是通过val类型的变量来引用的。这意味着一旦一个变量在初始化时绑定了一个硬件对象,它的引用就不能改变指向另一个对象。然而,这并不意味着该硬件对象本身不能被更新或修改。为了支持这种更新机制,Chisel引入了特殊的赋值方法:=,它不同于Scala中的=赋值运算符。
例如,在定义了两个Wire类型的变量x和y之后,我们可以使用:=操作符来更新它们的值。这里,:=是Chisel中定义的特殊赋值方法,用于更新硬件对象的状态,而不是改变变量的引用。
// 定义两个4位宽的Wire类型变量
val x = Wire(UInt(4.W))
val y = Wire(UInt(4.W)) // 使用":="操作符向x赋予一个4位的无符号数10(二进制表示为"b1010")
x := "b1010".U // 将x的值按位取反,并将结果赋给y
y := ~x
需要注意的是,虽然":="操作符在语法上与=类似,但它们在语义上有着根本的区别。在Chisel中,":="用于硬件赋值,而=则用于变量初始化或数据赋值(这些赋值不会被编译成电路逻辑)。
3.5 选择器Mux
在Chisel中,多路选择器(MUX)是一个常用的电路模块,用于根据选择信号从多个输入中选择一个输出。Chisel提供了几种不同的多路选择器实现方式,每种都有其特定的用途和语法。以下是整理后的内容,尽量保持原信息的完整性和准确性:
3.5.1. Mux(二输入多路选择器)
Mux是最基本的多路选择器,位于chisel3包中。它接受一个布尔类型的选择信号sel和两个相同类型的数据输入in1、in2。当sel为true.B时,返回in1;否则返回in2。
Mux(sel, in1, in2)
Mux可以内嵌使用,以构建多输入多路选择器,类似于嵌套的三元操作符。
3.5.2. MuxCase(多路选择器)
MuxCase是chisel3.util包中提供的一个多路选择器的简便写法,用于处理多个选择条件。它接受一个默认值和一个条件-值对数组。
import chisel3.util._ MuxCase(default, Array(c1 -> a, c2 -> b, ...))
这里,default是当所有条件都不满足时返回的默认值,数组中的每个元素都是一个对偶,包含条件和对应的值。
3.5.3. MuxLookup(查找表多路选择器)
MuxLookup是MuxCase的一个变体,它将选择条件简化为从0开始的索引值,类似于查找表。它也位于chisel3.util包中。
MuxLookup(idx, defaultArray(0.U -> a, 1.U -> b, ...))
这相当于使用idx作为索引,从defaultArray中查找对应的值。如果idx不在有效范围内,则返回defaultArray中的默认值(如果有的话)。
3.5.4. Mux1H(独热码多路选择器)
Mux1H是chisel3.util包中的独热码多路选择器,它接受一个独热码作为选择信号,并从提供的值中选择一个输出。如果零个或多个选择信号有效,则行为不确定。
val hotValue = Mux1H(io.selector, Seq(2.U, 4.U, 8.U, 11.U))
// 或者
val hotValue = Mux1H(Seg(io.selector(0), io.selector(1), ...), Seq(2.U, 4.U, ...))
// 或者
val hotValue = Mux1H(Seq(io.selector(0) -> 2.U, io.selector(1) -> 4.U, ...))
在Mux1H中,io.selector是一个UInt类型的数据,其位宽应不小于待选择数据的个数。Mux1H会从低到高依次将io.selector的每一位作为选择信号,并与提供的被选择数据一一对应。
相关文章:
【数字集成电路与系统设计】基本的组合逻辑电路
目录 一、简单例子引入 1.1 端口声明 1.1.2 Verilog实现 1.1.3 Chisel实现 逐行解释 1.2 内部逻辑实现 1.2.1 Verilog实现 1.2.2 Chisel实现 Chisel 关键点解释 1.3 常用的硬件原语 二、Chisel主要数据类型介绍 2.1 数据类型 2.2 数据宽度 2.3 数据转换 2.4 运算…...
11. 建立你的第一个Web3项目
11. 建立你的第一个Web3项目 在这一部分,我们将带你一步步地建立一个简单的Web3项目,从环境搭建到智能合约的创建与部署,再到开发一个去中心化应用(dApp)并与智能合约交互。这是你迈向Web3开发的第一步。 1. 环境搭建…...
衡石分析平台使用手册-容器部署
容器部署 本文介绍如何在容器上部署 HENGSHI SENSE,以及部署后如何进行版本升级和数据备份。 部署前准备工作 单机部署前,请完成如下准备工作。 1.检查 docker 的环境。需要满足 Docker 版本 > 17.09安装 docker-compose。 2.获取并导入离线…...
静态库,动态库以及makefile基础
一.静态(链接)库 libfun.a 静态链接进可执行程序 可执行程序偏大 运行时只需要可执行程序即可 生成静态库步骤 gcc -c fun.c -o fun.o ar rcv libfun.a fun.o //需要用.o文件生成数据库 运行 gcc main.c libfun.a 二.动态库 libfun.so 动…...
Python基础语法(1)上
常量和表达式 我们可以把 Python 当成一个计算器,来进行一些算术运算。 print(1 2 - 3) print(1 2 * 3) print(1 2 / 3) 这里我们可能会有疑问,为什么不是1.6666666666666667呢? 其实在编程中,一般没有“四舍五入”这样的规则…...
使用 Python/java/go做一个微信机器人
E云是一套完整的的第三方服务平台,包含微信API服务、企微API服务、SCRM系统定制、企微系统定制、服务类软件定制等模块,本文档主要讲述个微API服务相关,以下简称API,它能处理用户微信中的各种事件,提供了开发者与个微对…...
【北京迅为】iTOP-i.MX6开发板使用手册第四部分固件编译第十四章非设备树Android4.4系统编译
可根据用户需求更换,百变定制,高端产品无忧! 迅为IMX6Q兼容四核商业级 、双核商业级、四核工业级 、更可提供i.MX6Q家族PLUS版本核心板。 核心板采用十层PCB沉金盲埋设计,更能保证电磁兼容与系统稳定。 公众号:迅为电…...
测评造假?Mistral首个多模态模型Pixtral 12B发布
测评造假?Mistral首个多模态模型Pixtral 12B发布! 近日,法国人工智能(AI)初创公司Mistral于9月11日宣布推出其首款多模态AI大模型——Pixtral 12B,成功吸引了全球科技界的广泛关注。这款集图像与文本处理能…...
【Java-简单练习题】
1.”AABBBCCC“>>"A2B3C3" public class Test6 {public static void main(String[] args) {String ns "AABBBCCCC";String retcompress(ns);System.out.println(ret);}public static String compress(String str) {StringBuilder ret new StringB…...
Notepad++ 下载安装教程
目录 1.下教程 2.安装教程 1.下教程 Downloads | Notepad (notepad-plus-plus.org) 进入下载地址后选择最新版点击连接 点击链接后,向下滑动,下载适合自己电脑版本的安装包 这里大家没有梯子可能打不开页面,可以直接从本文开头下载。 2.安…...
shader 案例学习笔记之smoothstep函数
参考:smoothstep 用来生成0-1的平滑过渡值 smoothstep函数源码实现: float smoothstep(float t1, float t2, float x) {// Scale, bias and saturate x to 0..1 rangex clamp((x - t1) / (t2 - t1), 0.0, 1.0); // Evaluate polynomialreturn x * x *…...
大模型的第一个杀手级应用场景出来了
大家终于都意识到大模型首先改变的是软件行业自己,而软件的根基是代码生成。代码生成第一波就是AI辅助开发,这个会是大模型第一个杀手级应用。大家苦苦逼问自己的大模型杀手级应用,为什么会是辅助编程,这里说下什么: 必…...
不允许有程序员不知道这款AI代码扩写工具
01CodeGeeX编程大模型 在介绍什么是codeGeeX之前,先上图。 想象一下,自己写代码的时候旁边有个专家助手,随时跟你解释前面别人写的代码是什么意思,有什么缺陷。在你自己写的时候也可以每一步进行代码提示和代码扩写,是…...
java 的list集合排序自定义元素
在 Java 中,可以对包含自定义元素的List集合进行排序。通常可以使用Collections.sort()方法结合自定义的比较器来实现。 一、定义包含自定义元素的类 假设我们有一个表示学生的类Student: class Student {private int id;private String name;private …...
【数学建模】2024数学建模国赛经验分享
文章目录 一、关于我二、我的数模历程三、经验总结: 一、关于我 我的CSDN主页:https://gxdxyl.blog.csdn.net/ 2020年7月(大二结束的暑假)开始在CSDN写作: 阿里云博客专家: 接触的领域挺多的ÿ…...
Scala尾递归解决爆栈问题
引言 我在上篇中详细的讲了递归的一系列问题,多路递归,爆栈问题,尾递归优化等,今天就实际演示一下尾递归是如何解决爆栈问题的,以及它的原理是什么? 支持尾递归优化的语言 尾递归是一种特殊的递归形式,如果…...
【观察者】设计模式:构建灵活且响应式的软件系统
引言 在软件开发中,我们经常面临需要在多个对象之间进行通信的挑战。特别是当一个对象的状态发生变化时,我们希望所有依赖于这个状态的对象都能自动更新。这就是观察者设计模式大显身手的地方。 简介 观察者模式是一种行为设计模式,它定义…...
开源网安斩获CCIA中国网络安全创新创业大赛总决赛三等奖
近日,由中央网信办指导,中国网络安全产业联盟(CCIA)主办的2024年中国网络安全创新创业大赛总决赛及颁奖典礼在国家网络安全宣传周落下帷幕。开源网安“AI代码审核平台CodeSec V4.0” 凭借在AI方向的技术创新、技术突破及功能应用创…...
进程的同步与互斥
目录 一、进程同步 二、进程互斥 1.临界资源访问代码: ①进入区 ②临界区 ③退出区 ④剩余区 注: 2.互斥准则: ①.空闲让进。 ②.忙则等待。 ③.有限等待。 ④.让权等待。 三、进程互斥的软件实现方法 1.单标志法 2.双标志先…...
基础的八股
JS this 全局:this指向window 函数:this指向window 对象:this指向调用它的 get、post的区别 1、写的地方不同:get在地址栏里 地址栏有多长就只能写多少、post在请求体里 没有上限 2、关于回退和刷新:get回退和刷新没问…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
