Перейти к содержанию
    

Профессия RTL Designer не имеет будущего?

to Leka

То, к чему тянется ваша душа, имеется в природе под названием SystemC. Я, правда, кроме названия, ничего про него не знаю. Советую обратить внимание.

 

to SM

Извиняюсь, поздно откликнулся.

Кстати... Вот очень простой и яркий пример неоднозначности из синопсисовских док.

 

always @(posedge clk)

a=b;

always @(posedge clk)

b=a;

...

А если заменить на <= , то все станет однозначно? Да то же самое и будет. Ну и дальнейшие ваши выводы, как я думаю, неверные.

Изменено пользователем ViKo

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

... Да то же самое и будет. Ну и дальнейшие ваши выводы, как я думаю, неверные.

 

А почему Вы так решили?

 

 

 

 

 

Вы проверяли? Какой пример, какие результаты?

 

Или Вы где-то прочитали? Где? Стандарт? Какой пункт?

 

 

 

 

Давайте не будем писать просто то, что пришло в голову.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А почему Вы так решили?

 

 

 

 

 

Вы проверяли? Какой пример, какие результаты?

 

Или Вы где-то прочитали? Где? Стандарт? Какой пункт?

 

 

 

 

Давайте не будем писать просто то, что пришло в голову.

Потому что обновление переменных a и b будет происходить одинаково по времени и для =, и для <=. Ведь в приведенных блоках никаких других операторов нет. Задержек нет. Появился clk, изменились a и b. В самом блоке, в момент clk, или при выходе из блока в тот же момент clk. Согласны? Ну а дальше, как сказал...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

... Согласны? ...

 

Не согласен.

 

 

Прочитайте в стандарте. Посмотрите в симуляторе. Убедитесь, что Вы не правы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если заменить на <= , то все станет однозначно? Да то же самое и будет. Ну и дальнейшие ваши выводы, как я думаю, неверные.

 

Да, все станет однозначно, и синопсис это прямо и недвусмысленно пишет. Читайте документацию и стандарт. Разница в том, что блокирующие вычисляются в один этап, во время вычисления всех RHSов, отсюда и неоднозначность, так как присваивание может произойти раньше, чем взятие его результата в другом блоке, а может и позже, несмотря что симуляционное время формально одно. А неблокирующие - в первый этап "собирают все результаты RHSов", а во второй, когда вычислены все RHS во всех блоках, - все присваивают. Поэтому неоднозначности нет. И выводы верные. И я вполне признаю, что писал раньше неоднократно такой код, с потенциальными гонками... Больше не буду, буду блокирующие использовать только для переменных, используемых только в пределах одного блока begin..end.

 

Потому что обновление переменных a и b будет происходить одинаково по времени и для =, и для <=.

Неверно и ошибочно. Формально - по времени (симуляционному) одинаково. Физически не одинаково, так как алгоритмы разные, поэтому возникает "race condition" для блокирующих, и не возникает для неблокирующих.

 

Вы считаете, что в операторе for(i=0, i<n, i++) используются блокирующие присваивания?

А в assign a = b & c; - тоже?

Не я считаю, а стандарт считает. 9.6. "for ( variable_assignment ; expression ; variable_assignment )" А какой assignment - какой напишите, такой и будет. Все обычно применяют блокирующие. Вы, по ходу, хотите без них обойтись. Ну ладно, уговорили, если в for это кому-то явно не видно, то давайте остановимся на while ( в 9.6 в конце для непонятливых написано, что делает for и какой у него эквивалент в while).

 

