Неожиданное поведение при использовании тернарного оператора (Verilog)

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

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

Бонусные баллы за ответы, указывающие на спецификацию Verilog, объясняющую, что здесь происходит!

/* Every second, the set of leds that are lit will change */
module blinky(
input clk,
output [3:0] led
);
    reg [3:0] count = 0;
    reg [27:0] i = 0;
    localparam [27:0] nTicksPerSecond = 100000000;

    assign led = {count[3],count[2],count[1],count[0]};

    always @ (posedge(clk)) begin
        // This works:
        //count = i==nTicksPerSecond ? (count + 1) : count;
        //i     = i==nTicksPerSecond ? 0 : i+1;

        // But this doesn't:
        {count,i} = i==nTicksPerSecond ? 
          {count+1, 28'b0  } :
          {count  , i+1};
    end
endmodule

PS: я использую Vivado 2018.2


person Olivier Sohn    schedule 25.11.2018    source источник
comment
1/Вы должны использовать неблокирующие назначения. 2/ i+1 будет иметь ширину 32 бита и нарушит порядок битов {count , i+1}.   -  person Oldfart    schedule 25.11.2018
comment
@Oldfart Я думаю, что использование блокирующего или неблокирующего присваивания здесь ничего не меняет, поскольку есть одно присваивание. Верно?   -  person Olivier Sohn    schedule 25.11.2018
comment
Всегда используйте неблокирующие назначения в синхронизированной секции. (Да, даже если это одно задание!)   -  person Oldfart    schedule 25.11.2018
comment
@Oldfart, можете ли вы объяснить, почему или указать мне какое-то соответствующее объяснение?   -  person Olivier Sohn    schedule 25.11.2018
comment
Потому что это поведение, которое соответствует реальному оборудованию. Поиск блокирующий/неблокирующий. Есть десятки постов на эту тему.   -  person Oldfart    schedule 25.11.2018
comment
@Oldfart, судя по тому, что я читал, иногда оправдано иметь блокирующие задания.   -  person Olivier Sohn    schedule 25.11.2018
comment
Давайте продолжим обсуждение в чате.   -  person Olivier Sohn    schedule 25.11.2018


Ответы (1)


Причина в том, что ширина count+1 и i+1 составляет 32 бита. Неразмерное число имеет ширину 32 бита (1800-2017 LRM, раздел 5.7.1), а ширина оператора сложения равна размеру наибольшего операнда (LRM, раздел 11.6.1). Чтобы ваш код работал, добавьте правильный размер к вашим числовым литералам.

 {count,i} = i==nTicksPerSecond ? 
          {count+4'd1, 28'b0  } :
          {count  , i+28'd1};

Более простой способ написать этот код:

  always @ (posedge clk) 
      if (i== nTicksPerSecond)
         begin 
           count <= count + 1;
           i <= 0;
         end
      else
         begin
           i <= i + 1;
         end
person dave_59    schedule 25.11.2018
comment
Спасибо! Знаете ли вы, есть ли способ для компилятора сгенерировать предупреждение в этом случае (например, элемент справа больше, чем элемент слева)? И как бы вы упростили этот код? - person Olivier Sohn; 25.11.2018
comment
К сожалению, большинство инструментов не будут генерировать предупреждение, так как Verilog имеет слабую типизацию. - person dave_59; 25.11.2018
comment
это действительно прискорбно... Я думаю, что VHDL хорошо справится с этим случаем (я слышал, что он строго типизирован) - person Olivier Sohn; 25.11.2018
comment
Вопрос, который вы разместили, является прекрасным примером того, как легко ошибиться с конкатенацией. - person dave_59; 25.11.2018
comment
Инструмент для анализа кода должен решать такие проблемы. - person nguthrie; 28.11.2018