我有一个浮点添加凿子模块,我想使用它有几个阶段的管道。我想让它变得稳定,以便我可以将它放入一个管道中,该管道可能无法在任何给定时间使用输出数据,因此我希望将部分计算的添加存储在模块中。
我最初希望我可以添加一个启用信号,然后将其添加为更新各种寄存器的另一个条件,但不幸的是,该模块包含许多 Reg(next=xxx) 形式的语句。我很想知道如果我只是将寄存器分配给它自己会发生什么,即使它的输入已经通过 next=xxx 分配,所以我制作了一个测试模块并得到了一些(在我看来)奇怪的结果。
这是斯卡拉:
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