Спасибо за подсказки, но я ещё не захожу так далеко, чтобы думать о хорошем стиле.
Мне сейчас важно убедиться, что я правильно понимаю синтаксис языка и логику действий компилятора.
Я придумываю какие-то примеры, возможно и не удачные для практической реализации, но мне важнее, чтобы компилятор выдал какой-то конкретный фрагмент именно так, что мной было задумано. Если этого не происходит, я разбираю причины.
Например, я придумываю два модуля, в каждом из которых вычисляется какая-то функция. Причем с одними и теми же входными данными. И потом смотрю итог. Мне интересно, сообразит ли компилятор, что эту функцию можно реализовать в железе один раз, а не дважды. Не соображает :(.
Дело в том, что компиляторы для традиционных языков программирования уже достигли очень приличной оптимизации кода.
Иногда речь заходит даже о том, что они могут давать код лучше, чем средний ассемблер -программист. И я сам это вижу: когда какой-нибудь небольшой кусок проги на C реально компилируется в такой же небольшой ассемблер-код. С выкидыванием всех неиспользуемых функций, с развёрткой выражений, подстановкой констант, удалением условий, которые никогда не выполнятся. И это ещё не всё: где-то в интеловских документах об оптимизации когда для 3-4 пней были и более изысканные примеры, когда в 3-5 ассемблер-команд компилировалось несколько арифметических выражений, да ещё и с условиями.
Кроме того, последние годы я замечаю, что компиляторы становятся не только эффективными внутри, но и снаружи:
они в warning'ах уже подсказывают многое, что как бы разрешено в языке, но может неоднозначно выглядеть и, вероятно,
является ошибкой. Они анализируют соответствия строки формата printf и фактических аргументов, соответствия типов
указателей, предупреждают о всяких "if (x=1)" и подобном. Недавно даже увидел предупреждение в какой-то конструкции вида:
"if () c(); else if () a(); else b();" что-то вроде "запутаетесь вы в своих else, однако".
И я вот пытаюсь понять, когда пишу какую нибудь фигню: эта фигня не должна компилироваться вообще или я придумал что-то вроде:
int x[10][20];
main() {
printf("%d\n", x[3,5]);
}
Т.е. это плохой стиль, такая прога делает что-то совсем непонятное с точки зрения программиста, переходящего с паскаля на C, например. Но она даёт вполне предсказуемый результат с точки зрения документации на язык.
Я хочу оценить, на что способен verilog, мне хочется понять, что он видит в моих примерах.
Могу ли я расчитывать на то, что компилятор предупредит о проблемах или оптимизирует конфигурацию или же нужно самому заранее это всё делать максимально эффективно, даже в ущерб читаемости исходника ?
> 2А) В блоке always все действия происходят одновременно и параллельно по положительному фронту s. А ты же И инкрементируешь t1 И присваиваешь t1 значения. КАК ТАК??? Напомню: все происходит ОДНОВРЕМЕННО и ПАРАЛЛЕЛЬНО по клоку. Это НЕ ПРОГРАММА, которая выполняется последовательно... Меняй мЫшление! ;) Перестраивайся на синхронный дизайн.
Так в том всё и дело, что если это технически невозможно, то почему компилятор не сообщает об ошибке ?
Или всё таки есть некая договорённость внутри языка, которая говорит о том, что условные выражения имеют приоритет перед безусловными ? Может она там мультиплексер синтезирует в ответ, который при совпадении case отключит инкремент.
> 2Б) Для case с вариантами 'x' есть casex. И для case с вариантами 'z' есть casez.
Вот тут интересно: это было введено в поздних версиях языка или max plus не даёт ошибок потому что просто опять косячит ?
Т.е. case предназначен только для полностью определённых случаев и в моём примере должна была возникнуть ошибка компиляции ?
Выкопал стандарт языка, не знаю - актуальный или нет:
http://www.csit-sun.pub.ro/~cpop/Verilo … synver.pdf
Тут говорится: "A case item consists of an expression (usually a simple constant) or a list of expressions separated by commas, followed by
a colon (:).". Как бы нечёткое определение. Т.е. для case вроде как и не запрещены xxx. С другой стороны, для casex:
"A case item can have expressions consisting of... A constant containing z, x, or ?"
> 2В) Для case очень и очень желательно default-вариант.
Иначе что будет ? Ненужное усложнение схемы или путаница ?
Например, я делаю параллельный сдвиговый регистр:
module preg(clk, wire [1:0] mode, [7:0] data, [7:0] q)
always @(posedge clk) begin
case (mode)
2'b01: q <= q < 1;
2'b10: q <= q > 1;
2'b11: q <= data;
endcase
end
По логике вещей, мне не нужна тут комбинация mode==00 - это просто хранение данных в q.
Я расчитываю получить из case обычный дешифратор режима из трёх комбинаций двухвходовых элементов И и парочкой НЕ.
Что мне даст default ? Будет ли польза от того, что я добавлю пустой "default: ;" ?