SystemVerilog-RU
Блог сайта www.SystemVerilog.ru
пятница, 26 ноября 2010 г.
Зачем нужны clocking-блоки в SystemVerilog?
Интерфейс описывает сигналы, с помощью которых testbench взаимодействует с тестируемым устройством (DUT). Однако, интерфейсы явно не описывают временные ограничения и синхронизацию. Для этого в SystemVerilog добавлены clocking-блоки. Они отделяют все, что связано с временными параметрами и синхронизацией от других элементов testbench'а. С помощью clocking-блоков можно группировать сигналы, изменяющиеся по одному тактовому сигналу.
пятница, 19 ноября 2010 г.
В чем различие между типами данных wire, reg и logic?
Тип данных определяет набор значений и набор операций над этими значениями.
bit | logic | reg | byte | shortint | int | longint | integer | time | byte | shortint | int | longint | integer | time | struct | union | enum | string | event и т.д. - все это типы данных.
reg и logic тута. А где wire? Попробуем разобрать, что такое классы объектов, может там найдется wire.Итак, в SV выделяют следующие классы объектов: литералы, параметры, константы, переменные, сигналы и атрибуты. Все они описаны в стандарте. Мы же рассмотрим поподробнее классы объектов "переменные" (variables) и "сигналы" (nets).
К классу "сигналы" относятся -
supply0 | supply1 | tri | triand | trior | trireg | tri0 | tri1 | uwire | wire | wand | wor.
Вот и нашелся wire. Объекты класса "сигналы" по умолчанию относятся к типу данных logic и поэтому:wire a;
иwire logic a;
эквивалентны. Все, что явно не объявлено объектом класса "сигналы", становится объектом класса "переменные". Объявить переменную можно с помощью типа данных и следующего за ним названия переменной:logic a;
или с добавлением ключевого слова var:var logic a;
Это эквивалентные записи. При использовании var тип данных можно не указывать, тогда по умолчание тип данных будет logic.wire
- Wire используется для соединения различных элементов
- Wire представляет собой физический провод (цепь)
- Wire можно считывать или присваивать
- Wire не может хранить значение
- Для определения состояния сигнала в цепи, у нее должен быть источник сигнала (драйвер), который будет непрерывно управлять цепью
- Wire может иметь несколько драйверов. Что в этом случае происходит, читаем здесь
- Назначить драйвер для wire можно с помощью оператора непрерывного присваивания assign или через порт модуля
- При синтезе wire всегда воспринимается как провод
reg
- Reg в Verilog/SystemVerilog представляет элементы хранения данных (аналог переменной в языках программирования)
- Reg не всегда представляет физический регистр. При синтезе может получиться регистр (flip-flop), регистр-защелка (latch) или комбинационная логика (еще есть вариант, когда может вообще ничего не получиться - это называется несинтезируемая конструкция).
logic
- Ключевое слово logic было добавлено в стандарт, чтобы разработчики больше не думали, что используя переменную reg, они получат физический регистр. logic - это эквивалент reg.
- Если к переменной типа logic одновременно осуществляется несколько присваиваний, то выбирается последнее.
- Присваивание переменной типа logic можно осуществить с помощью оператора непрерывного присваивания assign (тогда она воспринимается, как wire), через порт модуля или в процедурном блоке:
logic sum;
assign sum = a ^ b; // как wire
always_comb sum = a + b; // как reg
adder adder_inst(.out(sum), .op1(a), op2(b)); // как wire
четверг, 18 ноября 2010 г.
Что такое Factory Pattern в SystemVerilog?
О том, что такое паттерн, уже писалось здесь. Вкратце напомню, что паттерн в ООП - это устоявшееся решение проблем, которые возникали, возникают и будут возникать. У некоторых из этих решений есть свое название. Что же такое factory pattern (или фабричный паттерн)? Сперва обратимся к определению фабричного метода из wiki:
Фабричный метод (англ. Factory Method) — порождающий шаблон проектирования, предоставляющий подклассам интерфейс для создания экземпляров некоторого класса. В момент создания наследники могут определить, какой класс инстанциировать. Иными словами, Фабрика делегирует создание объектов наследникам родительского класса. Это позволяет использовать в коде программы не специфические классы, а манипулировать абстрактными объектами на более высоком уровне. Также известен под названием виртуальный конструктор. Фабричный паттерн нацелен на решение проблемы создания объекта. Есть еще набор паттернов, которые имеют отношение к созданию объекта, предназначенные для различных случаев. Они известны под названием creational patterns (порождающие паттерны).
Рассмотрим пример использования порождающего паттерна на SystemVerilog. Создадим класс для "Фабрики роботов", который необходим, чтобы создавать разные типы роботов (Андроид (android), Боевой робот (robokiller), Бытовой робот (robomama), Персональный робот (robocomp)). Тип робота будет выбираться с помощью входной строки.
Для каждого типа робота нам потребуется свой класс. Создадим базовый класс ROBO, который будет содержать общие для всех классов переменные, подзадачи task, функции function. Остальные классы будут наследовать базовый класс:
class ROBO;
// Общие объекты данных
string type;
// Общие методы
virtual function string get_type();
endclass : ROBO
class ANDROID extends ROBO;
function new();
this.string = "Android";
endfunction : new
string function string get_type();
return this.string;
endfunction : get_type
endclass : ANDROID
class ROBOKILLER extends ROBO;
function new();
this.string = "ROBOKILLER";
endfunction : new
string function string get_type();
return this.string;
endfunction : get_type
endclass : ROBOKILLER
Теперь опишем класс "фабрики роботов" (ROBO_FACTORY). Для простоты пронумеруем каждый тип робота, чтобы было легче выбирать, какого робота создавать.
class ROBO_FACTORY;
ROBO my_robo
// Общие методы
function ROBO get_robo(int type);
if(type == 1) this.my_robo = new ANDROID();
if(type == 2) this.my_robo = new ROBOKILLER();
return this.my_robo;
endfunction : get_robo
endclass : ROBO_FACTORY
Дополнительно читайте здесь.
вторник, 16 ноября 2010 г.
Что такое Callback в SystemVerilog?
Callback (англ. call — вызов, англ. back — обратный) или фу́нкция обра́тного вы́зова в программировании — передача исполняемого кода в качестве одного из параметров другого кода.
Например, вам необходимо передать одну функцию в качестве входного параметра другой функции. Это и есть callback.
Как это реализуется с помощью средств ООП в SystemVerilog? Рассмотрим пример:
Есть базовый класс my_transactor, который принимает транзакции от драйвера и пересылает их в монитор:
class my_transactor;
...
task main();
...
forever begin
...
// Достаем из почтового ящика транзакцию,
// которую прислал драйвер
driver2xactor.get(in_tr);
// Выполняем необходимые действия
...
// Отправляем транзакцию в блок монитора
xactor2monitor.put(out_tr);
...
end
endtask
endclass
Предположим, мы хотим просто посмотреть содержимое принятой транзакции и содержимое транзакции, подготовленной для пересылки в монитор:
class my_transactor;
...
task main();
...
forever begin
...
// Достаем из почтового ящика транзакцию,
// которую прислал драйвер
driver2xactor.get(in_tr);
$display(" Input trans: a = %h, b = %h", in_tr.a, in_tr.b);
// Выполняем необходимые действия
...
// Отправляем транзакцию в блок монитора
$display(" Output trans: a = %h, b = %h", out_tr.a, out_tr.b);
xactor2monitor.put(out_tr);
...
end
endtask
endclass
Теперь этот код непригоден для повторного использования, т.к. добавленные сообщения специфичны для конкретной тестируемой схемы (DUT) или для определенного теста. Это становится ощутимо, если поменять содержимое транзакции или попробовать не выводить содержимое транзакции в наследуемом классе. Необходимо избегать использования специфичного для данной реализации кода в тестовых окружениях, предназначенных для повторного использования. Эта проблема общая для повторно используемого кода, не только касательно верификации. И средства ООП предлагают решение этой проблемы: виртуальные методы. С помощью них можно расширить возможности транзактора при необходимости:
class my_transactor;
virtual task pre_exec(in_trans tr);
endtask
virtual task post_exec(out_trans tr);
endtask
...
task main();
...
forever begin
...
// Достаем из почтового ящика транзакцию,
// которую прислал драйвер
driver2xactor.get(in_tr);
this.pre_exec(in_tr);
// Выполняем необходимые действия
...
// Отправляем транзакцию в блок монитора
this.post_exec(out_tr);
xactor2monitor.put(out_tr);
...
end
endtask
endclass
class my_transactor_child extend my_transactor;
virtual task pre_exec(in_trans tr);
$display(" Input trans: a = %h, b = %h", tr.a, tr.b);
endtask
virtual task post_exec(out_trans tr);
$display(" Output trans: a = %h, b = %h", tr.a, tr.b);
endtask
...
endclass
Как это работает? В базовом классе my_transactor есть 3 подзадачи task, 2 из которых виртуальные и не реализованы. Класс-потомок my_transactor_child наследует методы базового класса и может и заполняет виртуальные методы в соответствии со своими нуждами. Тем самым мы можем вносить изменения в метод main, не изменяя его код.
Callback методы содержат фрагменты кода, функции и подзадачи, которые меняются от теста к тесту. Они очень полезны, когда идет речь о создании базового класса, который планируется использовать в нескольких тестовых окружениях.
У приведенного выше примера callback есть некоторые ограничения, которые можно решить с помощью паттернов. Паттерны в ООП это не базовые классы или библиотеки. Это некий шаблон проектирования или техника для построения объектно-ориентированного кода, которая позволяет решить сложные задачи. Подробнее об этом в статье - Janick Bergeron "How to use VMM callbacks"