«…Труд избавляет человека от трех великих зол: скуки, порока, нужды…»

OVM/OVM методология/Механика OVM/4.7

Материал из Wiki
Перейти к: навигация, поиск

4.7 Подключение тестбенча к hardware

В конечном счете, все компоненты на основе классов должны быть подключены к RTL оборудованию. SystemVerilog предоставляет интерфейсы для подключения аппаратных объектов без того, чтобы это сделать как подключение контакт к контакту. Оборудование, в данном случае, означает, RTL компоненту представлены с использованием Verilog модулей. Язык также обеспечивает виртуальные интерфейсы как средство на основе классов объектов для подключения к RTL компонентов. По сути, виртуальный интерфейс является указатель (ссылку) на интерфейс.

G4.7p1.jpg

Для соединения тетсбенча и компонентов аппаратуры на основе класса, необходимо подключить интерфейс аппаратуры, а затем поместить(обвернуть) виртуальный интерфейс в classbased окружение. Ниже приведен пример интерфейс уровня подключения. Это интерфейс памяти, который имеет адрес (address), выходные данные (wr_data), входных данных (rd_data), вход, который выбирает данные направления (RW), контакты запроса и авторизации (REQ и ACK), контакт сброса (RST), индикатор ошибки (ERR), и, конечно, тактовый сигнал (CLK).

25 interface pin_if (input clk);
26 bit [15:0] address;
27 bit [7:0] wr_data;
28 bit [7:0] rd_data;
29 bit rst;
30 bit rw;
31 bit req;
32 bit ack;
33 bit err;
34
35 modport master_mp(
36 input clk,
37 input rst,
38 output address,
39 output wr_data,
40 input rd_data,
41 output req,
42 output rw,
43 input ack,
44 input err );
45
46 modport slave_mp(
47 input clk,
48 input rst,
49 input address,
50 input wr_data,
51 output rd_data,
52 input req,
53 input rw,
54 output ack,
55 output err );
56
57 modport monitor_mp(
58 input clk,
59 input rst,
60 input address,
61 input wr_data,
62 input rd_data,
63 input req,
64 input rw ,
65 input ack,
66 input err );
67 endinterface
file: 04_OVM_mechanics/10_vif/top.sv

Интерфейс состоит из нескольких частей. Мы рассмотрим их по отдельности. Первая часть заголовка, который определяет имя интерфейса, в данном случае pin_if. Чуть ниже, что является набором контактов, которые служат для внешнего наблюдения за оборудованием. В остальном конструкция интерфейса содержит декларацию трех modports. Каждый modport представляет собой вид комплект контактов. В нашем примере, каждый modport содержит набор всех контактов, но с разными направления сигналов. Мастер modport управляет операциями на шине: входами address, wr_data, REQ, RW и всеми выходами. Устройство, которое использует этот modport будет управлять этими контакты. На остальных устройствах все сигналы входные. Ведомые устройства используют управляемый modport, сигналами на котором управляет расположенный напротив master. Устройства наблюдения являются пассивными и не управляют никакими сигналами. Все их сигналы являются входами. Путем подбора соответствующих modport для любого устройства, мы можем легко установить направление всех сигналов и гарантировать согласованность всех устройств, подключенных к шине. В верхнем уровне модуля мы статически создадим экземпляр тактового генератора, интерфейса и DUT'а.

150 module top;
151
152 clkgen ck(clk);
153 pin_if pif(clk);
154 dut d(pif.slave_mp);
155
156 env e;
157
158 initial begin
159 e = new(“env”);
160 e.set_vif(pif.master_mp);
161 run_test();
162 end
163
164 endmodule
file: 04_OVM_mechanics/10_vif/top.sv

Initial block динамически создает экземпляр класса тестового окружения, передает заголовок интерфейса (иначе известная, как виртуальный интерфейс) в только что созданного окружения(тестового), и запускается тест. Обратите внимание, что slave modport передается в DUT. Это уместно, поскольку DUT это управляемая память. Мастер modport передается в тестовое окружение и в конечном счете управляет сигналами. Среда хранит виртуальный интерфейс и передает его в любой из подчиненных компонентов, которые могут в ней нуждается.

108 class env extends ovm_env;
109
110 local virtual pin_if vif;
111 driver d;
112
113 function new(string name, ovm_component parent = null);
114 super.new(name, parent);
115 endfunction
116
117 function void build();
118 d = new(“driver”, this);
119 d.set_vif(vif);
120 endfunction
121
122 task run();
123 #100;
124 global_stop_request();
125 endtask
126
127 function void set_vif(virtual pin_if _if);
128 vif = _if;
129 endfunction
130
131 endclass
file: 04_OVM_mechanics/10_vif/top.sv

Обратите внимание, что виртуальный интерфейс, VIF, хранится в локальной переменной. Как и любой другой переменной, что делает его локальной и предотвращает несанкционированный доступ к ней. Таким образом, доступ к интерфейсу находится под контролем. Set_vif () предоставляет доступ локальному виртуальному интерфейсу значение которого необходимо установить. Как окружение верхнего уровня, master также имеет set_vif () функцию, которая работает точно таким же образом.


