Jump to content

    
Sign in to follow this  
flammmable

Вложенные циклы на Verilog

Recommended Posts

Пытаюсь написать модуль, раcсчитывающий CRC.

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

Для полностью параллельного вычислителя CRC есть некоторое количество генераторов типа этого, однако код жестко привязывается к параметрам CRC (например "CRC-16 modbus").

Я хотел бы написать на чистом Верилоге полностью параметризованный код вычислителя CRC. Для LFSR отлично подходит синтаксис цикла "for":

module main 
#(
parameter LFSR_SIZE     = 16,
parameter START_VALUE   = 'hFFFF,
parameter POLYNOME      = 'h8005)
(
input           clk,    
input           n_reset,    
output reg  [LFSR_SIZE-1:0]lfsr);

integer lfsr_index;

always @(posedge clk) begin
    if(n_reset) begin       
        lfsr[0] <= lfsr[LFSR_SIZE - 1];             
        for(lfsr_index = 1; lfsr_index < LFSR_SIZE; lfsr_index = lfsr_index + 1) begin
            if( ((1 << lfsr_index) & POLYNOME) == 0) begin
                lfsr[lfsr_index] <= lfsr[lfsr_index - 1];                   
            end
            else begin
                lfsr[lfsr_index] <= lfsr[lfsr_index - 1] ^ lfsr[LFSR_SIZE - 1];
            end
        end     
    end
    else begin
        lfsr <= START_VALUE;                
    end
end
endmodule

Однако у меня не получается придумать, как при помощи дополнительного цикла внедрить сдвиг LFSR на какое-либо количество бит.

Подойдет ли здесь вообще конструкция со вложенными циклами? Если нет, то применяются ли где-нибудь вложенные циклы в Verilog?

P.S. Electronix.ru - приличное место, но всё же и здесь могут быть первонахи, которые расскажут, что "цикл в HDL -  это не тоже самое, что в Си" вместо собственно ответа. Так вот. Я осознаю, что циклы в Verilog не выполняются последовательно, а создают нечто, имеющее регулярную, повторяющуюся структуру.

Edited by flammmable

Share this post


Link to post
Share on other sites
7 minutes ago, des00 said:

Это я безусловно прочитал. Но в ваших примерах:
1) полином задается не шестнадцатеричным числом, а несколькими строками кода.
2) используются функции.

Хотелось бы:
1) задавать полином шестнадцатеричным числом.
2) не использовать функции.
2) использовать вложенные циклы.

Share this post


Link to post
Share on other sites
7 minutes ago, flammmable said:

Хотелось бы:
1) задавать полином шестнадцатеричным числом.
2) не использовать функции.
2) использовать вложенные циклы.

ну и в чем проблема тогда, если читали?

1.

crc16x1[0]  = d ^ msb;
crc16x1[5]  = d ^ msb ^ crc[4];
crc16x1[12] = d ^ msb ^ crc[11];

соберите в одну строку

crc16x1 ^= {16{d ^ msb}} & poly[15 : 0];

2,3 разверните функции, пару копипастов и все.

Share this post


Link to post
Share on other sites
1 minute ago, des00 said:

ну и в чем проблема тогда, если читали?

1.


crc16x1[0]  = d ^ msb;
crc16x1[5]  = d ^ msb ^ crc[4];
crc16x1[12] = d ^ msb ^ crc[11];

соберите в одну строку


crc16x1 ^= {16{d ^ msb}} & poly[15 : 0];

2,3 разверните функции, пару копипастов и все.

Проблема в разворачивании функций. Я не могу сообразить, как их развернуть.

Share this post


Link to post
Share on other sites
13 minutes ago, flammmable said:

Проблема в разворачивании функций. Я не могу сообразить, как их развернуть.

