Chisel将enable添加到具有下一个字段的寄存器



我有一个浮点加法凿模块,我想使用它,它有几个阶段的管道。我想让它可以安装,这样我就可以将它放入一个管道中,该管道可能无法在任何给定时间消耗输出数据,因此我希望将部分计算的加法存储在模块中。

我最初希望我可以添加一个启用信号,然后将其添加为更新各种寄存器的另一个条件,但不幸的是,该模块包含许多形式为Reg(next=xxx)的语句。我很好奇,如果我只是把寄存器分配给它自己会发生什么,尽管它的输入已经通过next=xxx分配了,所以我做了一个测试模块,得到了一些(在我看来)奇怪的结果。

这是scala:

package Hello
import Chisel._
class Hello extends Module {
  val io = new Bundle { 
    val in = UInt(INPUT, 8)
    val en = Bool(INPUT)
    val out = UInt(OUTPUT, 8)
  }
  val test_reg = Reg(next = io.in)
  io.out := test_reg
  when (!io.en) {
    test_reg := test_reg
  }
}
object Hello {
  def main(args: Array[String]): Unit = {
  }
}

这是生成的verilog:

module Hello(input clk,
    input [7:0] io_in,
    input  io_en,
    output[7:0] io_out
);
  reg [7:0] test_reg;
  wire[7:0] T0;
  wire T1;
`ifndef SYNTHESIS
// synthesis translate_off
  integer initvar;
  initial begin
    #0.002;
    test_reg = {1{$random}};
  end
// synthesis translate_on
`endif
  assign io_out = test_reg;
  assign T0 = T1 ? test_reg : io_in;
  assign T1 = io_en ^ 1'h1;
  always @(posedge clk) begin
    if(T1) begin
      test_reg <= test_reg;
    end else begin
      test_reg <= io_in;
    end
  end
endmodule

我感到奇怪的是,verilog似乎几乎以两种不同的方式实现了enable。它使用T1(!en)在test_reg和io_in之间进行多路复用,并标记输出T0。如果T0被无条件地作为test_reg的输入,我认为这将具有所需的功能。相反,T0被完全忽略,并且在if-else块中使用T1来选择寄存器是否应该更新。

最终,这个例子看起来仍然正确,但现在我有点害怕在更复杂的浮点单元中使用,如果它在简单的情况下表现得有点出乎意料的话。

有没有更优雅的方法来停止浮点加法模块的管道?我最初喜欢上面的方法,因为我可以在末尾添加一个when(!en)块,它只将所有状态的输出写入其输入。我认为另一种方法是用Reg()替换Reg(next=xxx)的任何实例,然后用when(en){Reg:=next}块更新寄存器。最终,我正在努力学习Chisel,所以我想知道最干净的方法是什么。

作为参考,我所说的浮点加法模块是:https://github.com/zhemao/chisel-float/blob/master/src/main/scala/FPAdd.scala

val test_reg = Reg(next = io.in)
io.out := test_reg
when (!io.en) {
  test_reg := test_reg
}

我认为这是一种糟糕的编码实践——要么使用Reg(next=...),要么通过test_reg := ...指定下一个值,但不要两者混合!首先,读者不清楚哪位作家应该优先(尽管答案是"最后一位作家获胜")。其次,当读者看到Reg(next=...)时,他可能不希望看到代码中的其他地方覆盖了那个编写器。

写为:

val test_reg = Reg(io.in.clone())
when (io.en) { 
   test_reg := io.in
}

它仍然会生成一些未使用的信号,但代码的意图要清晰得多。

always @(posedge clk) begin
  if(io_en) begin
    test_reg <= io_in;
  end
end

我从未使用过凿子,但我的猜测是:

when (io.en) {
  test_reg := io.in
}

会产生这样的东西:

always @(posedge clk) begin
  if(io_en) begin
    test_reg <= io_in;
  end
end

我认为这相当于你现在所拥有的,但可读性更强。