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

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

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) блоках.

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


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

Скажите, а есть ли способ не подсчитывать вручную количество ячеек в массиве для строки "Hello, world"? А так, чтоб само посчитало и завело массив нужного размера. :)

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


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

Под "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-блока".

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


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

Не согласен, если в обсуждаемом примере заменить "<=" на "=" - неопределенность останется. Лично я сформулировал для себя правило: не использовать результат блокирующего присваивания вне данного always-блока. И везде использовать по-возможности только неблокирующие присваивания (это правило и в инете находится по "Verilog race condition").

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

Если заменить у Вас <= на =, результат будет однозначным, определяемым последовательным выполнением операторов.

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


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

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"

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

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


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

Не согласен, если в обсуждаемом примере заменить "<=" на "=" - неопределенность останется.

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

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


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

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

 

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

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


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

IMHO это совсем не правило. Блокирующие/неблокирующие ни для чего "больше не подходят", а выбираются для решения того или иного типа задач именно по смыслу задачи. И никак не связаны с тем, решается ли данная задача комбинаторно или с регистром на выходе.

Вот именно, что по смыслу. И смысл, например, в always @(posedge ...) в том, что значения всех правых частей выражений блока вычисляются в момент аргумента posedge, поэтому пиши блокирующие, не пиши, ничего они не дадут, кроме возможных ошибок. Классический пример:

 

reg a;
reg b;

always @(posdege clk) begin
    ...
    a = b;
    b = a;
end

 

На выходе будет фигня, и синтезатор в данном случае про это выдает предупреждение (а случаи бывают более сложными). Совсем другое дело с неблокирующими.

 

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

 

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

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


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

На выходе будет фигня...

Не обязательно. Например, можно описать сдвиговый регистр следующим образом:

always @ posedge CLK
begin
d = c;
c = b;
b = a;
a = IN;
end

И скомпилируется абсолютно в то же, что и при неблокирующих присваиваниях. Только думать над кодом придется дольше. И смысла - никакого.

А в остальном - полностью поддерживаю.

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


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

Не обязательно.

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

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


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

Вот именно, что по смыслу. И смысл, например, в 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, хоть еще что там) - вещь никак не связанная с логикой, внутри блока описанной, и тем, какие там присваивания более эффективны.

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


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

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

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

 

 

А вот другой пример. Упомянутый мной контроллер прерываний, т.е. его кусок:

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

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


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

И что будет, если тут использовать как положено неблокирующие присваивания? Что поменяется? В чем смысл и преимущество в использовании тут блокирующих?

 

А Вы в код гляньте, только внимательнее, проследив работу с переменной prio. И сами все поймете. Вообще не ожидал такого ошеломляющего вопроса (наверное результат комплекса вредности блокирующих присваиваний в регистровых блоках). Для остальных переменных, действительно, не важен тип присваивания, стоит блокирующий только чтобы варнинг синтезатора о том, что в одном always и такие и сякие в перемешку, убить...

 

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

 

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

 

В корне не верно. Последовательность тут задаваться может, и должна, так как перед тем, как сигнал в конце всего того, что описано блоком, защелкнется в регистр, он может пройти сквозь сколь угодно сложную логику и арифметику, как в моем простом примере с prio, и как в более сложном с делителем.

 

И что я там должен увидеть? Что prio последовательно обрабатывается в if-блоках?

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

 

куда сообщение пропало, на который я этот ответ писал ??! не хорошо...

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


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

А Вы в код гляньте, только внимательнее, проследив работу с переменной 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 секунд?

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


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

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

Это лишь Ваше IMHO, что такой стиль плох. Лично меня запутывает, когда есть лишние always, которых могло бы и не быть. Краткость => минимум лишних слов и действий => понятность и простота. И все средства языка хороши для того, чтобы добиться краткости записи и ликвидаци лишних сущностей.

 

Что касается неприсутствия в правой части - вернитесь к примеру с делителем - там это присутствие абсолютно полное. Я же говорил - что это просто более простой пример. И мне всегда "сходит с рук" применение любого типа присваивания, так как я просто умею ими пользоваться и знаю, где и какое мне позволит сэкономить какое-то количество писанины в исходнике, следовательно упростить его. Вредость того или иного типа присваивания там или тут - лишь комплекс, и ничего более.

 

Ваш первый вариант неверен, так как prio меняется только если есть соответутвующий ему irq. Я же написал - это контроллер прерываний с приоритетами. Прерывание вызывает тот блок, от которого есть *_irq и чей *_ip (приоритет конкретного блока - тут трех таймеров и уарта) выше. Если *_irq не было, то и сравниваться/меняться с его *_ip ничего не должно. Ваш второй вариант абсолютно правилен, но он не красив и запутан наличием лишнго блока, которого могло бы не быть. Чтобы понять сущность описания в Вашей записи надо прочитать два блока и мысленно их объединить, что вызывает некоторое торможение при чтении такого кода.

 

Вы что, мониторите форум с интервалом 15 секунд?

нет, это чисто вероятностное событие.

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


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

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

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

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

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

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

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

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

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

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