[quote]PS Блокирующие и не блокирующие назначение при синтезе дают один и тот же [правильный] результат в массе своей, так что проблемы только в моделировании можно заметить.[/quote]
Не совсем так.
Если под рукой есть синтезатор, тот же квартус, попробуйте написать такой код ( SystemVerilog ):
always_ff @( posedge clk_i or posedge rst_i ) begin
if ( rst_i ) begin
data_o <= 0;
data_between <= 0;
end else begin
data_between <= data_i;
data_o <= data_between;
end
end
endmodule
Просинтезируйте и посмотрите RTL модель, затем поменяйте неблокирующие присваивания на блокирующие, просинтезируйте и посмотрите, что будет. А будет следующее: цепочка из 2х триггеров будет «оптимизирована» и один из триггеров будет выкинут просто-напросто
Как говорится, я, конечно, не гинеколог, но посмотреть могу… Я не профессионал, но могу пару общих правил привести, по возможности, с примером ошибки из кода:
1. Необходимо чётко знать, какой тип схемы должен получиться из куска кода: синхронная, защёлка или комбинационная. Для каждого типа есть свои правила написания кода, их я ниже изложу
2. В синхронной схеме нужно использовать только неблокирующие присваивания, т.е. <=
В приведённом коде этот кусок с ошибкой
…
always @(negedge clock)
begin
if(PS2_CLK_in == 1)
count_clk = count_clk + 1;
else
…
3. В комбинационной только блокирующие =
В приведённом коде этот кусок с ошибкой
…
always @*
begin
visible <= hvisible & vvisible;
end
…
4. Все возможные ветви комбинационного кода должны быть описаны, иначе получится защёлка. Например, если у вас кейс по 4х-битной переменной, нужно либо описать все 16 ветвей либо добавить ветку default для всех неописанных.
Если получилась где-то защёлка, где вы не собирались её создавать (вы это увидите в варнингах), то скорее всего, код косячный.
Ещё по коду увидел такую вещь: синхронизация дисплея берётся с выхода комбинационной схемы
…
wire w_hsync = (pixel_count < h_sync);
…
Выход комбинационной схемы может давать иголки из-за неодновременного переключения составляющих логических элементов, поэтому их всегда надо пропускать через синхронизатор, прежде чем заводить куда-то дальше в синхронных схемах
Не совсем так.
Если под рукой есть синтезатор, тот же квартус, попробуйте написать такой код ( SystemVerilog ):
module top (
input logic rst_i,
input logic clk_i,
input logic data_i,
output logic data_o
);
logic data_between;
always_ff @( posedge clk_i or posedge rst_i ) begin
if ( rst_i ) begin
data_o <= 0;
data_between <= 0;
end else begin
data_between <= data_i;
data_o <= data_between;
end
end
endmodule
Просинтезируйте и посмотрите RTL модель, затем поменяйте неблокирующие присваивания на блокирующие, просинтезируйте и посмотрите, что будет. А будет следующее: цепочка из 2х триггеров будет «оптимизирована» и один из триггеров будет выкинут просто-напросто
1. Необходимо чётко знать, какой тип схемы должен получиться из куска кода: синхронная, защёлка или комбинационная. Для каждого типа есть свои правила написания кода, их я ниже изложу
2. В синхронной схеме нужно использовать только неблокирующие присваивания, т.е. <=
В приведённом коде этот кусок с ошибкой
…
always @(negedge clock)
begin
if(PS2_CLK_in == 1)
count_clk = count_clk + 1;
else
…
3. В комбинационной только блокирующие =
В приведённом коде этот кусок с ошибкой
…
always @*
begin
visible <= hvisible & vvisible;
end
…
4. Все возможные ветви комбинационного кода должны быть описаны, иначе получится защёлка. Например, если у вас кейс по 4х-битной переменной, нужно либо описать все 16 ветвей либо добавить ветку default для всех неописанных.
Если получилась где-то защёлка, где вы не собирались её создавать (вы это увидите в варнингах), то скорее всего, код косячный.
Ещё по коду увидел такую вещь: синхронизация дисплея берётся с выхода комбинационной схемы
…
wire w_hsync = (pixel_count < h_sync);
…
Выход комбинационной схемы может давать иголки из-за неодновременного переключения составляющих логических элементов, поэтому их всегда надо пропускать через синхронизатор, прежде чем заводить куда-то дальше в синхронных схемах
initial begin
#0 clock_r = 1;
//…
end
always begin
#x clock_r = ~clock_r;
end
х — это половина периода синхронизации
Это нужно чтобы клок сам бегал, без вашего постоянного контроля и портянки кода для этого)
Попробуйте в тестбенчах для генерации клока такую конструкцию:
initial begin
#0 clock_r = 1;
//…
end
always begin
#x clock_r