Вызов задачи иерархически без определений

У меня есть предоставленный поставщиком модуль 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, но я сделаю решающий шаг, если есть что-то, что поможет. Любая помощь приветствуется.

[Обновление] Несколько ограничений, которые я не упомянул:

  1. Я не могу изменить или заменить предоставленную поставщиком BFM. Я предпочел бы даже не оборачивать это (то есть создавать экземпляр в моей обертке).
  2. По причинам, в которые я не хочу вдаваться, 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.

Другие вопросы по тегам