**Это старая версия документа!**

BreaksVM

BreaksVM (Breaks Verilog Machine) - виртуальная машина для выполнения Verilog-подобных скриптов.

Мы не собдюдаем стандартов, то что не поддерживается можете добавить сами.

Главная особенность и отличие от Verilog - это добавление виртуальных девайсов в скомпилированный netlist. Добавленные девайсы интегрируются в реактивную среду netlist-а и "цепляются" к выбранным IO-контактам модулей.

Устройство

Исходными данными для виртуальной машины являются Verlog-скрипты (*.v)

Встроенный компилятор создает из скриптов netlist, который затем передается статическому рекомпилятору, который преобразует netlist в быстрый платформенный код.

Управлением виртуальной машиной занимается родительское приложение.

BreaksVM API

Весь интерфейс содержится в файле breaksvm.h, а программный код - в breaksvm.c. Из зависимостей - stdio, pthread.

Типы данных используемые в BreaksVM: u8, u16, u32, u64.

  • breaksvminit () : подготовка виртуальной машины * breaksvmshutdown () : закрыть машину и освободить все используемые ей ресурсы
  • breaksvmload (filename) : указывается .v файл, который должен быть загружен в VM * breaksvminputreal (inputname, callback) : прикрепить входное устройство типа real
    • breaksvminputreg (inputname, callback) : прикрепить входное устройство типа reg * breaksvmoutputreal (outputname, callback) : прикрепить выходное устройство типа real
    • breaksvmoutputreg (outputname, callback) : прикрепить выходное устройство типа reg * breaksvmrun (timeout) : запустить симуляцию состояния. timeout задает количество итераций, для прерывания race condition.
    • breaksvm_status : 1 - VM выполняет симуляцию, 0 - VM idle

    Виртуальные девайсы, которые прикрепляются к входам и выходам виртуальной машины работают следующим образом :

  • Callbackи входных устройств выполняются ядром ДО симуляции (при вызове run)
  • Соответственно callbacks выходных устройств выполняются после прогона симуляции (в конце run)
  • Callback для девайсов типа reg имеет вид void callback (unsigned char * reg), LSB-first
  • Callback для девайсов типа real имеет вид void callback (float * reg)
  • Можно прикреплять несколько девайсов на один контакт. Выполняться они будут в порядке добавления.

Типичный пример виртуального девайса - это XTAL (генератор опорной частоты) :

void XTAL_output (unsigned char * reg)  // toggle clock
{
    if ( reg[0] == '0' ) reg[0] = '1';
    if ( reg[1] == '1' ) reg[1] = '0';
}

После инициализации VM мы устанавливаем этот callback :

breaksvm_output_reg ( "CLK", XTAL_output );

Теперь после каждого прогона run контакт CLK будет менять своё значение, тем самым тактируя схему.

Все ошибки времени компиляции и симуляции сыпятся в stdout. При серьезных ошибках run прерывается, предупреждения не прерывают симуляцию.

Диалект Verilog

Мы выкинули ненужный хлам, который не понадобился для наших целей. Считайте этот документ описанием стандарта BreaksVM =) Однако главное правило - любой verilog-скрипт для BreaksVM может быть синтезирован в реальный девайс, то есть мы не используем нестандартные дополнения.

Отличия :

  • все временные задержки (delay) игнорируются
  • fork/join блоки не поддерживаются (выдается предупреждение и блок пропускается)
  • переменные типов time и event не поддерживаются (выдается предупреждение, значение переменных всегда неопределено)
  • из всех встроенных функций поддерживается только $display, остальные игнорятся (с предупреждением)
  • нет операторов wait/forever/disable (выдается предупреждение и блок пропускается)
  • директивы препроцессора не поддерживаются (выдается предупреждение)
  • совпадение идентификаторов определенных в модуле и внутри именованного блока выдает предупреждение
  • пространства имён между блоками не поддерживаются (синтаксическая ошибка)
  • Операции редукции и сдвиги пока не поддерживаются
  • Арифметические операции + - * / % также пока не поддерживаются
  • Операцию конкатенации пока не осмыслил до конца )))
  • Пользовательские примитивы не поддерживаются (выдается ошибка)
  • Из встроенных примитивов поддерживаются только: and, nand, nor, or, xor, xnor, buf, not, bufif0, bufif1, notif0, notif1

То есть наш диалект максимально приспособлен для синтезирования логики.

Особенности реализации

Все reg и wire хранятся в памяти как байты (unsigned char). Логические значения соответственно могут быть '0', '1', 'x', 'z', 'L', 'H' итп. (char-константы)

real хранятся как float (IEEE734 32-бит). Вещественные входы/выходы используются для аналоговых схем и представляют собой моментальное напряжение.

parameter тоже самое что и integer. integer тоже самое что и reg[31:0].

Все input/output/inout всех модулей связаны реактивно. Симуляция всей системы продолжается до тех пор, пока все входы/выходы останутся неизменными.

Run flow одного запуска симуляции выглядит следующим образом :

  • Вызываются все inputdeivce callbacks, устанавливаются входные контакты * Производится выборка always блоков, при изменении реактивных сигналов, управляющих ими * Выполняется прогон схемы, до тех пор, пока состояние всех входов/выходов не стабилизируется * Вызываются все outputdevice callbacks, используются значения с выходных контактов

Разобранное синтаксическое дерево (netlist) выдается в формате EDIF 2 0 0. http://iroi.seu.edu.cn/books/asics/Book2/CH09/CH09.4.htm Каждый узел этого дерева - стандартная ячейка библиотеки breaksvm.

Netlist преобразуется в двоичную форму, а затем производится его статическая рекомпиляция. После чего VM готова к исполнению (run).

Библиотека стандартных ячеек breaksvm

Библиотека реализует стандартный набор логических элементов эпохи NMOS. Более сложные ячейки могут быть добавлены со временем.

  • x = NAND(a,b)
  • x = NOR(a,b)
  • x = AND(a,b)
  • x = OR(a,b)
  • x = XOR(a,b)
  • x = XNOR(a,b)
  • x = NOT(a)
  • x = BUF(a)
  • x = TRI(a,enable)
  • x = MUX(s,in0,in1)
  • _q = DLATCH(d,t)
  • Показать исходный текст