ViKo 1 27 марта, 2010 Опубликовано 27 марта, 2010 (изменено) · Жалоба to Leka То, к чему тянется ваша душа, имеется в природе под названием SystemC. Я, правда, кроме названия, ничего про него не знаю. Советую обратить внимание. to SM Извиняюсь, поздно откликнулся. Кстати... Вот очень простой и яркий пример неоднозначности из синопсисовских док. always @(posedge clk) a=b; always @(posedge clk) b=a; ... А если заменить на <= , то все станет однозначно? Да то же самое и будет. Ну и дальнейшие ваши выводы, как я думаю, неверные. Изменено 27 марта, 2010 пользователем ViKo Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Des333 0 27 марта, 2010 Опубликовано 27 марта, 2010 · Жалоба ... Да то же самое и будет. Ну и дальнейшие ваши выводы, как я думаю, неверные. А почему Вы так решили? Вы проверяли? Какой пример, какие результаты? Или Вы где-то прочитали? Где? Стандарт? Какой пункт? Давайте не будем писать просто то, что пришло в голову. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 27 марта, 2010 Опубликовано 27 марта, 2010 · Жалоба А почему Вы так решили? Вы проверяли? Какой пример, какие результаты? Или Вы где-то прочитали? Где? Стандарт? Какой пункт? Давайте не будем писать просто то, что пришло в голову. Потому что обновление переменных a и b будет происходить одинаково по времени и для =, и для <=. Ведь в приведенных блоках никаких других операторов нет. Задержек нет. Появился clk, изменились a и b. В самом блоке, в момент clk, или при выходе из блока в тот же момент clk. Согласны? Ну а дальше, как сказал... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Des333 0 27 марта, 2010 Опубликовано 27 марта, 2010 · Жалоба ... Согласны? ... Не согласен. Прочитайте в стандарте. Посмотрите в симуляторе. Убедитесь, что Вы не правы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SM 0 28 марта, 2010 Опубликовано 28 марта, 2010 · Жалоба А если заменить на <= , то все станет однозначно? Да то же самое и будет. Ну и дальнейшие ваши выводы, как я думаю, неверные. Да, все станет однозначно, и синопсис это прямо и недвусмысленно пишет. Читайте документацию и стандарт. Разница в том, что блокирующие вычисляются в один этап, во время вычисления всех 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", а не сразу присваивает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 58 28 марта, 2010 Опубликовано 28 марта, 2010 · Жалоба С `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. Ответа на письмо буду ждать, но кажется, что я уже знаю, каков он будет. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 28 марта, 2010 Опубликовано 28 марта, 2010 (изменено) · Жалоба В сообщениях 397...402 речь шла о том, как обойтись одними неблокирующими присваиваниями в операторе for. Естественно, речь должна идти не о переменной цикла. Это шутка такая. Я еще хотел написать что-то вроде: "А для for(i=0; i<=10;i++) не обойтись без присваиваний обоих типов?". Зачем придумывать казуистические примеры? assign n =... - того же вида. Шутка! :) Я не собираюсь использовать только = или только <=. Я говорил, что это можно делать, если захотеть. А также, я говорил, что два вида присваиваний призваны облегчить жизнь писателю. В том числе, и избежать гонок "малой кровью". По поводу одинакового поведения = и <= в конкурирующих блоках - давайте проверим. На симуляторе, на компиляторе. А насчет SystemC - кто знает, может в следующей версии Quartus будет его поддерживать. Я вчера полез сам почитать, скачал стандарт. Документ не хуже того, который здесь горячо цитируется. Изменено 28 марта, 2010 пользователем ViKo Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 58 28 марта, 2010 Опубликовано 28 марта, 2010 · Жалоба По поводу одинакового поведения = и <= в конкурирующих блоках - давайте проверим. На симуляторе, на компиляторе. Уже все, вроде, проверили. Что именно еще вы хотите проверить? А насчет SystemC - кто знает, может в следующей версии Quartus будет его поддерживать. В следующей точно не будет. И послеследующей тоже. :( Я вчера полез сам почитать, скачал стандарт. Документ не хуже того, который здесь горячо цитируется. SystemC - это не новый язык, на самом деле. И не вчерашнее изобретение, ему уж скоро десяток лет (если не уже). SystemC - это ЯП С++ + библиотека поддержки параллельного описания + методология использования всего этого хозяйства. Дело за "малым" - где синтезаторы? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 28 марта, 2010 Опубликовано 28 марта, 2010 · Жалоба Насчет = и <= в двух блоках - пока не все изучил, позже выскажусь. Если что - признаю что не прав. Не знаю. Читаю. Насчет цикла for - в пункте 9.6 нет упоминания ни блокирующих, ни неблокирующих присваиваний. И не должно быть. Как справедливо заметил SM, что захочу, то и поставлю. Так ведь я именно об этом и говорил! Опять все наизнанку вывернуто. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sazh 8 28 марта, 2010 Опубликовано 28 марта, 2010 · Жалоба Можно ездить на красный свет и не иметь негативных последствий, если: а) на перекрестке и вблизи него нет пешеходов и других автомобилей; б) вблизи перекреста отсутствуют ИДПС и/или камеры фиксации нарушений ПДД. Вот если аккуратно соблюдать эти правила, то ничего негативного не произойдет. Но можно просто не ездить на красный свет - это проще соблюдать :bb-offtopic: По мне - вот наглядное подтверждение тому, как одним неосторожным сравнением можно перечеркнуть желание следовать по пути Ваших интелектуальных высказываний. (Если правила нарушаете, значит и требование стандартов тоже). Ведь если нельзя, но очень хочется, то можно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 58 28 марта, 2010 Опубликовано 28 марта, 2010 · Жалоба Насчет цикла for - в пункте 9.6 нет упоминания ни блокирующих, ни неблокирующих присваиваний. И не должно быть. Как справедливо заметил SM, что захочу, то и поставлю. Да, как напишете, такое присваивание и будет. В примере, который вы приводили for(i=0; i<n; i++), есть два присваивания (i=0 и i++ (разворачивается в i = i + 1)) и оба блокирующие. :bb-offtopic: По мне - вот наглядное подтверждение тому, как одним неосторожным сравнением можно перечеркнуть желание следовать по пути Ваших интелектуальных высказываний. (Если правила нарушаете, значит и требование стандартов тоже). Ведь если нельзя, но очень хочется, то можно. Я правила (ПДД) стараюсь не нарушать (хотя это не удается в части следования скоростному режиму, и не думаю, что это кому-то удается)... Хм, вижу, что аналогию привел неадекватную, извините: действительно, в одном случае - использование блокирующих присваиваний к локальным переменным блока - нарушений нет, в другом - езда на красный свет - нарушение есть по-любому. Я хотел лишь подчеркнуть меру ответственности... Хорошо, перефразирую аналогию: желательно всегда ездить по главной дороге и избегать поворотов налево. Но если удобнее в том или ином случае проехать по второстепенной (с последующим выездом на главную) или повернуть налево, то... особая внимательность + четкое знание правил проезда нерегулируемых перекрестков + четкое им следование. Т.к. действие потенциально опасное, то особое внимание + понимание последствий. Так пойдет? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 28 марта, 2010 Опубликовано 28 марта, 2010 (изменено) · Жалоба Да, как напишете, такое присваивание и будет. В примере, который вы приводили for(i=0; i<n; i++), есть два присваивания (i=0 и i++ (разворачивается в i = i + 1)) и оба блокирующие. Это просто переменная цикла, не относящаяся к переменным, которым присваивается значение (внутри цикла, внутри блока). Речь должна идти не о ней. На всякий случай спрошу - разве я могу присвоить что-то i внутри цикла? Изменено 28 марта, 2010 пользователем ViKo Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 58 28 марта, 2010 Опубликовано 28 марта, 2010 · Жалоба Это просто переменная цикла, не относящаяся к переменным, которым присваивается значение (внутри цикла, внутри блока). Речь должна идти не о ней. Понятно. Только "переменная цикла" это обыкновенная переменная, никакими особыми привилегиями она в данном случае не пользуется. На всякий случай спрошу - разве я могу присвоить что-то i внутри цикла? А почему нет: for(int i = 0; i < 10; i++) begin if(i == 2) begin i = 4; end a[i] = ...; end Тут мы [сознательно] пропустили два индекса. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 28 марта, 2010 Опубликовано 28 марта, 2010 · Жалоба По поводу for - уже и не знаю... :unsure: По поводу <= в конкурирующих блоках - признаюсь, был неправ! В доказательство привожу файл, стр. 10 Эх, надо было раньше в него заглянуть :) Я ж учил :) 1996_CUG_presentation_nonblocking_assigns.pdf Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Des333 0 28 марта, 2010 Опубликовано 28 марта, 2010 · Жалоба <offtopic>По С++ уточню: С++ позволяет писать и в процедурном стиле, как С, и в объектом, и в ООП. С++ - не ОО язык, ООП - это один лишь из аспектов С++.</offtopic> :) В курсе. :) Я имел в виду, что если использовать в С++ только его "подмножество" - язык С, то можно С++ и не использовать. Это только потому, что пока нет распространенных и доступных синтезаторов с языков более высокого уровня, чем HDL. Вот представьте, что вы пишете код типа: ... указываете констрейн по скорости (с какой частотой должно выплевывать значения), и синтезатор сам под целевое "железо" родит конвейер, побьет код на такты, наведет синхронизацию по событиям и т.д. При этом вам не надо париться с тактами, заводить кучу промежуточных низкоуровневых переменных - синтезатор сам все это сделает. А вы можете сосредоточиться на целевой задаче. По сути это уход с уровня ассемблера на уровнь языка вроде С/Паскаль. Разве создание такого синтезатора - не достойная цель? Имхо, очень достойная. Высокоуровневый синтез (если все будет удобно, правильно и красиво) - вещь, конечно, хорошая. Я и не спорю. :) Просто я не назвал бы то, что пытается делать Leka, "высокоуровневым синтезом". Это как из C пробовать самому сделать C++ посредством `defin'ов. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться