26 Отредактировано Voldemar0 (07-01-2018 16:48)

Re: Копаю PAL/FPGA. В целом, не только для Агата

Я их так и пишу и прямо этот файл в jed компилирую. Уравнений в виде структуры у меня нет.
(собственно, я и думаю на языке уравнений, когда это всё пишу... "И.. НЕ... ИЛИ....")

ЗЫ Нашел уже одну ошибку в формировании R_CLK

27 Отредактировано Voldemar0 (10-01-2018 20:01)

Re: Копаю PAL/FPGA. В целом, не только для Агата

Заработала ! :)))

Только год выпуска зеркально сделал :(

Post's attachments

2cut.png, 26.52 kb, 771 x 327
2cut.png 26.52 kb, 95 downloads since 2018-01-10 

DSC_0060.jpg, 164.87 kb, 762 x 589
DSC_0060.jpg 164.87 kb, 120 downloads since 2018-01-10 

DSC_0061.jpg, 187.51 kb, 773 x 602
DSC_0061.jpg 187.51 kb, 108 downloads since 2018-01-10 

28 Отредактировано Voldemar0 (13-11-2019 09:37)

Re: Копаю PAL/FPGA. В целом, не только для Агата

Продолжил ковырять тему матриц. Осваиваю Verilog. Экспериментирую с небольшой платкой, на которую запаяна epm3064.
Поставил max plus II и пару Quartus II (9 и 11). Пока читаю книжки и статьи и пишу мелкие тестовые проги.

Как-то сразу повезло попасть на два то ли бага, то ли фичи:

1)

module ac(x)
input x;
wire x = 1;

Вроде бы объявляю x как вход, но при этом могу ему же присвоить значение. Max Plus II это пропускает, похоже по ошибке.
При этом x становиться как бы локальной шиной (т.е. разрывается его связь с вышележащим модулем).
Квартусы ругаются на ошибку.

2)

always @(posedge s) begin
t1 <= t1 + 1;
case (x)
    3'bxx1: t1 <= 4;
    3'b11x: t1 <= 3;
endcase
end

В квартусе case работает только если варианты определены полностью (без "x"). Те, которые с 'x', тихо игнорируются и ничего не синтезируют.

В max plus II варианты с 'x' корректно синтезируются и потом работают в симуляции.

29 Отредактировано LeoN (14-11-2019 03:49)

Re: Копаю PAL/FPGA. В целом, не только для Агата

1) Так низзя делать. Раз ты объявил его входом, то и присваивать низзя. Нарисуй эту схему и все станет очевидно.

2А) В блоке always все действия происходят одновременно и параллельно по положительному фронту s. А ты же И инкрементируешь t1 И присваиваешь t1 значения. КАК ТАК??? Напомню: все происходит ОДНОВРЕМЕННО и ПАРАЛЛЕЛЬНО по клоку. Это НЕ ПРОГРАММА, которая выполняется последовательно... Меняй мЫшление! ;) Перестраивайся на синхронный дизайн.

2Б) Для case с вариантами 'x' есть casex. И для case с вариантами 'z' есть casez.

2В) Для case очень и очень желательно default-вариант.

Турбо АГАТ-9/16 (65C802 CPU, 2.8 Маха), MSX2 Yamaha YIS503IIIR.

30 Отредактировано x0Dh (13-11-2019 17:18)

Re: Копаю PAL/FPGA. В целом, не только для Агата

Вставлю свои 3 копейки по verilog и мышлению.

Целую неделю бился и решил свою задачку. Тут не важно какую, но мышление изменил снова :-)
В verilog цепи (wire) и регистры (reg) по умолчанию со знаком, даже однобитные. Поэтому операция инверсии бита ~ меняет знак.
Пример:
Сумматор с переносом.

wire A;
wire B;
wire S;               // сумма
wire P;               //бит переноса 

assign {P,S} = A + B;

