dxp 58 21 марта, 2010 Опубликовано 21 марта, 2010 · Жалоба module tst( output reg q1, q2); reg d; wire q = d; always@* begin d = 1; q1 <= q; d = 0; q2 <= q; end endmodule q1=? Почему? У вас d не инициализирован. При первой "сработке" always-блока d присваивается 1, но q1 значение присвается с помощью неблокирующего присваивания (и значение это равно q, которое всегда имеет значение d), поэтому q1 имеет значение d, не дожидаясь пока в d будет записана 1. А поскольку значение d исходно неизвестно (неинициализированый регистр), то поэтому и ?. Использовать в "комбинационных" блоках неблокирующие присваивания - моветон и источник неприятных ошибок. Как и использование блокирующих присваиваний в "регистровых" (с posedge/negedge) блоках. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 21 марта, 2010 Опубликовано 21 марта, 2010 · Жалоба Скажите, а есть ли способ не подсчитывать вручную количество ячеек в массиве для строки "Hello, world"? А так, чтоб само посчитало и завело массив нужного размера. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 0 21 марта, 2010 Опубликовано 21 марта, 2010 · Жалоба Под "q1=?" имел в виду не "q = don't care", а вопрос "чему равно q1 ?": В ISE и Квартусе - q1=0, в Icarus Verilog - q1=1. На форуме ixbt уже ответили: bvt: "Любое из двух - правильное. Assign-ы, блокирующие присваивания и правые части неблокирующих присваиваний выполняются Верилогом в одной общей очереди, при этом очередность гарантируется лишь для последовательных инструкций одного блока, т.е. присвоится новое значение переменной q один раз после выполниния всех инструкций always@*-блока, или несколько присвоений ей будут перемешаны с инструкциями этого блока, как я понимаю, явно не определено и реализационно зависимо. То самое пресловутое Verilog race condition." Использовать в "комбинационных" блоках неблокирующие присваивания - моветон и источник неприятных ошибок. Не согласен, если в обсуждаемом примере заменить "<=" на "=" - неопределенность останется. Лично я сформулировал для себя правило: не использовать результат блокирующего присваивания вне данного always-блока. И везде использовать по-возможности только неблокирующие присваивания (это правило и в инете находится по "Verilog race condition"). Как и использование блокирующих присваиваний в "регистровых" (с posedge/negedge) блоках. М/б вынужденный случай. И тут, имхо, д/б правило "не использовать результат блокирующего присваивания вне данного always-блока". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 21 марта, 2010 Опубликовано 21 марта, 2010 · Жалоба Не согласен, если в обсуждаемом примере заменить "<=" на "=" - неопределенность останется. Лично я сформулировал для себя правило: не использовать результат блокирующего присваивания вне данного always-блока. И везде использовать по-возможности только неблокирующие присваивания (это правило и в инете находится по "Verilog race condition"). Не стоит смешивать в одном блоке блокирующие и неблокирующие присваивания, особенно, если в них участвуют те же переменные. А результат можно использовать где угодно, и как угодно. Если заменить у Вас <= на =, результат будет однозначным, определяемым последовательным выполнением операторов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 0 21 марта, 2010 Опубликовано 21 марта, 2010 (изменено) · Жалоба module tst( output reg [7:0] c, input clk ); function [9:0] msb; input [1023:0] str; integer i; begin msb = 0; for (i=0; i<2048; i=i+1) if (str[i] != 0) msb = i; end endfunction localparam str = "Hello,world "; localparam len = (msb(str)+7)/8; localparam adr = msb(len); reg [adr:0] pos = len; always@(posedge clk) begin if( pos > 0 ) pos <= pos - 1; q <= str[pos*8 +: 8]; end endmodule Про "<=" и "=" - не сейчас, cначала хочу на задачке "N-ферзей" опробовать новую методику. В коде надо "с" --> "q" Изменено 21 марта, 2010 пользователем Leka Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 58 22 марта, 2010 Опубликовано 22 марта, 2010 · Жалоба Не согласен, если в обсуждаемом примере заменить "<=" на "=" - неопределенность останется. То, что у вас тут ошибка комплексная (гонки), не отменяет того, что блокирующие присваивания по смыслу больше подходят комбинационным блокам, а неблокирующие - регистровым. Нарушение этого простого правила чревато ошибками. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SM 0 22 марта, 2010 Опубликовано 22 марта, 2010 · Жалоба что блокирующие присваивания по смыслу больше подходят комбинационным блокам, а неблокирующие - регистровым. Нарушение этого простого правила чревато ошибками. IMHO это совсем не правило. Блокирующие/неблокирующие ни для чего "больше не подходят", а выбираются для решения того или иного типа задач именно по смыслу задачи. И никак не связаны с тем, решается ли данная задача комбинаторно или с регистром на выходе. Например приоритетный кодер источника прерываний процессора, не зависимо от того, регистровый он или нет, удобно описать блокирующими, так как результат каждой предыдущей итерации рассмотрения/проверки источника влияет на следующий. А какое нибудь там АЛУ - неблокирующим, так как в нем совершенно плоская одноуровневая логика перед комбинаторным выходом или выходным регистром. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 58 22 марта, 2010 Опубликовано 22 марта, 2010 · Жалоба IMHO это совсем не правило. Блокирующие/неблокирующие ни для чего "больше не подходят", а выбираются для решения того или иного типа задач именно по смыслу задачи. И никак не связаны с тем, решается ли данная задача комбинаторно или с регистром на выходе. Вот именно, что по смыслу. И смысл, например, в always @(posedge ...) в том, что значения всех правых частей выражений блока вычисляются в момент аргумента posedge, поэтому пиши блокирующие, не пиши, ничего они не дадут, кроме возможных ошибок. Классический пример: reg a; reg b; always @(posdege clk) begin ... a = b; b = a; end На выходе будет фигня, и синтезатор в данном случае про это выдает предупреждение (а случаи бывают более сложными). Совсем другое дело с неблокирующими. Применение же блокирующих присваиваний в комбинационных блоках очень хорошо "ложится" именно на комбинационную сущность логики блока, где важно задать именно последовательность передачи сигналов, и неблокирующие присваивания, позволяя "прыгать" внутрь описания последовательности сигналов, нарушают логичность описания. Это не я придумал, эти вещи неоднократно попадались в разных книжках, где прямо такие рекомендации и давались: не хотите проблем - избегайте использования блокирующих присваиваний в "регистровых" блоках, а неблокирующих - в "комбинационных". Писать можно как угодно, только при этом каждый сам себе злобный буратина. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 22 марта, 2010 Опубликовано 22 марта, 2010 · Жалоба На выходе будет фигня... Не обязательно. Например, можно описать сдвиговый регистр следующим образом: always @ posedge CLK begin d = c; c = b; b = a; a = IN; end И скомпилируется абсолютно в то же, что и при неблокирующих присваиваниях. Только думать над кодом придется дольше. И смысла - никакого. А в остальном - полностью поддерживаю. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 58 22 марта, 2010 Опубликовано 22 марта, 2010 · Жалоба Не обязательно. Цитированная вами фраза относилась конкретно к приведенному мною примеру. Там будет фигня, а не обмен значениями регистров. Ваш пример дает правильное по смыслу описание, только как вы сами и сказали, смысла в использовании блокирующих присваиваний никакого нет, а тенденция к запутыванию кода есть. И когда код не такой простой, то эта тенденция может стать уже проблемой. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SM 0 22 марта, 2010 Опубликовано 22 марта, 2010 · Жалоба Вот именно, что по смыслу. И смысл, например, в always @(posedge ...) в том, что значения всех правых частей выражений блока вычисляются в момент аргумента posedge, поэтому пиши блокирующие, не пиши, ничего они не дадут, кроме возможных ошибок. Вы привели пример, удобный для Вас, и не более того... А вот другой пример. Упомянутый мной контроллер прерываний, т.е. его кусок: always @(posedge clk) if (reset) intrq = 1'b0; else if (!intrq || int_completed) begin prio = 2'b00; intrq = 1'b0; intvec = 5'hxx; t0_iack = 1'b0; t1_iack = 1'b0; t2_iack = 1'b0; uart_iack = 1'b0; if (t2_irq && (t2_ip > prio)) begin prio = t2_ip; intvec = t2_vec; intrq = 1'b1; t2_iack = intack; end if (t1_irq && (t1_ip > prio)) begin prio = t1_ip; intvec = t1_vec; intrq = 1'b1; t1_iack = intack; t2_iack = 1'b0; end if (t0_irq && (t0_ip > prio)) begin prio = t0_ip; intvec = t0_vec; intrq = 1'b1; t0_iack = intack; t1_iack = 1'b0; t2_iack = 1'b0; end if (uart_irq && (uart_ip > prio)) begin prio = uart_ip; intvec = uart_vec; intrq = 1'b1; t0_iack = 1'b0; t1_iack = 1'b0; t2_iack = 1'b0; uart_iack = intack; end end Очень даже удобное применение блокирующего присваивания внутри регистрового always. Извините, но никак не вижу связи с комбинаторностью. Еще у меня есть пример куска делителя, делящего 16/8 бит за 1 такт, и 16/16 за два - там тоже регистровый always, и тоже блокирующее присваивание, но уже в цикле for. Посмотрим, во что это выльется, если использовать неблокирующие..... always @(posedge clk) begin temp = cycle ? {temp[15:0], int_num[7] & !(en_frct)} : (en_frct ? {int_num, 1'b0} : {16'h0000,int_num[m16?15:7]}); for (i=0; i<8; i = i+1'b1) begin temp1 = temp - int_den; out[7-i] = !temp1[17]; if (i != 7) temp = {(temp1[17] ? temp[15:0] : temp1[15:0]), int_num[(cycle | !m16) ? (6-i) : (14-i)] & !(en_frct)}; else temp = {1'b0, (temp1[17] ? temp[15:0] : temp1[15:0])}; end end т.е. по какому набору евентов запускается кусок схемы, описанный блоком always (хоть *, хоть posedge clk, хоть еще что там) - вещь никак не связанная с логикой, внутри блока описанной, и тем, какие там присваивания более эффективны. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 58 22 марта, 2010 Опубликовано 22 марта, 2010 · Жалоба Вы привели пример, удобный для Вас, и не более того... Я привел пример, показывающий логическое несоответствие блокирующего присваивания. Если вы не поняли, объясню еще раз. Блокирующее присваивание в силу блокирования последующих выражений органично описывает комбинационную логику - т.е. последовательность соединений, когда надо четко и однозначно задать какой элемент идет за каким в цепочке сигнала. А в регистровом блоке идет запись по фронту события в регистры блока. Одновременно. Никакой последовательности тут задаваться не может - правые части выражений вычисляются в момент фронта события. Поэтому тут органично подходит неблокирующее присваивание - его поведение отражает "физику" процесса. А блокирующее присваивание в регистровом блоке притянуто за уши - описывать-то можно, только для получения правильно работающего описания надо внимательно следить за порядком следования выражений, если между ними имеются перекрестные связи. А вот другой пример. Упомянутый мной контроллер прерываний, т.е. его кусок: И что будет, если тут использовать как положено неблокирующие присваивания? Что поменяется? В чем смысл и преимущество в использовании тут блокирующих? В чем их недостатки в регистровых блоках, и так понятно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SM 0 22 марта, 2010 Опубликовано 22 марта, 2010 · Жалоба И что будет, если тут использовать как положено неблокирующие присваивания? Что поменяется? В чем смысл и преимущество в использовании тут блокирующих? А Вы в код гляньте, только внимательнее, проследив работу с переменной prio. И сами все поймете. Вообще не ожидал такого ошеломляющего вопроса (наверное результат комплекса вредности блокирующих присваиваний в регистровых блоках). Для остальных переменных, действительно, не важен тип присваивания, стоит блокирующий только чтобы варнинг синтезатора о том, что в одном always и такие и сякие в перемешку, убить... Еще раз - никакой связи между типом рекомендуемого присваивания и регистровостью блока нет и быть не может, потому как та самая, цитирую, "последовательность cоединений, когда надо четко и однозначно задать какой элемент идет за каким в цепочке сигнала", одинаково важна и в случае, если она оканчивается регистром, и в случае, если она им не оканчивается. Никакой последовательности тут задаваться не может - правые части выражений вычисляются в момент фронта события. В корне не верно. Последовательность тут задаваться может, и должна, так как перед тем, как сигнал в конце всего того, что описано блоком, защелкнется в регистр, он может пройти сквозь сколь угодно сложную логику и арифметику, как в моем простом примере с prio, и как в более сложном с делителем. И что я там должен увидеть? Что prio последовательно обрабатывается в if-блоках? Да, что значение prio, проверяемое в каждом последующим сравнении может быть обновлено в случае прохождения проверки в предыдущем. Если заменить блокирующее присваивание неблокирующим, то блок перестанет работать, так как в проверках условия станет производится сравнение с тем, что хранится в prio с предыдущего такта, вместо "промежуточного результата" от предыдущего условного блока. И потеряется та самая последовательность действий, которую должен пройти сигнал, прежде чем быть записан в регистр. куда сообщение пропало, на который я этот ответ писал ??! не хорошо... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 58 23 марта, 2010 Опубликовано 23 марта, 2010 · Жалоба А Вы в код гляньте, только внимательнее, проследив работу с переменной prio. Да, посмотрел внимательнее. Не знаю целевой логики работы этого узла, но вполне очевидно, что все условия в if-ах известны на этапе проектирования. И код мог иметь, например, такой вид: always @(posedge clk) if (reset) intrq = 1'b0; else if (!intrq || int_completed) begin prio <= 2'b00; ... if (t2_irq && (t2_ip > prio)) begin prio <= t2_ip; ... end if (t1_irq && (t1_ip > t2_ip)) begin prio <= t1_ip; ... end if (t0_irq && (t0_ip > t1_ip)) begin prio <= t0_ip; ... end if (uart_irq && (uart_ip > t0_ip)) begin prio <= uart_ip; ... end end Этот вариант куда прозрачнее, в нем сразу видно, что в условии, а в вашем надо заниматься дедукцией при анализе условия в каждом if-операторе - с такого стиля и начинается обычно то, что потом называют spaghetti code. Я написал "например", потому что не знаю, что такое эти tx_ip, и как они меж собой связаны, и вообще, что конкретно делает этот узел, какие входные сигналы, выходные и т.п. Поэтмому, возможно, предложенный выше вариант в чем-то не соответствует замыслу. Но нет никаких сомнений, что все это легко описывается с помощью неблокирующих присваиваний и имеет прозрачный вид. Да, что значение prio, проверяемое в каждом последующим сравнении может быть обновлено в случае прохождения проверки в предыдущем. Если заменить блокирующее присваивание неблокирующим, то блок перестанет работать, так как в проверках условия станет производится сравнение с тем, что хранится в prio с предыдущего такта, вместо "промежуточного результата" от предыдущего условного блока. И потеряется та самая последовательность действий, которую должен пройти сигнал, прежде чем быть записан в регистр. Ваш код, если угодно, красиво, логично и безопасно описывается следующим образом: always @* begin next_prio = 2'b00; if (t2_irq && (t2_ip > next_prio)) begin next_prio = t2_ip; ... end if (t1_irq && (t1_ip > next_prio)) begin next_prio = t1_ip; ... end if (t0_irq && (t0_ip > next_prio)) begin next_prio = t0_ip; ... end if (uart_irq && (uart_ip > next_prio)) begin next_prio = uart_ip; ... end end always @(posedge clk) begin prio <= next_prio; end Этот код функционально эквивалентен вашему. И вы просто втащили комбинационный блок в регистровый. И вам это сошло без негативных последствий только потому, что у вас prio и все остальные без исключения регистры не присутствовали в правой части присваиваний. Добавьте такое выражение и все может посыпаться (и хорошо, если синтезатор обнаружит это и сообщит). Именно поэтому этот стиль и плох, именно поэтому и существуют рекомендации по использованию присваиваний. куда сообщение пропало, на который я этот ответ писал ??! не хорошо... Сообщение я отправил, но прочитав написанное, понял, что не на ту тему, а поскольку было уже поздно и я уходил домой, то времени переписывать не было, и решил ответить на следующий день более соответствующе и развернуто. Сообщение сразу удалил оно висело не более полуминуты, но вы успели его ухватить. Вы что, мониторите форум с интервалом 15 секунд? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SM 0 23 марта, 2010 Опубликовано 23 марта, 2010 · Жалоба И вы просто втащили комбинационный блок в регистровый. И вам это сошло без негативных последствий только потому, что у вас prio и все остальные без исключения регистры не присутствовали в правой части присваиваний. Добавьте такое выражение и все может посыпаться (и хорошо, если синтезатор обнаружит это и сообщит). Именно поэтому этот стиль и плох, именно поэтому и существуют рекомендации по использованию присваиваний. Это лишь Ваше IMHO, что такой стиль плох. Лично меня запутывает, когда есть лишние always, которых могло бы и не быть. Краткость => минимум лишних слов и действий => понятность и простота. И все средства языка хороши для того, чтобы добиться краткости записи и ликвидаци лишних сущностей. Что касается неприсутствия в правой части - вернитесь к примеру с делителем - там это присутствие абсолютно полное. Я же говорил - что это просто более простой пример. И мне всегда "сходит с рук" применение любого типа присваивания, так как я просто умею ими пользоваться и знаю, где и какое мне позволит сэкономить какое-то количество писанины в исходнике, следовательно упростить его. Вредость того или иного типа присваивания там или тут - лишь комплекс, и ничего более. Ваш первый вариант неверен, так как prio меняется только если есть соответутвующий ему irq. Я же написал - это контроллер прерываний с приоритетами. Прерывание вызывает тот блок, от которого есть *_irq и чей *_ip (приоритет конкретного блока - тут трех таймеров и уарта) выше. Если *_irq не было, то и сравниваться/меняться с его *_ip ничего не должно. Ваш второй вариант абсолютно правилен, но он не красив и запутан наличием лишнго блока, которого могло бы не быть. Чтобы понять сущность описания в Вашей записи надо прочитать два блока и мысленно их объединить, что вызывает некоторое торможение при чтении такого кода. Вы что, мониторите форум с интервалом 15 секунд? нет, это чисто вероятностное событие. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться