Долото добавление разрешения в реестр, имеющий следующее поле

У меня есть модуль добавления долота с плавающей запятой, который я хочу использовать, который имеет несколько этапов конвейеров. Я хочу сделать его стабильным, чтобы я мог поместить его в конвейер, который может не иметь возможности потреблять выходные данные в любое время, и поэтому я хотел бы, чтобы частично рассчитанные добавления сохранялись в модуле.

Сначала я надеялся, что смогу просто добавить сигнал включения, а затем просто добавить его в качестве еще одного условия для обновления различных регистров, но, к сожалению, модуль содержит множество операторов формы 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


person user3704133    schedule 30.06.2015    source источник
comment
Использование Chisel.RegEnable (updateData, resetData, enable) вместо Reg также может быть вариантом.   -  person ɹɐʎɯɐʞ    schedule 26.08.2015


Ответы (2)


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
person Chris    schedule 03.07.2015

Я никогда не использовал долото, но предполагаю, что это:

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

произвел бы что-то вроде этого:

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

Что, я думаю, эквивалентно тому, что у вас есть сейчас, но гораздо более читабельно.

person nguthrie    schedule 30.06.2015
comment
Проблема в том, что мой пример пытается имитировать то, с чем я столкнулся бы, пытаясь изменить сумматор с плавающей запятой (код, который я не писал). Если бы я писал это с нуля, я бы сделал именно это - обновил элементы состояния на основе утверждения включения. Однако я пытаюсь изменить код, сводя к минимуму свои шансы на ошибку, поэтому я хочу как можно меньше переписать уже существующую логику. Первоначальный автор (без намерения включить) написал такие вещи, как val reg_manta = Reg (next = a_wrap.mantissa), что означает, что мне действительно нужно проверить, когда io.en не является flase. - person user3704133; 01.07.2015
comment
Хорошо, я понимаю, что вы пытаетесь сделать, но, пытаясь взломать это, добавляя только строки кода, вы просто сбиваете с толку следующего человека, который смотрит на код. Этим человеком, вероятно, будете вы в будущем, и вы посмотрите на это и не поймете, что он должен делать. Лучше закомментировать старый код и заменить его новым кодом. - person nguthrie; 01.07.2015