Тут собственно будет работать как надо.
A=0 B=0 выход S=0 P=0,
A=0 B=1 выход S=1 P=0,
A=1 B=0 выход S=1 P=0,
A=1 B=1 выход S=0 P=1.
Но, если изменить суматор с инверсией А. Вот так:

assign  {P,S} = ~A + B;

То тут будет так:
A=0 B=0 выход S=1 P=1,
A=0 B=1 выход S=1 P=1,
A=1 B=0 выход S=0 P=0,
A=1 B=1 выход S=1 P=0.

То есть при инверсии единицы, получаем ноль с минусом :-)

Я решил так:

assign  {P,S} = $unsigned( ~A ) + B;

31

Re: Копаю PAL/FPGA. В целом, не только для Агата

x0Dh пишет:

В verilog цепи (wire) и регистры (reg) по умолчанию со знаком, даже однобитные.

Не стоит выдумывать небылицы...

x0Dh пишет:
assign  {P,S} = ~A + B;

А попробуй вместо "~" использовать "!". Что получится в итоге? И расскажи нам. ;)

Турбо АГАТ-9/16 (65C802 CPU, 2.8 Маха), MSX2 Yamaha YIS503IIIR.

32 Отредактировано Voldemar0 (14-11-2019 09:04)

Re: Копаю PAL/FPGA. В целом, не только для Агата

Спасибо за подсказки, но я ещё не захожу так далеко, чтобы думать о хорошем стиле.
Мне сейчас важно убедиться, что я правильно понимаю синтаксис языка и логику действий компилятора.
Я придумываю какие-то примеры, возможно и не удачные для практической реализации, но мне важнее, чтобы компилятор выдал какой-то конкретный фрагмент именно так, что мной было задумано. Если этого не происходит, я разбираю причины.

Например, я придумываю два модуля, в каждом из которых вычисляется какая-то функция. Причем с одними и теми же входными данными. И потом смотрю итог. Мне интересно, сообразит ли компилятор, что эту функцию можно реализовать в железе один раз,  а не дважды. Не соображает :(.

Дело в том, что компиляторы для традиционных языков программирования уже достигли очень приличной оптимизации кода.
Иногда речь заходит даже о том, что они могут давать код лучше, чем средний ассемблер -программист. И я сам это вижу: когда какой-нибудь небольшой кусок проги на 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: ;" ?

33 Отредактировано LeoN (14-11-2019 11:32)

Re: Копаю PAL/FPGA. В целом, не только для Агата

Voldemar0 пишет:

но мне важнее, чтобы компилятор выдал какой-то конкретный фрагмент именно так, что мной было задумано.

Voldemar0 пишет:

Могу ли я расчитывать на то, что компилятор предупредит о проблемах или оптимизирует конфигурацию или же нужно самому заранее это всё делать максимально эффективно, даже в ущерб читаемости исходника ?

Цампутер (и компилятор) - это просто ящик с килобайтами. Он не умеет мыслить. Это твоя задача мыслить. И твоя же задача объяснить компилятору по его правилам и ограничениям то, что ты задумал.

Voldemar0 пишет:

Так в том всё и дело, что если это технически невозможно, то почему компилятор не сообщает об ошибке ?
Или всё таки есть некая договорённость внутри языка, которая говорит о том, что условные выражения имеют приоритет перед безусловными ? Может она там мультиплексер синтезирует в ответ, который при совпадении case отключит инкремент.

Дык, тогда поставь инкремент в case-default. Цампутер не умеет читать твои мысли. А если ты именно так задумал, так и объясни ему это. Сможешь нарисовать схему твоего первоначального варианта? Я думаю - нет. По тому, как ты описал первоначальный вариант - я тоже не смогу нарисовать... Почему ты решил, что ящик с килобайтами сможет решить твой ребус?...

Еще раз: это не последовательная программа. Это параллельные вычисления! В случае комбинаторики - параллельные непрерывные вычисления. В случае регистров (синхронизм) - параллельные одновременные и одномоментные вычисления.

Voldemar0 пишет:

Иначе что будет ? Ненужное усложнение схемы или путаница ?

Где-то на просторах zx-pk попадалось, что if без else, и case без default дают латчи... И case без default дает что-то вроде приоритетного шифратора... А с ними дают нормальные мультиплексоры.

Voldemar0 пишет:

Например, я делаю параллельный сдвиговый регистр:

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: ;" ?

Пустой default вряд ли проканает. А вот default: q <= q; - вполне!
И почему у тебя вместо сдвига идет сравнение?

Турбо АГАТ-9/16 (65C802 CPU, 2.8 Маха), MSX2 Yamaha YIS503IIIR.

34

Re: Копаю PAL/FPGA. В целом, не только для Агата

LeoN пишет:
x0Dh пишет:

В verilog цепи (wire) и регистры (reg) по умолчанию со знаком, даже однобитные.

Не стоит выдумывать небылицы...

x0Dh пишет:
assign  {P,S} = ~A + B;

А попробуй вместо "~" использовать "!". Что получится в итоге? И расскажи нам. ;)

