У меня есть модуль добавления долота с плавающей запятой, который я хочу использовать, который имеет несколько этапов конвейеров. Я хочу сделать его стабильным, чтобы я мог поместить его в конвейер, который может не иметь возможности потреблять выходные данные в любое время, и поэтому я хотел бы, чтобы частично рассчитанные добавления сохранялись в модуле.
Сначала я надеялся, что смогу просто добавить сигнал включения, а затем просто добавить его в качестве еще одного условия для обновления различных регистров, но, к сожалению, модуль содержит множество операторов формы 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 полностью игнорируется, а T1 используется в блоке if else для выбора, следует ли обновлять регистр или нет.
В конечном счете, этот пример кажется, что он все еще работает правильно, но теперь я немного боюсь использовать его в более сложном модуле с плавающей запятой, если он ведет себя неожиданно в простом случае.
Есть ли более элегантный способ остановить конвейер модуля добавления с плавающей запятой? Изначально мне понравился вышеупомянутый подход, потому что я мог просто добавить в конце блок when (! En), который просто записывает вывод всего состояния на свой ввод. Я думаю, что другой подход заключался бы в замене любого экземпляра Reg (next = xxx) на Reg (), а затем на блок when (en) {reg: = next}, который обновляет регистр. В конечном итоге я пытаюсь изучить Chisel, поэтому мне интересно, как это сделать проще всего.
Для справки, модуль добавления с плавающей запятой, о котором я говорю: https://github.com/zhemao/chisel-float/blob/master/src/main/scala/FPAdd.scala