module Alu1(
input [1:0] io_fn,
input [3:0] io_a,
input [3:0] io_b,
output reg [3:0] io_result
);
always @ (*)
case (io_fn)
0 : io_result = io_a + io_b ;
1 : io_result = io_a - io_b ;
2 : io_result = io_a | io_b ;
3 : io_result = io_a & io_b ;
endcase
endmodule
module Alu2( // @[:@3.2]
input [1:0] io_fn, // @[:@6.4]
input [3:0] io_a, // @[:@6.4]
input [3:0] io_b, // @[:@6.4]
output [3:0] io_result // @[:@6.4]
);
wire _T_16; // @[Conditional.scala 37:30:@10.4]
wire [4:0] _T_17; // @[Alu.scala 19:22:@12.6]
wire [3:0] _T_18; // @[Alu.scala 19:22:@13.6]
wire _T_20; // @[Conditional.scala 37:30:@17.6]
wire [4:0] _T_21; // @[Alu.scala 20:22:@19.8]
wire [4:0] _T_22; // @[Alu.scala 20:22:@20.8]
wire [3:0] _T_23; // @[Alu.scala 20:22:@21.8]
wire _T_25; // @[Conditional.scala 37:30:@25.8]
wire [3:0] _T_26; // @[Alu.scala 21:22:@27.10]
wire _T_28; // @[Conditional.scala 37:30:@31.10]
wire [3:0] _T_29; // @[Alu.scala 22:22:@33.12]
wire [3:0] _GEN_0; // @[Conditional.scala 39:67:@32.10]
wire [3:0] _GEN_1; // @[Conditional.scala 39:67:@26.8]
wire [3:0] _GEN_2; // @[Conditional.scala 39:67:@18.6]
assign _T_16 = 2'h0 == io_fn; // @[Conditional.scala 37:30:@10.4]
assign _T_17 = io_a + io_b; // @[Alu.scala 19:22:@12.6]
assign _T_18 = _T_17[3:0]; // @[Alu.scala 19:22:@13.6]
assign _T_20 = 2'h1 == io_fn; // @[Conditional.scala 37:30:@17.6]
assign _T_21 = io_a - io_b; // @[Alu.scala 20:22:@19.8]
assign _T_22 = $unsigned(_T_21); // @[Alu.scala 20:22:@20.8]
assign _T_23 = _T_22[3:0]; // @[Alu.scala 20:22:@21.8]
assign _T_25 = 2'h2 == io_fn; // @[Conditional.scala 37:30:@25.8]
assign _T_26 = io_a | io_b; // @[Alu.scala 21:22:@27.10]
assign _T_28 = 2'h3 == io_fn; // @[Conditional.scala 37:30:@31.10]
assign _T_29 = io_a & io_b; // @[Alu.scala 22:22:@33.12]
assign _GEN_0 = _T_28 ? _T_29 : 4'h0; // @[Conditional.scala 39:67:@32.10]
assign _GEN_1 = _T_25 ? _T_26 : _GEN_0; // @[Conditional.scala 39:67:@26.8]
assign _GEN_2 = _T_20 ? _T_23 : _GEN_1; // @[Conditional.scala 39:67:@18.6]
assign io_result = _T_16 ? _T_18 : _GEN_2; // @[Alu.scala 24:11:@36.4]
endmodule
module AluTop( // @[:@38.2]
input clock, // @[:@39.4]
input reset, // @[:@40.4]
input [9:0] io_sw, // @[:@41.4]
output [9:0] io_led // @[:@41.4]
);
wire [1:0] alu_io_fn; // @[Alu.scala 32:18:@43.4]
wire [3:0] alu_io_a; // @[Alu.scala 32:18:@43.4]
wire [3:0] alu_io_b; // @[Alu.scala 32:18:@43.4]
wire [3:0] alu_io_result; // @[Alu.scala 32:18:@43.4]
Alu alu ( // @[Alu.scala 32:18:@43.4]
.io_fn(alu_io_fn),
.io_a(alu_io_a),
.io_b(alu_io_b),
.io_result(alu_io_result)
);
assign io_led = {{6'd0}, alu_io_result}; // @[Alu.scala 36:8:@52.4]
assign alu_io_fn = io_sw[1:0]; // @[Alu.scala 33:11:@47.4]
assign alu_io_a = io_sw[5:2]; // @[Alu.scala 34:10:@49.4]
assign alu_io_b = io_sw[9:6]; // @[Alu.scala 35:10:@51.4]
endmodule
上述两端代码,实现同样功能,其中Alu2是由chisel生成的。看上去使用了一层一层的选择器,似乎能占用更多资源。
我用Quartus综合的结果结果正好相反: 手写的Alu1和生成的Alu2分别生成了 17个LUT 和16个LUT。
也就是说CHISEL 生成的看似繁琐的代码反而更高效!本来我是想看看可能效率低一些没想到剧情反转了。
附录:一下部分是chisel代码,我们可以看到switch部分几乎跟verilog的case语句完全一样的表达。
package simple
import chisel3._
import chisel3.util._
class Alu extends Module {
val io = IO (new Bundle{
val fn = Input(UInt(2.W))
val a = Input(UInt(4.W))
val b = Input(UInt(4.W))
val result = Output(UInt(4.W))})
val fn = io.fn ;
val a = io.a ;
val b = io.b;
val result = Wire(UInt(4.W))
result := 0.U
switch (fn){
is (0.U) {result := a+b }
is (1.U) {result := a-b }
is (2.U) {result := a|b }
is (3.U) {result := a&b }
}
io.result := result
}
class AluTop extends Module {
val io= IO(new Bundle{
val sw = Input(UInt(10.W))
val led=Output(UInt(10.W))})
val alu = Module (new Alu ())
alu.io.fn := io.sw(1,0)
alu.io.a := io.sw(5,2)
alu.io.b := io.sw(9,6)
io.led := alu.io.result
}
object AluMain extends App {
println("Generating the ALU hardware ");
chisel3.Driver.execute(Array("--target-dir","generated"),()=>new AluTop())
}
又改写了一下代码,实验了一下:
package simple1
import chisel3._
import chisel3.util._
class Alu extends Module {
val io = IO (new Bundle{
val fn = Input(UInt(2.W))
val a = Input(UInt(4.W))
val b = Input(UInt(4.W))
val result = Output(UInt(4.W))})
val fn = io.fn ;
val a = io.a ;
val b = io.b ;
val and_result = io.a & b ;
val or_result = a | b ;
val add_result = a + b ;
val sub_result = a - b ;
val result = Wire(UInt(4.W));
result := 1.U;
switch (fn){
is (3.U) {result := and_result };
is (2.U) {result := or_result };
is (0.U) {result := add_result };
is (1.U) {result := io.a - io.b };
}
io.result := result ;
}
里面加了些分号,没有任何影响。也定义了一些中间变量。实验发现scala语法还是比较宽松的。
另外,如果package 后面是跟simple1,则要生成代码用下面命令。
sbt "runMain simple1.AluMain"
虽然命令行里面没有simple的字样,但是这个scala文件还是在simple目录下。依然能被找到。
可见命令行里面可以不体现出来文件夹以及文件名,但是必须体现出来package的名称。