Как симулятор iverilog интерпретирует мой код RAM для определения значений «x»? - PullRequest
0 голосов
/ 29 декабря 2018

Я пытаюсь написать и протестировать простой 16-разрядный чип RAM8 в Verilog с использованием Icarus Verilog.Мне трудно понять концептуально, почему симулятор iverilog показывает мне значения 'x' (неопределенные) на определенных тактах и ​​задается вопросом, может ли кто-нибудь дать концептуальное понимание этой проблемы.

Я пыталсядве разные конструкции, одна из которых имеет смысл для вывода, но я не могу разобрать вывод второй.

Первый дизайн делает регистр out, и назначение для выхода синхронизируется:

module RAM8(out, address, in, load, clk);
   output[15:0] out;
   input [15:0] in;
   input [2:0]  address;
   input        load, clk;

   reg          out;            // out is a register
   reg [15:0]   ram [7:0];      // 8-element array of 16-bit wide reg

   always @(posedge clk) begin
      if (load)
        ram[address] <= in;
      out <= ram[address];      // clocked assignment
   end
endmodule // RAM8

В то время как второй дизайн, out - это непрерывно назначенный провод:

module RAM8(out, address, in, load, clk);
   output[15:0] out;
   input [15:0] in;
   input [2:0]  address;
   input        load, clk;

   reg [15:0]   ram [7:0];      // 8-element array of 16-bit wide reg

   always @(posedge clk) begin
      if (load)
        ram[address] <= in;
   end
   assign out = ram[address];      // continuous assignment
endmodule // RAM8

Испытательный стенд для них обоих одинаков:

module RAM8_tb();
   wire [15:0] out;
   reg [15:0]  in;
   reg [2:0]   address;
   reg         load;
   reg         clk;

   RAM8 DUT (
         .out(out),
         .in(in),
         .address(address),
         .load(load),
         .clk(clk)
         );

   initial begin
      clk = 0;
      load = 0;
      address = 0;
      in = 0;

      #10 load = 1; address = 0; in = 0;
      #10 load = 0; address = 0;
      #10 load = 1; address = 1; in = 1;
      #10 load = 0; address = 1;
      #10 load = 1; address = 2; in = 2;
      #10 load = 0; address = 2;
      #10 load = 1; address = 3; in = 3;
      #10 load = 0; address = 3;
      #10 load = 1; address = 4; in = 4;
      #10 load = 0; address = 4;
      #10 load = 1; address = 5; in = 5;
   end // initial begin

   always #5 clk = ~clk;

   initial #150 $stop;

   initial
     $monitor("At time %t, clk = %0d, load = %0d, address = %0d, in = %0d, out = %0d",
              $time, clk, load, address, in, out);
endmodule // RAM8_tb

Мой вывод на тестовом стенде для первого проекта такой:

At time                    0, clk = 0, load = 0, address = 0, in = 0, out = x
At time                    5, clk = 1, load = 0, address = 0, in = 0, out = x
At time                   10, clk = 0, load = 1, address = 0, in = 0, out = x
At time                   15, clk = 1, load = 1, address = 0, in = 0, out = x
At time                   20, clk = 0, load = 0, address = 0, in = 0, out = x
At time                   25, clk = 1, load = 0, address = 0, in = 0, out = 0
At time                   30, clk = 0, load = 1, address = 1, in = 1, out = 0
At time                   35, clk = 1, load = 1, address = 1, in = 1, out = x
At time                   40, clk = 0, load = 0, address = 1, in = 1, out = x
At time                   45, clk = 1, load = 0, address = 1, in = 1, out = 1
At time                   50, clk = 0, load = 1, address = 2, in = 2, out = 1
At time                   55, clk = 1, load = 1, address = 2, in = 2, out = x
At time                   60, clk = 0, load = 0, address = 2, in = 2, out = x
At time                   65, clk = 1, load = 0, address = 2, in = 2, out = 2
At time                   70, clk = 0, load = 1, address = 3, in = 3, out = 2
At time                   75, clk = 1, load = 1, address = 3, in = 3, out = x
At time                   80, clk = 0, load = 0, address = 3, in = 3, out = x
At time                   85, clk = 1, load = 0, address = 3, in = 3, out = 3
At time                   90, clk = 0, load = 1, address = 4, in = 4, out = 3
At time                   95, clk = 1, load = 1, address = 4, in = 4, out = x
At time                  100, clk = 0, load = 0, address = 4, in = 4, out = x
At time                  105, clk = 1, load = 0, address = 4, in = 4, out = 4
At time                  110, clk = 0, load = 1, address = 5, in = 5, out = 4
At time                  115, clk = 1, load = 1, address = 5, in = 5, out = x
At time                  120, clk = 0, load = 1, address = 5, in = 5, out = x
At time                  125, clk = 1, load = 1, address = 5, in = 5, out = 5
At time                  130, clk = 0, load = 1, address = 5, in = 5, out = 5
At time                  135, clk = 1, load = 1, address = 5, in = 5, out = 5
At time                  140, clk = 0, load = 1, address = 5, in = 5, out = 5
At time                  145, clk = 1, load = 1, address = 5, in = 5, out = 5

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

