使用方法

现在我们的需求是:在同一个 Generator 里可以使用端口定义相同、内部实现不同的子模块,且子模块可以通过参数进行配置。

首先定义一个特质 MyAdder,它可以理解为 Mod1Mod2 两个 Module 的接口定义。 Mod1Mod2 是两个接口相同、功能不同的模块。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// Provides a more specific interface since generic Module
// provides no compile-time information on generic module's IOs.
trait MyAdder {
    def in1: UInt
    def in2: UInt
    def out: UInt
}

class Mod1 extends RawModule with MyAdder {
    val in1 = IO(Input(UInt(8.W)))
    val in2 = IO(Input(UInt(8.W)))
    val out = IO(Output(UInt(8.W)))
    out := in1 + in2
}

class Mod2 extends RawModule with MyAdder {
    val in1 = IO(Input(UInt(8.W)))
    val in2 = IO(Input(UInt(8.W)))
    val out = IO(Output(UInt(8.W)))
    out := in1 - in2
}

X 接收一个实现了 MyAdder 特质的对象作为参数。: => 表示参数会延迟求值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class X[T <: BaseModule with MyAdder](genT: => T) 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))
    })
    val subMod = Module(genT)
    io.out := subMod.out
    subMod.in1 := io.in1
    subMod.in2 := io.in2
}

生成对应 Verilog 代码,并进行比较。

1
2
println(ChiselStage.emitVerilog(new X(new Mod1)))
println(ChiselStage.emitVerilog(new X(new Mod2)))

当类参数 genT = Mod1 时,生成了 XMod1 两个模块,并且在 X 中实例化了 Mod1 模块。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
module Mod1(
  input  [7:0] in1,
  input  [7:0] in2,
  output [7:0] out
);
  assign out = in1 + in2; // @[polymorphism-and-parameterization.md 174:16]
endmodule

module X(
  input        clock,
  input        reset,
  input  [7:0] io_in1,
  input  [7:0] io_in2,
  output [7:0] io_out
);
  wire [7:0] subMod_in1; // @[polymorphism-and-parameterization.md 192:24]
  wire [7:0] subMod_in2; // @[polymorphism-and-parameterization.md 192:24]
  wire [7:0] subMod_out; // @[polymorphism-and-parameterization.md 192:24]
  Mod1 subMod ( // @[polymorphism-and-parameterization.md 192:24]
    .in1(subMod_in1),
    .in2(subMod_in2),
    .out(subMod_out)
  );
  assign io_out = subMod_out; // @[polymorphism-and-parameterization.md 193:12]
  assign subMod_in1 = io_in1; // @[polymorphism-and-parameterization.md 194:16]
  assign subMod_in2 = io_in2; // @[polymorphism-and-parameterization.md 195:16]
endmodule

当类参数 genT = Mod2 时,X 中的子模块变成了 Mod2(此处省略了重复的代码)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
module Mod2(
  input  [7:0] in1,
  input  [7:0] in2,
  output [7:0] out
);
  assign out = in1 - in2; // @[polymorphism-and-parameterization.md 182:16]
endmodule

module X(/*...*/);
  /*...*/
  Mod2 subMod ( // @[polymorphism-and-parameterization.md 192:24]
    .in1(subMod_in1),
    .in2(subMod_in2),
    .out(subMod_out)
  );
  /*...*/
endmodule

更多

  • RawModule / BaseModule / Module 中:RawModule 没有隐式 clockreset 端口;BaseModule 是其它 Module抽象基类(abstract base class);Module 是定义一个模块时通常会使用的类。
  • MultiIOModule 比起 RawModule 多了隐式 clockreset 端口。

参考资料