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

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

Пытаюсь написать модуль, ра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 не выполняются последовательно, а создают нечто, имеющее регулярную, повторяющуюся структуру.

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

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


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

7 minutes ago, des00 said:

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

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

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


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

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 разверните функции, пару копипастов и все.

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


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

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 разверните функции, пару копипастов и все.

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

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


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

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

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

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


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

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 и функции в Си имеют намного больше общего, чем различий (за исключением статик-автоматик).

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

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


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

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

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.

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


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

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). Зато возместил недостаток внимательности избытком пафоса ))))

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

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


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

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

47 minutes ago, flammmable said:

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

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

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

 

Удачи! Rob. 

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


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

19 minutes ago, RobFPGA said:

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

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

 

Удачи! Rob. 

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

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

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

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


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

56 minutes ago, flammmable said:

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

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

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

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


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

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: Чем же потом код править? 

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

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


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

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

21 minutes ago, Nick_K said:

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

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

21 minutes ago, Nick_K said:

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

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

Удачи! Rob.

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


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

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

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

 

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


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

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

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

Гость
Ответить в этой теме...

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

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

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

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

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

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