May 3rd, 2012

Пара пожеланий синтаксису Verilog от Java-программиста

Синтаксис языка Verilog гораздо приятнее глазу C/C++/Java-программиста, чем VHDL - объявление модулей визуально похоже на объявление функций, объявлениех внутренних переменных, конструкции if/else if/else/case и т.п., но после ближайшего практического знакомства мне стали заметны еще несколько нюансов, которые можно было бы улучшить.

1. В Verilog для выделения блоков кода используются маркеры begin/end - в C/Java их полный аналог - фигурные скобки {}.

Код Verilog:
if(condition)
begin
    pio[0] = 1;
    pio[1] = 0;
end

Аналогичный (синтаксически) код Java:
if(condition) {
    pio[0] = 1;
    pio[1] = 0;
}

Конструкция begin/end очевидно более громоздка, чем фигурные скобки, поэтому их довольно часто (по крайней мере в примерах в книгах, которые я видел) упускают например при однострочных условиях типа:

if(condition)
    pio[0] = 1;

При этом если в обработчик условия понадобится добавить дополнительную строку с новой инструкцией (как в примере выше), то begin/end придется все-таки проставить.

В яве тоже можно так делать:

if(condition)
    pio[1] = 0;

Но т.к. выигрыш от подобного упрощения с точки зрения визуального облегчения кода не сильный, а читабельность кода повышается, и при этом понижается вероятность допущения целого класса глупых, но трудноуловимых ошибок (когда человек смотрит на 2 строки кода после if и думает, что они находятся внутри одного блока, а на самом деле из-за отсутствия скобок при условии if будет выполняться только 1я строка), во многих проектах и компаниях внутренними правилами форматирования кода запрещено использовать "однострочные условия" и требуется окаймлять блоки фигурными скобками во всех ситуациях, даже если это делать не обязательно:

if(condition) {
    pio[1] = 0;
}

Лично я уже словил пару проблем с забытыми begin/end на верилоге, поэтому и вспомнил хорошим словом фигурные скобки и правило хорошего тона в аналогичной ситуации в яве.

2. Я уже обращал внимание на то, что как сам концепт модулей, так и определения инстансов одних модулей внутри других модулей по многим критериям очень сильно напоминает определение и инстанциацию объектов в С++ или Java. Однако эта аналогия на мой взгляд продлена не достаточно сильно и синтаксис обращения с модулями можно было бы еще улучшить.

В частности допустим у меня есть модуль timer, у которого есть 3 параметра - clock, reset, finished:

module timer(input clock, input reset, output finished);
//...
endmodule


Теперь если я захочу создать два таймера внутри другого модуля и потом управлять ими через их параметры, в Verilog я должен буду написать примерно следующее:

// instantiate 1st timer
wire timer1_reset;
wire timer1_finish;
timer timer1(.clock(clock), .reset(timer1_reset), .finish(timer1_finish));

// instantiate 2nd timer
wire timer2_reset;
wire timer2_finish;
timer timer2(.clock(clock), .reset(timer2_reset), .finish(timer2_finish));

//...
    timer1_reset = 1;
    timer2_reset = 1;
// ...
    if(timer1_finish)
//...
    if(timer2_finish)
//...

Т.е. приходится в некотором роде "приделывать" к модулю снаружи провода wire и через них уже с ним взаимодействовать. Хотя было бы вполне логично, если бы синтаксис языка давал такую возможность изначально без привлечения дополнительных конструкций - я думаю на этот функционал мог бы идеально лечь концепт обращения с атрибутами экземпляров (инстансов) объектов в C++ или Java - например этот же код мог бы выглядеть примерно так:

// instantiate 1st timer
timer timer1(.clock(clock));
// instantiate 2nd timer
timer timer2(.clock(clock));

//...
    timer1.reset = 1;
    timer2.reset = 1;
// ...
    if(timer1.finish)
//...
    if(timer2.finish)
//...

При таком обращением с экземплярами модулей компилятор бы сам определил необходимые внутренние переменные wire timerXX_reset и timerXX_finish, т.е. в конечном итоге внутренний смысл кода ничем бы не отличался о приведенного выше рабочего куска, но код модуля стал бы намного чище и логичнее.