О задержке триггера Verilog

Я хочу буферизовать однобитовый сигнал «сделано» с двумя однобитными триггерами. В моем дизайне сигнал готовности будет возрастать только на один такт. Поэтому я написал следующий код.

//first level buffer done signal for one cycle to get ciphertext_reg ready
always @(posedge clk or posedge rst) begin
    if(rst)
        done_buf_1 = 1'b0;
    else
        done_buf_1 = done;
end

//second level buffer
always @(posedge clk or posedge rst) begin
    if(rst)
        done_buf_2 = 1'b0;
    else
        done_buf_2 = done_buf_1;
end

В функциональном моделировании я обнаружил, что done_buf_1 повышается на один цикл после done, но done_buf_2 повышается одновременно с done_buf_1.

Чем это объясняется?

Благодарю вас!


person drdot    schedule 16.06.2012    source источник
comment
Я почти не знаю какой-либо verilog, и я далеко не уверен в этом, но вам нужно использовать ‹= вместо = в заданиях, чтобы обеспечить правильное время здесь   -  person jcoder    schedule 16.06.2012
comment
См. здесь хорошее объяснение блокирующих и неблокирующих операторов: sutherland hdl.com/papers/   -  person Tim    schedule 16.06.2012
comment
@Tim Спасибо за ссылку!   -  person drdot    schedule 19.06.2012


Ответы (3)


У вас уже есть ответы с решением («использовать неблокирующие присваивания»), но вот попытка понять, почему вам нужно это сделать.

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

done_buf_1 = done;

... попадет, он будет блокироваться до тех пор, пока задание не будет завершено (это «блокирующее» задание). Поэтому done_buf_1 немедленно принимает новое значение. Это отличается от неблокирующей версии...

done_buf_1 <= done;

... который говорит: «дайте done_buf_1 значение done (которое я сейчас оценю) в конце временного интервала».

Теперь идем дальше, и присваивается done_buf_2.

done_buf_2 = done_buf_1;

Теперь, если done_buf_1 был обновлен блокирующим назначением, он уже имеет текущее значение done, и вы увидите, что оба сигнала возрастают одновременно. Если это было неблокирующее назначение, то done_buf_1 по-прежнему имеет предыдущее значение done, поскольку оно не будет обновляться до конца временного интервала, в результате чего для done_buf_2 будет задержка в 2 цикла.

Хотя есть и другая проблема. Помните, я говорил, что операторы always можно запускать в любом порядке, потому что события одинаковы? Что ж, если бы второй был выполнен первым, код работал бы так, как предполагалось (db2 = db1; db1 = done; Нет проблем). Поэтому стоит знать, что использование блокирующих назначений, подобных этому, дает неустойчивые результаты, особенно между инструментами. Это может привести к некоторым тонким ошибкам.

person Paul S    schedule 18.06.2012

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

person Community    schedule 16.06.2012

Как уже говорили другие: не используйте для этого блокирующие назначения (=).

Ключевым моментом является то, что «это» — это работа по обмену данными между различными процессами. Условия гонки, присущие блокирующим назначениям, делают это непредсказуемым. VHDL относится к этому так серьезно, что разделяет эти типы присваивания таким образом, что вы не можете использовать неправильный (при условии, что вы держитесь подальше от общих переменных).

Несколько интересных статей на эту тему от Яна Декалуве:

person Martin Thompson    schedule 18.06.2012
comment
Меня смущает объяснение второй статьи, которой вы делитесь. Каковы отношения между s, t, u? - person drdot; 25.06.2012
comment
s,t,u — это обновления сигналов, выполняемые в трех отдельных процессах, один из которых запускает процессы P и Q. Дело в том, что не должно быть никаких отношений, не имеет значения, в каком порядке они выполняются, поскольку P и Q не будут выполняться, пока обновления не будут завершены. - person Martin Thompson; 25.06.2012