前言
到目前为止,Chisel中的硬件实现都还能和软件对应上。 在控制流中,硬件和软件将开始会有很大的不同。 这一节中会介绍软件生成器中的控制流和硬件中的控制流。 例如重新连接Chisel中的线(wire)会发生什么? 怎样定义一个具有两个以上输入的多路复用器?
重复赋值
Chisel 用 := 声明连接接口。Chisel允许多个接口连接到同一个接口A的情况,在这样的情况下,接口A会和最后一个声明的接口相连。
class LastConnect extends Module {
val io = IO(new Bundle {
val in = Input(UInt(4.W))
val out = Output(UInt(4.W))
})
io.out := 1.U
io.out := 2.U
io.out := 3.U
io.out := 4.U // 最后接口out会得到值为4的信号。
}
println(getVerilog(new LastConnect))
// Test LastConnect
test(new LastConnect) { c => c.io.out.expect(4.U) } // Assert that the output correctly has 4
println("SUCCESS!!") // Scala Code: if we get here, our tests passed!
生成的verilog代码:可见位宽为4的十六进制数4被赋给了输出。
module LastConnect(
input clock,
input reset,
input [3:0] io_in,
output [3:0] io_out
);
assign io_out = 4'h4; // @[cmd3.sc 9:10]
endmodule
基础判断语句when
, else when
, 和 otherwise
Chisel的基础判断语句为when
, else when
, and otherwise
, 具体用例:
when(someBooleanCondition) {
// 当someBooleanCondition判断语句为真,执行该句
}.elsewhen(someOtherBooleanCondition) {
// things to do on this condition
}.otherwise {
// 当以上的判断语句都为假,执行该句
}
//注意这里的 < . >
注意:
-
w h e n → e l s e w h e n → o t h e r w i s e when\rightarrow elsewhen\rightarrow otherwise when→elsewhen→otherwise 使用顺序不能打乱。
可以对等C的 i f → e l s e i f → e l s e if\rightarrow elseif \rightarrow else if→elseif→else , 中间想用多少个elsewhen都无所谓。
-
与Scala中的if不同的是, when, elsewhen 和 otherwise语句并不返回值。因此以下使用是非法的:
val result = when(squareIt) { x * x }.otherwise { x }
实例
// Max3 返回三个值中的最大值
class Max3 extends Module {
val io = IO(new Bundle {
val in1 = Input(UInt(16.W))
val in2 = Input(UInt(16.W))
val in3 = Input(UInt(16.W))
val out = Output(UInt(16.W))
})
when(io.in1 >= io.in2 && io.in1 >= io.in3) {
io.out := io.in1
}.elsewhen(io.in2 >= io.in3) {
io.out := io.in2
}.otherwise {
io.out := io.in3
}
}
// Test Max3
test(new Max3) { c =>
// verify that the max of the three inputs is correct
c.io.in1.poke(6.U)
c.io.in2.poke(4.U)
c.io.in3.poke(2.U)
c.io.out.expect(6.U) // input 1 should be biggest
c.io.in2.poke(7.U)
c.io.out.expect(7.U) // now input 2 is
c.io.in3.poke(11.U)
c.io.out.expect(11.U) // and now input 3
c.io.in3.poke(3.U)
c.io.out.expect(7.U) // show that decreasing an input works as well
c.io.in1.poke(9.U)
c.io.in2.poke(9.U)
c.io.in3.poke(6.U)
c.io.out.expect(9.U) // still get max with tie
}
println("SUCCESS!!") // Scala Code: if we get here, our tests passed!
Wire语句
刚才介绍了when语句并不会返回任何数值。当两两比较然后赋值给输出的时候,when语句害能解决问题,但是如果是比较后的值还需要和第三个input比较呢?这时候需要有一个暂时存储的寄存器。
wire语句可以用来生成一个寄存器存储生成的“过渡”值。
实例
输入4个数值 i n 0 , i n 1 , i n 2 , i n 3 in_0,in_1,in_2,in_3 in0,in1,in2,in3, 比较左边的值和右边的值,当左值比右值小时,遵循红线赋值。当左值大于右值时,按照黑线赋值。
这时候可以看到,不再像上面的例子一样,单纯的把两值相比然后赋给输出,我们需要中间值来存储我们得到的结果,然后进一步比较,因此,可以用wire来声明 r o w 10 , r o w 11 , r o w 12 , r o w 13 , r o w 20 , r o w 21 , r o w 22 , r o w 23 row_{10},row_{11},row_{12},row_{13},row_{20},row_{21},row_{22},row_{23} row10,row11,row12,row13,row20,row21,row22,row23
/** Sort4 sorts its 4 inputs to its 4 outputs */
class Sort4 extends Module {
val io = IO(new Bundle {
val in0 = Input(UInt(16.W))
val in1 = Input(UInt(16.W))
val in2 = Input(UInt(16.W))
val in3 = Input(UInt(16.W))
val out0 = Output(UInt(16.W))
val out1 = Output(UInt(16.W))
val out2 = Output(UInt(16.W))
val out3 = Output(UInt(16.W))
})
val row10 = Wire(UInt(16.W))
val row11 = Wire(UInt(16.W))
val row12 = Wire(UInt(16.W))
val row13 = Wire(UInt(16.W))
when(io.in0 < io.in1) {
row10 := io.in0 // preserve first two elements
row11 := io.in1
}.otherwise {
row10 := io.in1 // swap first two elements
row11 := io.in0
}
when(io.in2 < io.in3) {
row12 := io.in2 // preserve last two elements
row13 := io.in3
}.otherwise {
row12 := io.in3 // swap last two elements
row13 := io.in2
}
val row21 = Wire(UInt(16.W))
val row22 = Wire(UInt(16.W))
when(row11 < row12) {
row21 := row11 // preserve middle 2 elements
row22 := row12
}.otherwise {
row21 := row12 // swap middle two elements
row22 := row11
}
val row20 = Wire(UInt(16.W))
val row23 = Wire(UInt(16.W))
when(row10 < row13) {
row20 := row10 // preserve middle 2 elements
row23 := row13
}.otherwise {
row20 := row13 // swap middle two elements
row23 := row10
}
when(row20 < row21) {
io.out0 := row20 // preserve first two elements
io.out1 := row21
}.otherwise {
io.out0 := row21 // swap first two elements
io.out1 := row20
}
when(row22 < row23) {
io.out2 := row22 // preserve first two elements
io.out3 := row23
}.otherwise {
io.out2 := row23 // swap first two elements
io.out3 := row22
}
}
println(getVerilog(new Sort4))
// Here's the tester
test(new Sort4) { c =>
// verify the inputs are sorted
c.io.in0.poke(3.U)
c.io.in1.poke(6.U)
c.io.in2.poke(9.U)
c.io.in3.poke(12.U)
c.io.out0.expect(3.U)
c.io.out1.expect(6.U)
c.io.out2.expect(9.U)
c.io.out3.expect(12.U)
c.io.in0.poke(13.U)
c.io.in1.poke(4.U)
c.io.in2.poke(6.U)
c.io.in3.poke(1.U)
c.io.out0.expect(1.U)
c.io.out1.expect(4.U)
c.io.out2.expect(6.U)
c.io.out3.expect(13.U)
c.io.in0.poke(13.U)
c.io.in1.poke(6.U)
c.io.in2.poke(4.U)
c.io.in3.poke(1.U)
c.io.out0.expect(1.U)
c.io.out1.expect(4.U)
c.io.out2.expect(6.U)
c.io.out3.expect(13.U)
}
println("SUCCESS!!") // Scala Code: if we get here, our tests passed!
生成的verilog代码:
module Sort4(
input clock,
input reset,
input [15:0] io_in0,
input [15:0] io_in1,
input [15:0] io_in2,
input [15:0] io_in3,
output [15:0] io_out0,
output [15:0] io_out1,
output [15:0] io_out2,
output [15:0] io_out3
);
wire [15:0] row10 = io_in0 < io_in1 ? io_in0 : io_in1; // @[cmd5.sc 18:25 cmd5.sc 19:11 cmd5.sc 22:11]
wire [15:0] row11 = io_in0 < io_in1 ? io_in1 : io_in0; // @[cmd5.sc 18:25 cmd5.sc 20:11 cmd5.sc 23:11]
wire [15:0] row12 = io_in2 < io_in3 ? io_in2 : io_in3; // @[cmd5.sc 26:25 cmd5.sc 27:11 cmd5.sc 30:11]
wire [15:0] row13 = io_in2 < io_in3 ? io_in3 : io_in2; // @[cmd5.sc 26:25 cmd5.sc 28:11 cmd5.sc 31:11]
wire [15:0] row21 = row11 < row12 ? row11 : row12; // @[cmd5.sc 37:23 cmd5.sc 38:11 cmd5.sc 41:11]
wire [15:0] row22 = row11 < row12 ? row12 : row11; // @[cmd5.sc 37:23 cmd5.sc 39:11 cmd5.sc 42:11]
wire [15:0] row20 = row10 < row13 ? row10 : row13; // @[cmd5.sc 47:23 cmd5.sc 48:11 cmd5.sc 51:11]
wire [15:0] row23 = row10 < row13 ? row13 : row10; // @[cmd5.sc 47:23 cmd5.sc 49:11 cmd5.sc 52:11]
assign io_out0 = row20 < row21 ? row20 : row21; // @[cmd5.sc 55:23 cmd5.sc 56:13 cmd5.sc 59:13]
assign io_out1 = row20 < row21 ? row21 : row20; // @[cmd5.sc 55:23 cmd5.sc 57:13 cmd5.sc 60:13]
assign io_out2 = row22 < row23 ? row22 : row23; // @[cmd5.sc 63:23 cmd5.sc 64:13 cmd5.sc 67:13]
assign io_out3 = row22 < row23 ? row23 : row22; // @[cmd5.sc 63:23 cmd5.sc 65:13 cmd5.sc 68:13]
endmodule
可见 r o w 10 , r o w 11 , r o w 12 , r o w 13 , r o w 20 , r o w 21 , r o w 22 , r o w 23 row_{10},row_{11},row_{12},row_{13},row_{20},row_{21},row_{22},row_{23} row10,row11,row12,row13,row20,row21,row22,row23都有对应的寄存器生成来存储过渡值。