эмм, ну начать можно с вариантa в лоб и простого копипаста

  always_ff @(posedge iclk) begin
    logic msb;
    logic [15 : 0] crc16xW;
    logic [15 : 0] crc16x1;

    if (iena) begin
      crc16xW = crc;
      for (int i = 0; i < 16; i++) begin
        msb     = crc16xW [15];
        crc16x1 = (crc16xW << 1);
        crc16x1 ^= {16{d[i] ^ msb}} & poly[15 : 0];
        crc16xW  = crc16x1;
      end
      crc <= crc16xW;
    end
  end

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

Share this post


Link to post
Share on other sites
1 hour ago, flammmable said:

 


always @(posedge clk) begin
    if(n_reset) begin       
        lfsr[0] <= lfsr[LFSR_SIZE - 1];             
        for(lfsr_index = 1; lfsr_index < LFSR_SIZE; lfsr_index = lfsr_index + 1) begin
            if( ((1 << lfsr_index) & POLYNOME) == 0) begin
                lfsr[lfsr_index] <= lfsr[lfsr_index - 1];                   
            end
            else begin
                lfsr[lfsr_index] <= lfsr[lfsr_index - 1] ^ lfsr[LFSR_SIZE - 1];
            end
        end     
    end

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

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

1 hour ago, flammmable said:

Подойдет ли здесь вообще конструкция со вложенными циклами? Если нет, то применяются ли где-нибудь вложенные циклы в Verilog?

И вложенные и циклы под generate, можно всё что угодно, только правильно. И как я сказал ранее - вынесите в функцию. Вы будете удивлены, но функции для HDL и функции в Си имеют намного больше общего, чем различий (за исключением статик-автоматик).

На последок, что такое "Хочу задавать полином шеснадцетеричным числом"? Это типа я программист и мне впадло разбираться? Ну или код для оных. Если очень хочется оставить совместимость, можно накрутить через макросы. Непонятно что за зверёк получится, но вполне вероятно даже будет работать.

Share this post


Link to post
Share on other sites

Приветствую!

17 minutes ago, Nick_K said:

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

Чет то вы уж больно агрессивны категоричны. :sad:  При чем тут состояние  reset?  С точки зрения языка никто не запрещает писать 

always @(posedge clk) begin
  if (reset) bgin
   // reset state
  end
  else begin
   // work state
  end

  if (~reset) bgin
   // work state
  end
  else begin
   // reset state
  end
end
  

Ну да - немного не по фэншую как у классиков, как и вариант 

always @(posedge clk) begin
  // work state
  ...
  if (reset) begin
   // reset state
  end
end

Но чтоб сразу пальцы в дверь ...:cray: Чем же потом код править? 

Удачи! Rob.

Share this post


Link to post
Share on other sites
3 hours ago, des00 said:

эмм, ну начать можно с вариантa в лоб и простого копипаста


  always_ff @(posedge iclk) begin
    logic msb;
    logic [15 : 0] crc16xW;
    logic [15 : 0] crc16x1;

    if (iena) begin
      crc16xW = crc;
      for (int i = 0; i < 16; i++) begin
        msb     = crc16xW [15];
        crc16x1 = (crc16xW << 1);
        crc16x1 ^= {16{d[i] ^ msb}} & poly[15 : 0];
        crc16xW  = crc16x1;
      end
      crc <= crc16xW;
    end
  end

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


crc16x1 ^= {16{d[i] ^ msb}} & poly[15 : 0];

Предположим, что d[] у нас всегда 0 или что его вообще нет.
Тогда:
crc16x1 = crc16x1 ^ (16{msb} & poly[15 : 0]);

Предположим, что msb равен 1
Тогда:
(16{msb} & poly[15 : 0]) равен poly[15 : 0]
и
crc16x1 = crc16x1 ^ poly[15 : 0];

Предположим, что msb равен 0
Тогда:
(16{msb} & poly[15 : 0]) равен 0
и
crc16x1 = crc16x1 ^ 0;

Мммм. Не похоже на обратную связь LFSR.

Кроме того, в чистом Верилоге нет logic-а. Если писать на чистом Верилоге, msb, crc16x1 и crc16xW будут reg или wire?

 

2 hours ago, RobFPGA said:

Чет то вы уж больно агрессивны категоричны. :sad:  При чем тут состояние  reset?  С точки зрения языка никто не запрещает писать 

Мне кажется, он не заметил инверсию ресета (n_reset). Зато возместил недостаток внимательности избытком пафоса ))))

Edited by flammmable

Share this post


Link to post
Share on other sites

Приветствую!

47 minutes ago, flammmable said:

Предположим, что d[] у нас всегда 0 или что его вообще нет.
Тогда:
...

Мммм. Не похоже на LFSR, не?

Если уж считаете в уме то считайте  весь алгоритм а не только серединку - сдвиг в строке чуть выше :  crc16x1 = (crc16xW << 1);

 

Удачи! Rob. 

Share this post


Link to post
Share on other sites
19 minutes ago, RobFPGA said:

Приветствую!

Если уж считаете в уме то считайте  весь алгоритм а не только серединку - сдвиг в строке чуть выше :  crc16x1 = (crc16xW << 1);

 

Удачи! Rob. 

Сдвиг-то есть, а вот обратная связь какая-то уж очень неизбирательная получается.

В любом случае, спасибо des00, я разобрался, как сделать полностью параметризуемый параллельный CRC двумя циклами. Завтра причешу тестбенч и имена переменных (чтобы было не так стыдно) и выложу.

В Моделсиме всё работает. По проверке в железе постараюсь также отписаться, если не забуду.

Share this post


Link to post
Share on other sites
56 minutes ago, flammmable said:

Сдвиг-то есть, а вот обратная связь какая-то уж очень неизбирательная получается.

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

Современные средства синтеза настолько хороши, что можно даже сложный код не разбивать на мелкие сущности, все зависит от алгоритма) 

Share this post


Link to post
Share on other sites
3 hours ago, flammmable said:

Мне кажется, он не заметил инверсию ресета (n_reset). Зато возместил недостаток внимательности избытком пафоса ))))

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

4 hours ago, RobFPGA said:

Ну да - немного не по фэншую как у классиков, как и вариант 


always @(posedge clk) begin
  // work state
  ...
  if (reset) begin
   // reset state
  end
end

Но чтоб сразу пальцы в дверь ...:cray: Чем же потом код править? 

Кстати у меня вот такие конструкции недавно и нагенерили латчей. Точнее там всего один латч был, но провозился я с ним знатно. Дня три наверное

Share this post


Link to post
Share on other sites

Приветствую!

21 minutes ago, Nick_K said:

С Вашим инверсным ресетом, который не ресет, тулу будет сложно определить - это комбинационная схема на входе в ресет или это нормальное состояние

Синтезаторы  уже дано  на такое не обращают внимание. При синхронном ресете  бывает надо еще и постараться (через атрибуты) чтобы  синтезатор использовал выделенный reset регистра, а не комбинировал логику сброса в обычный LUT.

21 minutes ago, Nick_K said:

Кстати у меня вот такие конструкции недавно и нагенерили латчей. Точнее там всего один латч был, но провозился я с ним знатно. Дня три наверное

Такие!?  или  все же под  каким-нибудь always(*) ?   :wink2:

Удачи! Rob.

Share this post


Link to post
Share on other sites
51 minutes ago, RobFPGA said:

Такие!?  или  все же под  каким-нибудь always(*) ?   :wink2:

Именно такие. Там весь прикол ,что в одном из стейтов внутри if-а не был задействован объявленный сигнал. Вот и генерился латч. Где-то так:

always @(clk) begin
  net1 <= '0;
  net2 <= '0;
  if (reset) begin
    net1 <= '0;
    net2 <= '0;
  end else begin
    case (net3)
      2'b00: begin
        net1 <= '0;
        net2 <= '0;
  end
      2'b01: begin
        net1 <= 2'b01;
        net2 <= 2'b10;
  end
      2'b10: begin
        net1 <= 2'b10;
  end
      default: begin
        net1 <= 2'b00;
        net2 <= 2'b01;
  end
 end
end

Или без дефолта, я уже точно не помню.

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this