Однаковывод для тестового стенда для второго дизайна меня смущает:

At time                    0, clk = 0, load = 0, address = 0, in = 0, out = x
At time                    5, clk = 1, load = 0, address = 0, in = 0, out = x
At time                   10, clk = 0, load = 1, address = 0, in = 0, out = x
At time                   15, clk = 1, load = 1, address = 0, in = 0, out = 0
At time                   20, clk = 0, load = 0, address = 0, in = 0, out = 0
At time                   25, clk = 1, load = 0, address = 0, in = 0, out = 0
At time                   30, clk = 0, load = 1, address = 1, in = 1, out = x
At time                   35, clk = 1, load = 1, address = 1, in = 1, out = 1
At time                   40, clk = 0, load = 0, address = 1, in = 1, out = 1
At time                   45, clk = 1, load = 0, address = 1, in = 1, out = 1
At time                   50, clk = 0, load = 1, address = 2, in = 2, out = x
At time                   55, clk = 1, load = 1, address = 2, in = 2, out = 2
At time                   60, clk = 0, load = 0, address = 2, in = 2, out = 2
At time                   65, clk = 1, load = 0, address = 2, in = 2, out = 2
At time                   70, clk = 0, load = 1, address = 3, in = 3, out = x
At time                   75, clk = 1, load = 1, address = 3, in = 3, out = 3
At time                   80, clk = 0, load = 0, address = 3, in = 3, out = 3
At time                   85, clk = 1, load = 0, address = 3, in = 3, out = 3
At time                   90, clk = 0, load = 1, address = 4, in = 4, out = x
At time                   95, clk = 1, load = 1, address = 4, in = 4, out = 4
At time                  100, clk = 0, load = 0, address = 4, in = 4, out = 4
At time                  105, clk = 1, load = 0, address = 4, in = 4, out = 4
At time                  110, clk = 0, load = 1, address = 5, in = 5, out = x
At time                  115, clk = 1, load = 1, address = 5, in = 5, out = 5
At time                  120, clk = 0, load = 1, address = 5, in = 5, out = 5
At time                  125, clk = 1, load = 1, address = 5, in = 5, out = 5
At time                  130, clk = 0, load = 1, address = 5, in = 5, out = 5
At time                  135, clk = 1, load = 1, address = 5, in = 5, out = 5
At time                  140, clk = 0, load = 1, address = 5, in = 5, out = 5
At time                  145, clk = 1, load = 1, address = 5, in = 5, out = 5

Мой вопрос здесь: какие периодические неопределенные значения на выходе вызваны?Похоже, что общность заключается в том, что clk равен 0, а нагрузка равна 1, но ничто из того, что я могу вспомнить из своего понимания регистров, не объясняет, почему это приведет к тому, что вывод будет мусором.Все регистры в моей схеме запускаются по положительному фронту тактового сигнала, так почему же отрицательный фронт меняет какое-либо значение?

Я полагаю, что в целом я могу быть смущен тем, что здесь происходит под капотом, и также был бы признателен, если бы кто-то подтвердил или опроверг мое объяснение поведения первого проекта.Заранее спасибо всем, кто нашел время, чтобы прочитать и ответить.

1 Ответ

0 голосов
/ 29 декабря 2018

В обоих случаях получаемые значения X являются начальными значениями ram (то есть X, поскольку вы не назначали никаких начальных значений).Если вы продолжите тестирование и циклически перебираете те же адреса, в следующий раз вы увидите значения, которые вы ранее написали.

В первом примере одновременное чтение и запись не является проблемой.Считывание возвращает значение до фронта тактового импульса, и ram будет содержать новое значение после фронта тактового импульса.

Во втором примере событие, инициирующее X, увеличивается address, а неclk и load сигналы.Поскольку out не зарегистрирован и не связан с clk, как только address изменится, вы увидите, что значение по этому адресу появится в out.Затем после фронта часов, который записывает новое значение, вы увидите, что out одновременно изменится на это значение.

...