72 class driver extends ovm_component;
73
74 local virtual pin_if vif;
75
76 function new(string name, ovm_component parent);
77 super.new(name, parent);
78 endfunction
79
80 function void set_vif(virtual pin_if _if);
81 vif = _if;
82 endfunction
83
84 task run;
85 forever begin
86 @(posedge vif.clk);
87 ovm_report_info(“driver”,posedge clk”);
88 //...
89 end
90 endtask
91
92 endclass
file: 04_OVM_mechanics/10_vif/top.sv


Иерархический вызов set_vif () функции отлично работает для небольших конструкций или ситуациях, когда вы передаете виртуальный интерфейс только на один или два уровня глубины. В ситуации, когда вы передаете через виртуальный интерфейс на большее число уровней, или что еще более важно, вы не знаете, априорно, где в иерархии получатели виртуальный интерфейс будет находиться, есть более обобщенный способ для передачи виртуальных интерфейсов. Для этой техники, которую мы называем техникой интерфейс объекта, нужно создать специальный объект для передачи интерфейса, и передать этот объект в его пункт назначения с использованием средство конфигурации. Специальный объект должен быть производным от ovm_object для того, чтобы средство конфигурации могло с ним работать.

72 class pin_vif extends ovm_object;
73
74 virtual pin_if m_vif;
75
76 function new(virtual pin_if vif);
77 m_vif = vif;
78 endfunction
79
80 endclass
file: 04_OVM_mechanics/11_vif/top.sv

Класс просто содержит виртуальный интерфейс соответствующего типа и конструктор, который устанавливает его значение, причем последний(конструктор) удобнее, и не обязательно требуется. В модуле верхнего уровня, мы создаем экземпляр объекта, назначаем виртуальный интерфейс, и положил его в базу данных конфигурации по с использованием вызова функции set_config_object ().

175 module top;
176
177 clkgen ck(clk);
178 pin_if pif(clk);
179 dut d(pif.slave_mp);
180 pin_vif vif;
181
182 env e;
183
184 initial begin
185 vif = new(pif);
186 set_config_object(*, “vif”, vif, 0);
187 e = new(“env”);
188 run_test();
189 end
190
191 endmodule
file: 04_OVM_mechanics/11_vif/top.sv

The set_vif() function and the local virtual interface are no longer needed in the environment. Other than the top-level module, the only component that needs to know about the interface object and the interface is the one that needs to use it. In our example, that is the driver.

Set_vif () и локальный виртуальный интерфейс больше не нужны в окружении. Помимо модуля верхнего уровня, единственное что нужно знать это объект интерфейса и компонент в котором этот интерфейс будет использоваться. В нашем примере это driver.

85 class driver extends ovm_component;
86
87 local virtual pin_if vif;
88
89 function new(string name, ovm_component parent);
90 super.new(name, parent);
91 endfunction
92
93 function void build();
94
95 ovm_object dummy;
96 pin_vif v;
97
98 if(!get_config_object(“vif”, dummy, 0)) begin
99 ovm_report_error(“get interface”,
100 “no virtual interface available for driver”);
101 end
102 else begin
103 if(!$cast(v, dummy)) begin
104 ovm_report_error(“interface cast”,
105 “supplied object is not the correct type”);
106 end
107 else begin
108 ovm_report_info(“get interface”,
109 “interface successfully retrieved”);
110 vif = v.m_vif;
111 end
112 end
113 endfunction
114
115 task run;
116 forever begin
117 @(posedge vif.clk);
118 ovm_report_info(“driver”,posedge clk”);
119 //...
120 end
121 endtask
122
123 endclass
file: 04_OVM_mechanics/11_vif/top.sv

Чтобы избавиться от локальных виртуальных интерфейсов и set_vif() функций, нужно написать дополнительный код в build() для получения интерфейса объект из базы данных конфигурации и убедится, что получен правильный тип. Мы получаем фиктивный объект из конфигурации базы данных с помощью get_config_object (). Тогда, если объект существует, мы приводим его к типу объекта "интерфейс". Если приведение успешно, то мы можем добраться до интерфейс объекта, чтобы получить виртуальный интерфейс и назначить его на наш локальный виртуальный интерфейс. Техника присвоения объектов "интерфес" виртуальным интерфейсам компонентов чуть более сложнее. Он требует, чтобы вы создали объект и поместили его в базу данных конфигурации.

Получатель должен получить объект и проверить, убедится, что объект действительно существует и имеет правильный тип. Тем не менее, это гораздо более общее и безопаснее, чем иерархический вызовов set_vif (). С одной стороны, только те компоненты, которые заботятся об интерфейсе должны пройти дополнительную работу получении интерфейс объекта. Никаким другим компонентам не нужно ничего делать. В то время как при использовании иерархических вызовов set_vif (), все компоненты между верхним уровнем и тот, который будет использовать интерфейс должен хранить локальную копию виртуального интерфейса и направить его вниз (по иерархии). Любой разрыв в цепи означает, что получатель не будет иметь доступа к (в распоряжении) интерфейс.

Для конструкций, которые являются небольшими, имеют мелкие иерархии, или только один виртуальный интерфейс, волноваться об этом или нет не столь очевидно. Вы можете успешно утверждают, что set_vif () метод эквивалентен или даже проще, чем техника с использованием объекта интерфейса. Однако, если ваш проект имеет несколько виртуальных интерфейсов и глубоких иерархий, техника интерфейс объекта явно превосходит. Как мы увидим в последующих главах, с использованием конфигурации объекта значительно увеличивает возможность повторного использования компонентов.