Вызов задачи иерархически без определений
У меня есть предоставленный поставщиком модуль BFM, созданный глубоко в моей иерархии; давайте назовем путь top.dut.u1.u2.bfm1
, API BFM немного архаичен и запутан для наших нужд. Я хотел бы написать "объект" (класс? Interface? Что-то еще?), Который будет обеспечивать задачи с более простым интерфейсом вызова и может вызывать задачи конкретной BFM, с которой он был "связан". Именно эту "связь" я не могу понять.
У меня есть простая версия, определенная как модуль, который использует `define для указания пути к BFM, что-то вроде:
`define BFM top.dut.u1.u2.bfm1
module bfm_wrapper;
...
task read_burst(...);
...
`BFM.read_burst(...);
endtask;
...
endmodule
Очевидно, это не очень многоразово. Как мне заменить `BFM на что-то более переносимое или абстрагированное до следующего более высокого уровня?
Я относительный новичок в SystemVerilog, и я еще даже не использую UVM, но я сделаю решающий шаг, если есть что-то, что поможет. Любая помощь приветствуется.
[Обновление] Несколько ограничений, которые я не упомянул:
- Я не могу изменить или заменить предоставленную поставщиком BFM. Я предпочел бы даже не оборачивать это (то есть создавать экземпляр в моей обертке).
- По причинам, в которые я не хочу вдаваться, BFM должен быть создан внутри DUT. Изменение этого потребует больше усилий, чем я могу инвестировать прямо сейчас.
2 ответа
Окончательный ответ (сначала предложенный @toolic и @Greg, затем @dave_59) должен использовать bind
динамически размещать оболочку там, где можно найти BFM поставщика с "обращением вверх по имени" (в частности, поместив оболочку внутри BFM поставщика). Так что мой код выше будет выглядеть примерно так:
`define BFM top.dut.u1.u2.bfm1
module top;
...
// Instantiate my wrapper code inside of the vendor's BFM
bind `BFM bfm_wrapper my_bfm();
// BFM commands go here
initial begin
wait (`BFM.reset === 0) @(posedge `BFM.clk);
`BFM.my_bfm.my_read_burst(...);
...
end
endmodule
module bfm_wrapper;
...
task my_read_burst(...);
...
read_burst(...);
endtask;
...
endmodule
Мои извинения, если есть какие-либо опечатки. Мой код не выглядел точно так.
Обратите внимание, что я не полностью избавился от define
, Вероятно, для этого потребуются более элегантные методы в статьях @ dave_59. Но я, по крайней мере, убрал его из повторно используемой части кода, что на данный момент достаточно.
Связывание вместе с абстрактными интерфейсами поможет вам установить соединение с BFM. Взгляните на две мои статьи о DVCon
http://www.doulos.com/downloads/events/DVCon_08_abstractBFM_final.pdf
http://events.dvcon.org/2012/proceedings/papers/01P_3.pdf
[ОБНОВИТЬ]
package bfm_pkg;
interface class bfm_api;
pure virtual task read_burst(...);
endclass
endpackage
module bfm_wrapper;
import bfm_pkg::*;
...
class wrapper extends bfm_api;
task read_burst(...);
`BFM.read_burst(...);
endtask;
endclass
wrapper h = new();
endmodule
Затем, отказавшись от занятий, вы можете написать
import bfm_pkg;:*;
class someclass
bfm_api h;
task foo;
...
h.read_burst(...);
endtask
endclass
Теперь вам просто нужно получить дескриптор h в вашем bfm_wrapper к h внутри объекта foo. Если вы используете UVM, то здесь поможет uvm_config_db, в противном случае вам нужно будет создать собственный механизм для копирования дескриптора h.