Я создаю UVM VIP, который может переключать полярность часов. В интерфейсе используется блок тактирования. Например, монитор должен сэмплировать данные, используя posege или negedge входящих тактовых импульсов в зависимости от конфигурации UVM, и это изменение полярности может произойти на лету.
Это может быть реализовано следующим образом:
// In the interface, two clocking blocks are defined
// one for posedge (passive_cb), one for negedge (passive_cbn).
task wait_clock_event();
if (cfg.pol == 0) @vif.passive_cb;
else @vif.passive_cbn;
endtask
task sample_data();
if (cfg.pol == 0) pkt.data = vif.passive_cb.data;
else pkt.data = vif.passive_cbn.data;
endtask
task run();
wait_clock_event();
sample_data();
endtask
Кажется, это работает, но тратит строки кода и подвержено ошибкам.
Есть ли лучшее решение?
Предполагая, что монитор имеет эксклюзивный доступ к блоку синхронизации, вы можете рассмотреть возможность изменения события синхронизации в интерфейсе с помощью квалификатора iff
.
bit pol;
clocking passive_cb @(posedge clk iff !pol, negedge clk iff pol);
input data;
endclocking
Существует потенциальное состояние гонки, если pol
изменяется на том же временном шаге, что и целевая полярность часов.
Тогда ваш код монитора будет включать в себя заданную функцию, а другие задачи могут быть упрощены до нас только одним блоком тактирования.
function void set_vifcb_pol();
vif.pol = cfg.pol;
endfunction
task wait_clock_event();
@vif.passive_cb;
endtask
task sample_data();
pkt.data = vif.passive_cb.data;
endtask
task run();
set_vifcb_pol();
wait_clock_event();
sample_data();
endtask