Эээ..какие небылицы? Как додумался так и рассказал, я только учусь :-)

А за логическое отрицание спасибо. Я про него думал, но почему оставил на потом. Да все работает так же как с @unsigned.
Это ж тоже все к "мышлению" ? :-)

35

Re: Копаю PAL/FPGA. В целом, не только для Агата

x0Dh пишет:

Эээ..какие небылицы?

Ну это правда небылица... Ты уж не обижайся. ;)
Fixed point arithmetic - это всего лишь абстракция. Сумматор с переносом - это такая же абстракция с использованием двоичных СИГНАЛОВ.

x0Dh пишет:

Как додумался так и рассказал, я только учусь :-)

Все мы учимся и делимся здесь граблями и опытом. ;)

Турбо АГАТ-9/16 (65C802 CPU, 2.8 Маха), MSX2 Yamaha YIS503IIIR.

36 Отредактировано Voldemar0 (14-11-2019 14:50)

Re: Копаю PAL/FPGA. В целом, не только для Агата

Че-то меня заинтересовала эта инверсия :)
Залез в стандарт 1364-2001 :
4.1.6: A reg data type shall be treated as an unsigned value unless explicitly declared to be signed.
А вот про wire такого чёткого определения не удалось найти :(.


Про case и default:
в документе от Synopsys (на который я давал ссылку) говорится следующее:
компилятор сам решает, синтезировать ли case в приоритетеный энкодер или в мультиплексер.
Но ему можно подсказать это опциями: //parallel_case или //full_case (возможно, это есть только в компиляторах synopsis).
Также влияет наличие default либо полный/не полный список всех возможных комбинаций case.

Нужно учитывать, что если вы во всех возможных комбинациях case задаёте значение какому-нибудь reg,
то этот reg может быть пострен как wire (т.е. синтезируется просто коммутатор). В то время как при не полном описании возможных
комбинаций (т.е. когда переменная может не менять значение в case) reg будет именно регистром.

Суть: что с default, что без него - это не плохие комбинации. Но они могут неожиданно для разработчика становиться
очень непохожими между собой в железе, что приведёт, как обычно, к внезапно уплывшим таймингам.


> И почему у тебя вместо сдвига идет сравнение?
Ошибся просто.


> Цампутер не умеет читать твои мысли.
А ему не надо читать.
Если ему не хватает моего описания или оно противоречит стандарту языка - он должен сказать об ошибке.
Если же противоречий нет - он должен синтезировать схему в соответствии со стандартом.
И всё.

Но он, в случае двойного "T1<="  не сообщает об ошибке синтеза. Значит либо он косячит либо стандарт как-то допускает такое описание. Надо порыться в описании стандарта...

37 Отредактировано LeoN (14-11-2019 17:26)

Re: Копаю PAL/FPGA. В целом, не только для Агата

Подводные камни с блокирующим и неблокирующим присваиваниями. И еще.

Турбо АГАТ-9/16 (65C802 CPU, 2.8 Маха), MSX2 Yamaha YIS503IIIR.