凿子添加启用到具有下一个字段

时间:2015-06-30 19:48:51

标签: scala verilog chisel

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

我最初希望我可以添加一个启用信号,然后将其添加为更新各种寄存器的另一个条件,但不幸的是该模块包含很多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似乎几乎以两种不同的方式实现了启用。它使用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

2 个答案:

答案 0 :(得分:1)

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

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

会产生这样的东西:

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

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

答案 1 :(得分:1)

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