в assign неблокирующее. Читайте 5.6.1, там ясно написано, "adds an active update event", а не сразу присваивает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С `define - это для практики, чтобы понять, что и как поправить в препроцессоре.

Препроцессор - это костыли. Код препроцессора (макроподстановки) выполняется скрытно и без проверки типов и прочего, что может приводить к очень подлым ошибкам, которые трудно обнаружить, анализируя код. Поэтому препроцессор более-менее годится для каких-то относительно несложных вещей, и писать на его основе целый язык - не очень удачная идея.

 

Вы считаете, что в операторе for(i=0, i<n, i++) используются блокирующие присваивания?

Тут - да, блокирующие.

 

А в assign a = b & c; - тоже?

Нет, тут это continuos assignment.

 

Так неблокирующее присваивание в коде расположено до блокирующего.

 

А в последовательном блоке присваивания должны выполняться по порядку.

Тогда получается, что:

 

A blocking procedural assignment statement shall be executed before the execution of the statements that

follow it in a sequential block.

 

избыточная инфа - ведь все выражения в последовательном блоке и так всегда выполняются последовательно. :)

 

Лично мне кажется, что Вы занимаетесь неблагодарным и ненужным делом.

Подпишусь. Но только потому, что достичь полезного результата - создать синтезатор, полезный при решение повседневных боевых задач, одному человеку в факультативном режиме не реально. А цель весьма достойная.

 

Можно писать на С в стиле С++ (в стиле ООП) или на С++ в стиле С (не используя ООП), можно также пытаться писать на С как на LISP.

 

Но, на мой взгляд, самый хороший результат будет достигаться, если писать на С когда нужен чисто императивный язык, для ООП испоьзовать С++, и использовать LISP, когда Вам нужен функциональный язык.

<offtopic>По С++ уточню: С++ позволяет писать и в процедурном стиле, как С, и в объектом, и в ООП. С++ - не ОО язык, ООП - это один лишь из аспектов С++.</offtopic>

 

Каждый инструмент создан, чтобы решать определенные задачи, и, скорее всего (если он создан с умом), именно он будет решать эти задачи лучше всего.

 

HDL созданы, чтобы описывать устройства. Если Вам нужно описать устройство - Ваш выбор HDL.

Это только потому, что пока нет распространенных и доступных синтезаторов с языков более высокого уровня, чем HDL. Вот представьте, что вы пишете код типа:

 

// процесс N
for(int i = 0; i < N; ++i)
{
    res[i] = a3*x[i]^3 + a2*x[i]^2 + a1*x[i] + a0;  // вычисление значения полинома
}
flag Done = true;
...
// процесс M
wait_event(Done)
{
    ...;
}

указываете констрейн по скорости (с какой частотой должно выплевывать значения), и синтезатор сам под целевое "железо" родит конвейер, побьет код на такты, наведет синхронизацию по событиям и т.д. При этом вам не надо париться с тактами, заводить кучу промежуточных низкоуровневых переменных - синтезатор сам все это сделает. А вы можете сосредоточиться на целевой задаче. По сути это уход с уровня ассемблера на уровнь языка вроде С/Паскаль.

 

Разве создание такого синтезатора - не достойная цель? Имхо, очень достойная.

 

По-моему, лучше потратить больше времени на глубокое (или очень глубокое) изучение языка. Или на практику.

Ну, это всяко нужно. Даже есть есть хороший синтезатор (как в вышеописанной фантазии (а может, уже не совсем фантазии?)), все равно нужно четко представлять себе, как и что делается на низком уровне (а то и помочь кое-где недогадливому синтезеру - "ассемблерной" вставкой). Иначе, без вникания во внутренние механизмы и понимания этих процессов, будет фигня. С которой часто сталкиваются РС программисты, которые начинают писать под embedded, не вникая в особенности целевой платформы.

 

 

to Leka

То, к чему тянется ваша душа, имеется в природе под названием SystemC. Я, правда, кроме названия, ничего про него не знаю. Советую обратить внимание.

Еще были бы синтезаторы под него доступны. :(

 

Кстати... Вот очень простой и яркий пример неоднозначности из синопсисовских док.

 

always @(posedge clk)

a=b;

always @(posedge clk)

b=a;

 

Имеет право при симуляции равновероятно обменять a с b, занести в обе "a", или занести в обе "b", в зависимости от того, последовательно ли были обработаны эти эвенты, в какой последовательности, или вообще параллельно. Однако при синтезе - гарантирована однозначность - обмен. И, заметим, опять пример никак не связан с гарантировано-последовательным исполнением внутри begin...end. Те самые гадкие межблочные связи.

Именно такой пример приведен в той книжке из поста №234. И с почти точно такими же комментариями.

 

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

Ну, не совсем так. Для регистрового блока такое поведение не подходит, а вот для комбинационного...

 

always @*  begin
    a = x;
    b = y;
end

always @*  begin
     d = x;
     c = a;
end

Допустим, что первым выполнился первый блок, а получило значение х. Затем выполняется второй блок, и c получает значение а (т.е. тоже х), как и задумано. Теперь пусть первым выполнился второй блок. с получило значение а, которое еще хранит предыдущую величину. Затем выполняется первый блок, а получается значение х, и это событие активизирует второй блок, в котором с получается значение а (х). Т.е. конечный результат одинаков. Гонки есть? Есть. Но гонки в комбинационной логике - это обычное дело, от них не избавиться ни на симуляторе, ни в железе, можно лишь писать код так, чтобы гонки не влияли на правильность работы задуманного (синхронный дизайн - один из подходов для достижения этого).

 

Таким образом, использование блокирующих присваиваний в комбинационных блоках вполне безопасно.

 

А отсюда - еще вывод. Присваивать окончательный результат, предназначенный для использования в других блоках, если внутри блока он итерационно или последовательно вычислялся с использованием блокирующих присваиваний, желательно всегда неблокирующим, и именно в том же блоке (иначе гонки!!).... Если не хотите на synthesis/simulation mismatch нарваться. Вот так получается. Как-то так:

 

begin
  temp1 = .....;
  temp2 = ....;
  temp3 = f(temp1);
  if (sel)
     temp4 = temp3;
  else
     temp4 = temp2;

  real_out <= temp4;
end

 

если использовать в других блоках real_out - будет все гарантировано однозначно. А вот если temp4... Как судьба распорядится :)

 

Я лично с синопсисом тут полностью согласен.

И я тоже согласен с вами и синопсисом. По сути такой код эквивалентен:

always @* begin
  temp1 = .....;
  temp2 = ....;
  temp3 = f(temp1);
  if (sel)
     temp4 = temp3;
  else
     temp4 = temp2;
end

always @(posedge clk) 
    real_out <= temp4;

Эта схема безопасна априори. Вам не нравится, я помню. Я тоже не люблю размазывать код лишний раз и применяю такую схему только когда код большой и развесистый. Если втаскивать комбинационную логику в регистровый блок, то имхо, надо соблюдать определенные правила. Главное из которых - все переменные этой комбинационной логики должны быть локальными по отношению к блоку, в котором они используются. Для обеспечения этого имеет смысл и объявлять их прямо внутри блока:

 

always @(posedge clk) begin : slon

    reg a;
    reg b;

    a = x;
    b = f(a, y);

    ...

end

тогда гарантировано наружу эти локальные переменные не попадут.

 

А если заменить на <= , то все станет однозначно? Да то же самое и будет. Ну и дальнейшие ваши выводы, как я думаю, неверные.

:) Дальнейшие выводы, скорее всего, верные. Да, мы тут пришли к тому, с чего и началась дискуссия вокруг присваиваний в комбинационных/регистровых блоках - что блокирующие присваивания органично подходят для комбинационных блоков, а неблокирующие - для регистровых. И соблюдение этого простого правила гарантирует от неоднозначностей. Но, как обычно, есть нюансы, :) соблюдение которых тоже гарантирует корректность.

 

Можно ездить на красный свет и не иметь негативных последствий, если: а) на перекрестке и вблизи него нет пешеходов и других автомобилей; б) вблизи перекреста отсутствуют ИДПС и/или камеры фиксации нарушений ПДД. Вот если аккуратно соблюдать эти правила, то ничего негативного не произойдет. Но можно просто не ездить на красный свет - это проще соблюдать. Хотя иногда (когда торопишься в аэропорт ночью) бывает разумнее не стоять и не терять время перед пустым перекрестком, на котором забыли выключить на ночь светофор. Но при этом ни на секунду нельзя забывать о вышеописанных пунктах а и б. В общем, тут каждый для себя решает сам - ответственность его. Надеюсь, аналогия адекватная.

 

И я вполне признаю, что писал раньше неоднократно такой код, с потенциальными гонками... Больше не буду, буду блокирующие использовать только для переменных, используемых только в пределах одного блока begin..end.

:cheers:

Я вижу, мы все тут приподняли меру понимания. И хотя ответа на письмо я пока не получил, посты №393 и №394, а также внимательное чтение и осмысление пунктов Стандарта 11.4.1 Determinism и 11.4.2 Nondeterminism привели меня к мнению, что гарантируется только порядок внутри последовательного блока и больше ничего, вплоть до того, что сами процессы присваиваний могут прерываться другими процессами из других блоков. Отсюда окончательный вывод, к которому вы сами пришли: блокирующие присваивания в регистровых блоках безопасно использовать только для присваивания значений переменным, используемым внутри этого блока - по сути локальным переменным.

 

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

 

P.S. Ответа на письмо буду ждать, но кажется, что я уже знаю, каков он будет. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В сообщениях 397...402 речь шла о том, как обойтись одними неблокирующими присваиваниями в операторе for. Естественно, речь должна идти не о переменной цикла. Это шутка такая. Я еще хотел написать что-то вроде: "А для for(i=0; i<=10;i++) не обойтись без присваиваний обоих типов?". Зачем придумывать казуистические примеры? assign n =... - того же вида. Шутка! :)

Я не собираюсь использовать только = или только <=. Я говорил, что это можно делать, если захотеть. А также, я говорил, что два вида присваиваний призваны облегчить жизнь писателю. В том числе, и избежать гонок "малой кровью".

По поводу одинакового поведения = и <= в конкурирующих блоках - давайте проверим. На симуляторе, на компиляторе.

А насчет SystemC - кто знает, может в следующей версии Quartus будет его поддерживать. Я вчера полез сам почитать, скачал стандарт. Документ не хуже того, который здесь горячо цитируется.

Изменено пользователем ViKo

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По поводу одинакового поведения = и <= в конкурирующих блоках - давайте проверим. На симуляторе, на компиляторе.

Уже все, вроде, проверили. Что именно еще вы хотите проверить?

 

А насчет SystemC - кто знает, может в следующей версии Quartus будет его поддерживать.

В следующей точно не будет. И послеследующей тоже. :(

 

Я вчера полез сам почитать, скачал стандарт. Документ не хуже того, который здесь горячо цитируется.

SystemC - это не новый язык, на самом деле. И не вчерашнее изобретение, ему уж скоро десяток лет (если не уже). SystemC - это ЯП С++ + библиотека поддержки параллельного описания + методология использования всего этого хозяйства. Дело за "малым" - где синтезаторы?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Насчет = и <= в двух блоках - пока не все изучил, позже выскажусь. Если что - признаю что не прав. Не знаю. Читаю.

Насчет цикла for - в пункте 9.6 нет упоминания ни блокирующих, ни неблокирующих присваиваний. И не должно быть. Как справедливо заметил SM, что захочу, то и поставлю. Так ведь я именно об этом и говорил! Опять все наизнанку вывернуто.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно ездить на красный свет и не иметь негативных последствий, если: а) на перекрестке и вблизи него нет пешеходов и других автомобилей; б) вблизи перекреста отсутствуют ИДПС и/или камеры фиксации нарушений ПДД. Вот если аккуратно соблюдать эти правила, то ничего негативного не произойдет. Но можно просто не ездить на красный свет - это проще соблюдать

 

:bb-offtopic:

По мне - вот наглядное подтверждение тому, как одним неосторожным сравнением можно перечеркнуть желание следовать по пути Ваших интелектуальных высказываний. (Если правила нарушаете, значит и требование стандартов тоже).

Ведь если нельзя, но очень хочется, то можно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Насчет цикла for - в пункте 9.6 нет упоминания ни блокирующих, ни неблокирующих присваиваний. И не должно быть. Как справедливо заметил SM, что захочу, то и поставлю.

Да, как напишете, такое присваивание и будет. В примере, который вы приводили for(i=0; i<n; i++), есть два присваивания (i=0 и i++ (разворачивается в i = i + 1)) и оба блокирующие.

 

:bb-offtopic:

По мне - вот наглядное подтверждение тому, как одним неосторожным сравнением можно перечеркнуть желание следовать по пути Ваших интелектуальных высказываний. (Если правила нарушаете, значит и требование стандартов тоже).

Ведь если нельзя, но очень хочется, то можно.

Я правила (ПДД) стараюсь не нарушать (хотя это не удается в части следования скоростному режиму, и не думаю, что это кому-то удается)... Хм, вижу, что аналогию привел неадекватную, извините: действительно, в одном случае - использование блокирующих присваиваний к локальным переменным блока - нарушений нет, в другом - езда на красный свет - нарушение есть по-любому. Я хотел лишь подчеркнуть меру ответственности...

 

Хорошо, перефразирую аналогию: желательно всегда ездить по главной дороге и избегать поворотов налево. Но если удобнее в том или ином случае проехать по второстепенной (с последующим выездом на главную) или повернуть налево, то... особая внимательность + четкое знание правил проезда нерегулируемых перекрестков + четкое им следование. Т.к. действие потенциально опасное, то особое внимание + понимание последствий. Так пойдет?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, как напишете, такое присваивание и будет. В примере, который вы приводили for(i=0; i<n; i++), есть два присваивания (i=0 и i++ (разворачивается в i = i + 1)) и оба блокирующие.

Это просто переменная цикла, не относящаяся к переменным, которым присваивается значение (внутри цикла, внутри блока). Речь должна идти не о ней.

На всякий случай спрошу - разве я могу присвоить что-то i внутри цикла?

Изменено пользователем ViKo

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это просто переменная цикла, не относящаяся к переменным, которым присваивается значение (внутри цикла, внутри блока). Речь должна идти не о ней.

Понятно. Только "переменная цикла" это обыкновенная переменная, никакими особыми привилегиями она в данном случае не пользуется.

 

На всякий случай спрошу - разве я могу присвоить что-то i внутри цикла?

А почему нет:

for(int i = 0; i < 10; i++) begin 
    if(i == 2) begin              
        i = 4;                    
    end                           
    a[i] = ...;                                                     
end

Тут мы [сознательно] пропустили два индекса.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По поводу for - уже и не знаю... :unsure:

По поводу <= в конкурирующих блоках - признаюсь, был неправ!

В доказательство привожу файл, стр. 10

Эх, надо было раньше в него заглянуть :) Я ж учил :)

1996_CUG_presentation_nonblocking_assigns.pdf

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

<offtopic>По С++ уточню: С++ позволяет писать и в процедурном стиле, как С, и в объектом, и в ООП. С++ - не ОО язык, ООП - это один лишь из аспектов С++.</offtopic> :)

В курсе.  :) Я имел в виду, что если использовать в С++ только его "подмножество" - язык С, то можно С++ и не использовать. 

 

 

 

 

Это только потому, что пока нет распространенных и доступных синтезаторов с языков более высокого уровня, чем HDL. Вот представьте, что вы пишете код типа:

...

указываете констрейн по скорости (с какой частотой должно выплевывать значения), и синтезатор сам под целевое "железо" родит конвейер, побьет код на такты, наведет синхронизацию по событиям и т.д. При этом вам не надо париться с тактами, заводить кучу промежуточных низкоуровневых переменных - синтезатор сам все это сделает. А вы можете сосредоточиться на целевой задаче. По сути это уход с уровня ассемблера на уровнь языка вроде С/Паскаль.

 

Разве создание такого синтезатора - не достойная цель? Имхо, очень достойная.

 

Высокоуровневый синтез (если все будет удобно, правильно и красиво) - вещь, конечно, хорошая. Я и не спорю.  :)

 

Просто я не назвал бы то, что пытается делать Leka, "высокоуровневым синтезом".

 

Это как из C пробовать самому сделать C++ посредством `defin'ов.  :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...