CRC circuit - Page 1
Forum section: electronics / general

author: promach
author_rank: Frequent Contributor
timestamp: July 07, 2020, 12:25:31 pm
content: What do you guys think aboutthis CRC circuit(CRC-3 polynomial divisor is 4'b1011) ?I am bit confused...

author: ataradov
author_rank: Super Contributor
timestamp: July 07, 2020, 08:01:55 pm
content: What do you find confusing here? Seems like a typical LFSR-based CRC. It takes a bit stream and produces a 3-bit CRC.

author: asmi
author_rank: Super Contributor
timestamp: July 07, 2020, 08:03:31 pm
content: The code is wrong. Blocking assignments should not be used inside clocked blocks.

author: ataradov
author_rank: Super Contributor
timestamp: July 07, 2020, 08:04:26 pm
content: Yes, I missed that part. All assignments inside always should be "<=" indeed.

author: promach
author_rank: Frequent Contributor
timestamp: July 10, 2020, 10:17:39 am
content: Looking atinput BITSTRB; // Current bit valid (Clock),Can I say that if the input message is of 32-bits length long, the whole CRC-3 process will only finish after 32 clock cycles ?The draft verilog code together withtestbench is located at this link here

author: ataradov
author_rank: Super Contributor
timestamp: July 10, 2020, 04:34:50 pm
content: Yes, this is the simplest serial implementation of the CRC, so it will take 32 clock cycles for calculate the CRC of the 32 bit word.There are tools to generate Verilog code for parallel implementations based on your polynomial and input/output sizes.

author: promach
author_rank: Frequent Contributor
timestamp: July 11, 2020, 12:37:33 pm
content: I foundthis parallel implementation of CRC, but I do not quite understand how the two matrices (Min = 0, Nin = 0) work ?The parallel implementation verilog code could be generated usingthis online CRC code generation toolCode://-----------------------------------------------------------------------------// Copyright (C) 2009 OutputLogic.com// This source file may be used and distributed without restriction// provided that this copyright statement is not removed from the file// and that any derivative work contains the original copyright notice// and the associated disclaimer.//// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.//-----------------------------------------------------------------------------// CRC module for data[11:0] , crc[3:0]=1+x^1+x^3+x^4;//-----------------------------------------------------------------------------module crc(input [11:0] data_in,input crc_en,output [3:0] crc_out,input rst,input clk);reg [3:0] lfsr_q,lfsr_c;assign crc_out = lfsr_q;always @(*) beginlfsr_c = lfsr_q ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in;lfsr_c = lfsr_q ^ data_in ^ data_in ^ data_in ^ data_in;lfsr_c = lfsr_q ^ data_in ^ data_in ^ data_in ^ data_in;lfsr_c = lfsr_q ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in;end // alwaysalways @(posedge clk, posedge rst) beginif(rst) beginlfsr_q <= {4{1'b1}};endelse beginlfsr_q <= crc_en ? lfsr_c : lfsr_q;endend // alwaysendmodule // crc

author: ataradov
author_rank: Super Contributor
timestamp: July 11, 2020, 05:55:03 pm
content: Here is my implementation of the idea described in that article. This is for USB polynomials. And this only generated the XOR block.Code:#!/usr/bin/env python# Inspired by http://outputlogic.com/?p=158# USB 5 : 0x105 - x^5 + x^2 + 1# USB 16: 0x18005 - x^16 + x^15 + x^2 + 1if 0:N = 8 # Data widthM = 5 # CRC widthP = 0x05 # USB CRC5: x^5 + x^2 + 1else:N = 8 # Data widthM = 16 # CRC widthP = 0x8005 # USB CRC16: x^16 + x^15 + x^2 + 1def crc_bit(crc, bit):if ((crc >> (M-1)) ^ bit) & 1:crc = (crc << 1) ^ Pelse:crc = (crc << 1)return crc & ((1 << M) - 1)def crc_par(crc, word):crc_out = crcfor i in range(N):crc_out = crc_bit(crc_out, (word >> i) & 1)return crc_outout_data = [[] for x in range(M)]out_crc = [[] for x in range(M)]c = 0for i in range(N):c = crc_par(0, 1 << i)for j in range(M):if (c & (1 << j)) and (i not in out_data):out_data += for i in range(M):c = crc_par(1 << i, 0)for j in range(M):if (c & (1 << j)) and (i not in out_crc):out_crc += for j in range(M):s = ' crc_out[%d] = ' % js += ' ^ '.join(['c[%d]' % v for v in out_crc])s += ' ^ 's += ' ^ '.join(['d[%d]' % v for v in out_data])print sHere is example of the use from the project:Code:reg [15:0] crc16_tx_r;always @(posedge clk_i) beginif (reset_i || ST_IDLE == state_r)crc16_tx_r <= 16'hffff;else if (ST_TX_DATA == state_r && pkt_tx_next_o)crc16_tx_r <= usb_crc16(crc16_tx_r, pkt_tx_data_i);endfunction [15:0] usb_crc16(input [15:0] crc, input [7:0] data);beginusb_crc16 = crc ^ crc ^ crc ^ crc ^ crc ^crc ^ crc ^ crc ^ data ^ data ^ data ^data ^ data ^ data ^ data ^ data;..............................................usb_crc16 = crc ^ crc ^ crc ^ crc ^ crc ^crc ^ crc ^ crc ^ crc ^ data ^ data ^data ^ data ^ data ^ data ^ data ^ data;endendfunction

author: promach
author_rank: Frequent Contributor
timestamp: July 11, 2020, 07:04:09 pm
content: Let me check your python script in a while.Whythis parallel CRC code simulation resultdoes not match the result forserial implementation of CRC code?

author: ataradov
author_rank: Super Contributor
timestamp: July 11, 2020, 07:19:02 pm
content: Your first link requires a log in. But in any case, there are many things that can be different for different CRC implementations - input bit order, polynomial bit order, input and output inversion. All that is also a part of the specification for the CRC.For example in case of my code, the final CRC value that actually goes in the packet is inverted and bit-reversed - "~reverse(crc16_tx_r)".

author: promach
author_rank: Frequent Contributor
timestamp: July 12, 2020, 01:39:27 am
content: QuoteHere is the code and testbench inside the first link. But the simulation result does not match theresult for serial implementation of CRC codeCode:// Credit : http://outputlogic.com/?page_id=321//-----------------------------------------------------------------------------// Copyright (C) 2009 OutputLogic.com// This source file may be used and distributed without restriction// provided that this copyright statement is not removed from the file// and that any derivative work contains the original copyright notice// and the associated disclaimer.//// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.//-----------------------------------------------------------------------------// CRC module for data[11:0] , crc[2:0]=1+x^1+x^3;//-----------------------------------------------------------------------------module crc(input [11:0] data_in,input crc_en,output [2:0] crc_out,input reset,input clk);reg [2:0] lfsr_q,lfsr_c;assign crc_out = lfsr_q;always @(*) beginlfsr_c = lfsr_q ^ lfsr_q ^ lfsr_q ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in;lfsr_c = lfsr_q ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in;lfsr_c = lfsr_q ^ lfsr_q ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in;end // alwaysalways @(posedge clk) beginif(reset) beginlfsr_q <= {3{1'b1}};endelse beginlfsr_q <= crc_en ? lfsr_c : lfsr_q;endend // alwaysendmodule // crcCode:module test_crc();reg clk;reg reset;reg crc_en;reg [11:0] data_in;wire [2:0] crc_out; // resultinitialbegin// Dump waves$dumpfile("test_crc.vcd");$dumpvars(0, test_crc);clk = 0;reset = 0;crc_en = 1;data_in = 'h1C0;@(posedge clk);reset = 1;@(posedge clk);@(posedge clk);reset = 0;#20 $finish;endalways #5 clk = !clk;crc crc3(.data_in(data_in), .crc_en(crc_en), .clk(clk), .reset(reset), .crc_out(crc_out));endmodule

author: ataradov
author_rank: Super Contributor
timestamp: July 12, 2020, 01:55:29 am
content: I don't have time or energy to study different implementations. The first clear difference that is obvious immediately, if default value for the CRC. In one case it is 3'b000, and in the other case 3'b111.Again, CRC-3 is not fixed thing. There are too many options for input and output parameters (inversion, bit order). You either need to know what specific configuration you want, or if you don't care, just take one and stick with it.

author: promach
author_rank: Frequent Contributor
timestamp: July 12, 2020, 03:01:57 pm
content: Your suggestion about the reset signal solved the above problem.See the updated verilog code and testbench below.However, I am still not sure how the two matrices (Min = 0, Nin = 0) work as described inhttp://outputlogic.com/?p=158Code:// Credit : http://outputlogic.com/?page_id=321//-----------------------------------------------------------------------------// Copyright (C) 2009 OutputLogic.com// This source file may be used and distributed without restriction// provided that this copyright statement is not removed from the file// and that any derivative work contains the original copyright notice// and the associated disclaimer.//// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.//-----------------------------------------------------------------------------// CRC module for data[11:0] , crc[2:0]=1+x^1+x^3;//-----------------------------------------------------------------------------module crc(input [11:0] data_in,//input crc_en,output [2:0] crc_out,input reset,input clk);reg [2:0] lfsr_q,lfsr_c;assign crc_out = lfsr_q;always @(*) beginlfsr_c = data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in;lfsr_c = data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in;lfsr_c = data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in;end // alwaysalways @(posedge clk) beginif(reset) beginlfsr_q <= {3{1'b0}};endelse beginlfsr_q <= lfsr_c;endend // alwaysendmodule // crcCode:module test_crc();reg clk;reg reset;//reg crc_en;reg [11:0] data_in;wire [2:0] crc_out; // resultinitialbegin// Dump waves$dumpfile("test_crc.vcd");$dumpvars(0, test_crc);clk = 0;reset = 0;//crc_en = 1;data_in = 'h1C3;@(posedge clk);reset = 1;@(posedge clk);@(posedge clk);reset = 0;@(posedge clk);//crc_en = 0;@(posedge clk);data_in = 'h1C2;@(posedge clk);//crc_en = 1;data_in = 'h1C1;@(posedge clk);data_in = 'h1C0;@(posedge clk);//crc_en = 0;#30 $finish;endalways #5 clk = !clk;crc crc3(.data_in(data_in), /*.crc_en(crc_en),*/ .clk(clk), .reset(reset), .crc_out(crc_out));endmodule

author: ataradov
author_rank: Super Contributor
timestamp: July 12, 2020, 06:36:38 pm
content: I'm not sure I understand the question. There is detailed description of how to generate those matrices. They are generated from the serial version and contain partial results. Having that lets you easily generate parallel version.

author: langwadt
author_rank: Super Contributor
timestamp: July 12, 2020, 06:54:50 pm
content: Quote from: asmi on July 07, 2020, 08:03:31 pmmaybe you shouldn't but you can

author: matrixofdynamism
author_rank: Regular Contributor
timestamp: July 27, 2020, 12:07:55 am
content: Anyone that wants to know anything about CRC, please do check out this page:http://checksumcrc.blogspot.com/

author: n5al
author_rank: Contributor
timestamp: August 06, 2020, 08:24:06 am
content: BTW,There is a neat, well-written article, by Greg Morse, in the September 1986 issue of Byte magazine, that discusses how to do CRC calculations using parallel methods. The article is focused on creating faster software implementations, but the basic techniques should apply to FPGA designs, as well.link to magazine article:https://archive.org/details/byte-magazine-1986-09/page/n124/mode/1up

author: promach
author_rank: Frequent Contributor
timestamp: August 07, 2020, 11:43:49 am
content: @n5alI do not quite understand the figures below extracted from your given byte-magazine link.By the way, I foundanother CRC implementationwhich seems more hardware-friendly.Could you comment about it ?Code:module usb_crc5(input rst_n,input clk,input clken,input d,output valid);reg[4:0] r;reg[4:0] next;wire top = r;assign valid = (next == 5'b01100);always @(*) beginif (top == d)next = { r, r, r, r, 1'b0 };elsenext = { r, r, !r, r, 1'b1 };endalways @(posedge clk or negedge rst_n) beginif (!rst_n) beginr <= 5'b11111;end else if (clken) beginr <= next;endendendmodule//---------------------------------------------------------------------module usb_crc16(input rst_n,input clk,input clken,input d,input dump,output out,output valid);reg[15:0] r;reg[15:0] next;assign out = r;assign valid = (next == 16'b1000000000001101);always @(*) beginif (dump || out == d)next = { r[14:0], 1'b0 };elsenext = { !r, r[13:2], !r, r, 1'b1 };endalways @(posedge clk or negedge rst_n) beginif (!rst_n) beginr <= 16'hffff;end else if (clken) beginr <= next;endendendmodule

author: ataradov
author_rank: Super Contributor
timestamp: August 07, 2020, 04:34:03 pm
content: This is the same thing, but serial again. It is not very useful if you are calculating the CRC at byte level, otherwise it should work.

author: promach
author_rank: Frequent Contributor
timestamp: August 08, 2020, 02:30:06 pm
content: QuoteWhich of the two implementations in my previous post above is serial ?

author: ataradov
author_rank: Super Contributor
timestamp: August 08, 2020, 06:14:08 pm
content: I'm not sure what post you are asking about. Any implementation that takes 1 bit at a time is serial.

author: promach
author_rank: Frequent Contributor
timestamp: August 09, 2020, 01:21:55 am
content: I was referring to the picture (crc architecture 1) and verilog code (crc architecture 2) insidepost #17

author: ataradov
author_rank: Super Contributor
timestamp: August 09, 2020, 01:24:04 am
content: Both are serial implementations. They take one bit a time and take 8 clock cycles to process one byte.

author: promach
author_rank: Frequent Contributor
timestamp: August 14, 2020, 03:55:44 pm
content: Forthis parallel CRC circuit, how to calculate the first matrix ? What does it mean by Min = 0 and Nin = 0 ?

author: ataradov
author_rank: Super Contributor
timestamp: August 14, 2020, 04:10:44 pm
content: You have a my Python code that calculates it. It answers how to calculate it with the exact code that does it. That matrix contains partial CRC results.

author: promach
author_rank: Frequent Contributor
timestamp: August 14, 2020, 04:49:33 pm
content: I modified your python code to use DATA_WIDTH=12 (M=12) and CRC_WIDTH = 3 (N=3), but your python code is generating code different fromreply #12Code:crc_out = c ^ c ^ d ^ d ^ d ^ d ^ d ^ d ^ d ^ dcrc_out = c ^ c ^ d ^ d ^ d ^ d ^ d ^ d ^ dcrc_out = c ^ d ^ d ^ d ^ d ^ d ^ d ^ dCode:always @(*)beginlfsr_c = data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in;lfsr_c = data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in;lfsr_c = data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in ^ data_in;end

author: ataradov
author_rank: Super Contributor
timestamp: August 14, 2020, 05:02:36 pm
content: How exactly was that code generated. It makes no sense to me. The old value of the CRC is not used at all in the generation of the lfsr_c[] and only input data is used. This is just wrong.

author: promach
author_rank: Frequent Contributor
timestamp: August 14, 2020, 10:42:26 pm
content: Try to have look athttp://outputlogic.com/my-stuff/circuit-cellar-january-2010-crc.pdfandhttp://outputlogic.com/?page_id=321

author: ataradov
author_rank: Super Contributor
timestamp: August 14, 2020, 10:47:13 pm
content: Yes, but what exact setting did you use to get that code? No matter what I do, I can't get it to generate that specific wrong code code. It looks like the code you posted was modified from the generated.Also, it is for a different polynomial compared to mine. Again, it is not clear what exactly you have modified in my code.Please provide all the details.

author: promach
author_rank: Frequent Contributor
timestamp: August 14, 2020, 11:18:13 pm
content: QuoteI think you mean I forgot to change P in your python code ?you mean the following modified python code ?After I changed P=0x08 , I have some strange verilog code.Code:crc_out = ^crc_out = ^crc_out = ^Code:#!/usr/bin/env python# Inspired by http://outputlogic.com/?p=158# USB 5 : 0x105 - x^5 + x^2 + 1# USB 16: 0x18005 - x^16 + x^15 + x^2 + 1if 1:N = 12 # Data widthM = 3 # CRC widthP = 0x08 # USB CRC5: x^3 + x^1 + 1else:N = 8 # Data widthM = 16 # CRC widthP = 0x8005 # USB CRC16: x^16 + x^15 + x^2 + 1def crc_bit(crc, bit):if ((crc >> (M-1)) ^ bit) & 1:crc = (crc << 1) ^ Pelse:crc = (crc << 1)return crc & ((1 << M) - 1)def crc_par(crc, word):crc_out = crcfor i in range(N):crc_out = crc_bit(crc_out, (word >> i) & 1)return crc_outout_data = [[] for x in range(M)]out_crc = [[] for x in range(M)]c = 0for i in range(N):c = crc_par(0, 1 << i)for j in range(M):if (c & (1 << j)) and (i not in out_data):out_data += for i in range(M):c = crc_par(1 << i, 0)for j in range(M):if (c & (1 << j)) and (i not in out_crc):out_crc += for j in range(M):s = ' crc_out[%d] = ' % js += ' ^ '.join(['c[%d]' % v for v in out_crc])s += ' ^ 's += ' ^ '.join(['d[%d]' % v for v in out_data])print(s)

author: ataradov
author_rank: Super Contributor
timestamp: August 14, 2020, 11:21:06 pm
content: Once again, you are not giving full information. What polynomial you want to get? 0x08 is x^4, which makes no sense with M=3. You probably want at least one tap < 4.

author: promach
author_rank: Frequent Contributor
timestamp: August 14, 2020, 11:36:54 pm
content: Sorry, now I am using P=0x13Code:crc_out = c ^ c ^ c ^ d ^ d ^ d ^ d ^ d ^ d ^ d ^ dcrc_out = c ^ d ^ d ^ d ^ d ^ d ^ d ^ dcrc_out = c ^ c ^ d ^ d ^ d ^ d ^ d ^ d ^ dSee alsohttps://www.edaplayground.com/x/666F

author: hamster_nz
author_rank: Super Contributor
timestamp: August 15, 2020, 09:16:31 am
content: @promach, In my view using code generators for your first few CRC codes is most likely a bad idea. Without working it through by hand will most likely miss that 'aha!' moment when you see how it all works. Likewise the mathematical analysis of CRCs is also a bit opaque, and made it difficult for me to see what is exactly supposed to happen. For short simple codes, at least initially, try working in through by hand.You can decompose your three lines above into three parts - what changes depend on the current state, what changes depend on the incoming data bits, and how they are merged together. This decomposition is the basis of most 'quick' CRC codes, usually though using lookup tables to avoid the binary operations.Here it is based on your three lines above:Code:// Advance the statefrom_state = c ^ c ^ cfrom_state = cfrom_state = c ^ c// Work out the changes due to the inputfrom_input = d ^ d ^ d ^ d ^ d ^ d ^ d ^ dfrom_input = d ^ d ^ d ^ d ^ d ^ d ^ dfrom_input = d ^ d ^ d ^ d ^ d ^ d ^ d// Merge the two togethercrc_out = from_state ^ from_inputAnd if you a looking for the matrix operations, this should make them pop out:Code:from_state = c ^ c ^ cfrom_state = c ^ 0 ^ 0from_state = c ^ c ^ 0// Work out the changes due to the inputfrom_input = d ^ d ^ d ^ 0 ^ d ^ 0 ^ 0 ^ d ^ d ^ d ^ 0 ^ dfrom_input = 0 ^ 0 ^ d ^ d ^ d ^ 0 ^ d ^ 0 ^ 0 ^ d ^ d ^ dfrom_input = 0 ^ d ^ d ^ d ^ 0 ^ d ^ 0 ^ 0 ^ d ^ d ^ d ^ 0

author: promach
author_rank: Frequent Contributor
timestamp: August 15, 2020, 10:43:49 am
content: Quote@hamster_nz : seehttps://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks#Parallel_computation_without_table

author: hamster_nz
author_rank: Super Contributor
timestamp: August 15, 2020, 11:16:51 am
content: Quote from: promach on August 15, 2020, 10:43:49 amI'm not quite sure what you are trying to say.You can expand it all out, but it is usually a waste of time if you are using a HDL. You can just repeat the simple operation 'n' times, merging in each bit of data as you go, then let the synthesis tools to the hard work of simplifying the logic.Here's CRC code I wrote for Ethernet frames, processing 8 bits at a time with a 32-bit CRC:Code:-- Note: v_crc is a VHDL variablev_crc := crc;for i in 0 to 7 loopif data_in(i) = v_crc(31) thenv_crc := v_crc(30 downto 0) & '0';elsev_crc := (v_crc(30 downto 0)& '0') xor x"04C11DB7";end if;end loop;crc <= v_crc;It is just as efficient as expanding it all out as per the Wikipedia page, but is less code and is less prone to bugs.

author: promach
author_rank: Frequent Contributor
timestamp: August 15, 2020, 01:47:07 pm
content: I am trying to understandhow the two matrices are derived from the crc polynomial itself, not just simply rearranging the final CRC functions coding into matrix visual formattingCode:v_crc := (v_crc(30 downto 0)& '0') xor x"04C11DB7";Why "04C11DB7" ?

author: ataradov
author_rank: Super Contributor
timestamp: August 15, 2020, 06:02:46 pm
content: 0x04C11DB7 is a standard Ethernet CRC32 polynomial.How the matrices are created is described step by step in the article. This is literally what the article is all about.Take a piece of paper and follow each step as described. There is no way we can explain it somehow better than the article does.You want some simple one sentence explanation and there is none. You have to work though it to understand.

author: hamster_nz
author_rank: Super Contributor
timestamp: August 15, 2020, 09:47:43 pm
content: Maybe this explanation will help.I wrote a small CRC calculator, calculating the CRC shown in the original post, allowing me to feed in bits.The output is the CRC state at the start of the cycle, "&", then the data bit, then the state at the end of the the cycle. Here is it run with all zeros:Code:0: (0,0,0) & 0 => (0,0,0)1: (0,0,0) & 0 => (0,0,0)2: (0,0,0) & 0 => (0,0,0)3: (0,0,0) & 0 => (0,0,0)4: (0,0,0) & 0 => (0,0,0)5: (0,0,0) & 0 => (0,0,0)6: (0,0,0) & 0 => (0,0,0)7: (0,0,0) & 0 => (0,0,0)8: (0,0,0) & 0 => (0,0,0)9: (0,0,0) & 0 => (0,0,0)Here is it run with a single '1' followed with '0's:Code:1: (0,0,0) & 1 => (0,1,1)2: (0,1,1) & 0 => (1,1,0)3: (1,1,0) & 0 => (1,1,1)4: (1,1,1) & 0 => (1,0,1)5: (1,0,1) & 0 => (0,0,1)6: (0,0,1) & 0 => (0,1,0)7: (0,1,0) & 0 => (1,0,0)8: (1,0,0) & 0 => (0,1,1)9: (0,1,1) & 0 => (1,1,0)10: (1,1,0) & 0 => (1,1,1)11: (1,1,1) & 0 => (1,0,1)12: (1,0,1) & 0 => (0,0,1)13: (0,0,1) & 0 => (0,1,0)14: (0,1,0) & 0 => (1,0,0)15: (1,0,0) & 0 => (0,1,1)16: (0,1,1) & 0 => (1,1,0)17: (1,1,0) & 0 => (1,1,1)18: (1,1,1) & 0 => (1,0,1)19: (1,0,1) & 0 => (0,0,1)If you look at the second output, you can see that the repeats every seven lines.Code:...3: (1,1,0) & 0 => (1,1,1)...10: (1,1,0) & 0 => (1,1,1)...17: (1,1,0) & 0 => (1,1,1)...Why seven? It's 2^(CRC length)-1;Now focus on these three lines:Code:6: (0,0,1) & 0 => (0,1,0)7: (0,1,0) & 0 => (1,0,0)8: (1,0,0) & 0 => (0,1,1)These are the key lines because only one bit is set in the present CRC state. You can use these to derive all the other lines if you want. For example, if you wanted to know the output of "(0,1,1) & 0"you just XOR all the items together:Code:(0,0,1) & 0 => (0,1,0)(0,1,0) & 0 => (1,0,0)-- XOR the two lines ---(0,1,1) & 0 => (1,1,0);And you can see that this is correct:Code:9: (0,1,1) & 0 => (1,1,0)So what if you wanted to advance steps at a time? We can do it, by expanding the table a little:Code:6: (0,0,1) & 0 => (0,1,0)7: (0,1,0) & 0 => (1,0,0)8: (1,0,0) & 0 => (0,1,1)9: (0,1,1) & 0 => (1,1,0)Just append the operation and result of the next line onto the existing lines:Code:(0,0,1) & 0 => (0,1,0) & 0 => (1,0,0)(0,1,0) & 0 => (1,0,0) & 0 => (0,1,1)(1,0,0) & 0 => (0,1,1) & 0 => (1,1,0)If we delete the middle state, we have a way to quickly advance the CRC state through two cyclesCode:(0,0,1) & 0 => => (1,0,0)(0,1,0) & 0 => => (0,1,1)(1,0,0) & 0 => => (1,1,0)Let's test it by seeing what (0,1,1) will be two cycles laterCode:(0,0,1) & 0 => => (1,0,0)(0,1,0) & 0 => => (0,1,1)=== XOR==========(0,1,1) & 0 => => (1,1,1)And checking with the original tables of states, this is correct:Code:2: (0,1,1) & 0 => (1,1,0)3: (1,1,0) & 0 => (1,1,1).So this is how you can build one of your two matrices:- Look for input states where only a single bits set- Look at what the state is 'n' cycles later.- Add that state to the matrixSo how do you build the other matrix? It's pretty simple. Here's one way:Take the top 'n' rows of the table, and reverse the order:Code:8: (1,0,0) & 0 => (0,1,1)7: (0,1,0) & 0 => (1,0,0)6: (0,0,1) & 0 => (0,1,0)5: (1,0,1) & 0 => (0,0,1)4: (1,1,1) & 0 => (1,0,1)3: (1,1,0) & 0 => (1,1,1)2: (0,1,1) & 0 => (1,1,0)1: (0,0,0) & 1 => (0,1,1)Remove everything to the left of the "=>", and you get this:Code:8: (0,1,1)7: (1,0,0)6: (0,1,0)5: (0,0,1)4: (1,0,1)3: (1,1,1)2: (1,1,0)1: (0,1,1)You can then use this table to calculate the change made if a data bit was a one 'n-1' cycles ago.So the CRC for "00000001" should be (0,1,1), from line 1. For '00001000" it should be (1,0,1), from line 4. and for "10000000" it should be (0,1,1). Let's test the last one:Code:1: (0,0,0) & 1 => (0,1,1)2: (0,1,1) & 0 => (1,1,0)3: (1,1,0) & 0 => (1,1,1)4: (1,1,1) & 0 => (1,0,1)5: (1,0,1) & 0 => (0,0,1)6: (0,0,1) & 0 => (0,1,0)7: (0,1,0) & 0 => (1,0,0)8: (1,0,0) & 0 => (0,1,1)And indeed it is. Treating this as a matrix, we can generate the change in the CRC caused by any 8-bit value. Say you want the CRC of "10001001",Code:00000001 => (0,1,1)00001000 => (1,0,1)10000000 => (0,1,1)== XOR THEM ===10001001 => (1,0,1)So let's see if that is the case:Code:1: (0,0,0) & 1 => (0,1,1)2: (0,1,1) & 0 => (1,1,0)3: (1,1,0) & 0 => (1,1,1)4: (1,1,1) & 0 => (1,0,1)5: (1,0,1) & 1 => (0,1,0)6: (0,1,0) & 0 => (1,0,0)7: (1,0,0) & 0 => (0,1,1)8: (0,1,1) & 1 => (1,0,1)Holy heck! It works, so there is the source of the two matices. One is 'single bit of state set" advanced 'n' cycles (in this post I've only advanced by two cycles, making an 'n' bit one is an exercise left to the reader. It's a bit of an odd case, as 8 cycles is 7+1, so has the same change as advancing one cycle)Code:(0,0,1) & 0 => => (1,0,0)(0,1,0) & 0 => => (0,1,1)(1,0,0) & 0 => => (1,1,0)The other is a single data bit rolled forward n cycles, with the order reversed, It is the change introduced by a single non-zero bit 'n' cycles ago:Code:8: (1,0,0) & 0 => (0,1,1)7: (0,1,0) & 0 => (1,0,0)6: (0,0,1) & 0 => (0,1,0)5: (1,0,1) & 0 => (0,0,1)4: (1,1,1) & 0 => (1,0,1)3: (1,1,0) & 0 => (1,1,1)2: (0,1,1) & 0 => (1,1,0)1: (0,0,0) & 1 => (0,1,1)You can just XOR them the lines together as required.

author: promach
author_rank: Frequent Contributor
timestamp: August 17, 2020, 10:52:34 am
content: Code:100000000100101 subtract=========001010 (The 5 highest bits are the first row in the matrix)100101 no subtraction=========010100 (The 5 highest bits are the second row in the matrix)100101 no subtraction=========101000 (The 5 highest bits are the third row in the matrix)100101 subtract=========01101 (No more dividend bits, this is the remainder (CRC) for the message "1000" and the fourth row in the matrix)The long division mechanism forthe circuit cellar articleseems to be different from that described inwikipedia articleCode:11010011101100 000 <--- input right padded by 3 bits1011 <--- divisor01100011101100 000 <--- result (note the first four bits are the XOR with the divisor beneath, the rest of the bits are unchanged)1011 <--- divisor ...00111011101100 000101100010111101100 000101100000001101100 000 <--- note that the divisor moves over to align with the next 1 in the dividend (since quotient for that step was zero)1011 (in other words, it doesn't necessarily move one bit per iteration)00000000110100 000101100000000011000 000101100000000001110 000101100000000000101 000101 1-----------------00000000000000 100 <--- remainder (3 bits). Division algorithm stops here as dividend is equal to zero.I think I know what the first matrix is doing. It is basically the long division but again storing all the in-between steps whether subtraction operation is performed or not. Refer to the wikipedia version for comparison.By the way, why do we need the second matrix (Nin = 0) ?

author: hamster_nz
author_rank: Super Contributor
timestamp: August 17, 2020, 12:02:38 pm
content: Quote from: promach on August 17, 2020, 10:52:34 amBecause you are calculating it on a small part of the message at a time.It is "if we have a remainder of X at the start of this block, what will contribute Y to the remainder after this block is processed".It is very close to trying to find the remainder of dividing a very big decimal by 7 one digit at a time by using this formula:remainder_out = (table[remainder in])+(next digit)) % 7.Where the table is :table = {0, 3, 6, 2, 5, 1, 4}So to calculate 100%7 the process would be:Processing the first digit gives:remainder_out = (table+1)%7 = 1Second digit givesremainder_out = (table+0)%7 = 3Third digit givesremainder_out = (table+0)%7 = 2So 100 % 7 = 2.So what is in 'table'? Just precalculated values for (10*x)%7...

author: promach
author_rank: Frequent Contributor
timestamp: August 17, 2020, 01:36:55 pm
content: But how to compute values for all 5 rows intable 2 (second matrix)?

author: hamster_nz
author_rank: Super Contributor
timestamp: August 17, 2020, 10:19:14 pm
content: Quote from: promach on August 17, 2020, 01:36:55 pmHere's how I would do it, without reading all the theory in the article.Looking at figure 1, I hacked a quick bit of code to dump out how the state transitions, starting with bit 0 set in the state:Code:#include <stdio.h>int main(int argc, char *argv[]) {int state = 1, i;for(i = 0; i < 31; i++) {printf("%02i: ", i);putchar(state&0x10 ? '1' : '0');putchar(state&0x08 ? '1' : '0');putchar(state&0x04 ? '1' : '0');putchar(state&0x02 ? '1' : '0');putchar(state&0x01 ? '1' : '0');putchar('\n');if(state & 0x10) {state = (state << 1) ^ 0x5;} else {state = (state << 1);}}}Here's the output:Code:00: 0000101: 0001002: 0010003: 0100004: 1000005: 0010106: 0101007: 1010008: 0110109: 1101010: 1000111: 0011112: 0111013: 1110014: 1110115: 1111116: 1101117: 1001118: 0001119: 0011020: 0110021: 1100022: 1010123: 0111124: 1111025: 1100126: 1011127: 0101128: 1011029: 0100130: 1001031: 00001Note how rows 0 to 4 have only one bit set. This is very important.Table 2, with 'h' = 4 (advancing through four states) is generated as followsFind the state where bit zero is set, count down four lines and get that state:00001 (from line 0) => 10000 (from line 4)Then find the state where bit one is set, count down four lines and grab that value00010 => 00101.. and so on till you have:00001 => 1000000010 => 0010100100 => 0101001000 => 1010010000 => 01101And there is your table:The 00001 mapping is "min" : 1 0 0 0 0The 00010 mapping is "min" : 0 0 1 0 1The 00100 mapping is "min" : 0 1 0 1 0The 01000 mapping is "min" : 1 0 1 0 0The 10000 mapping is "min" : 0 1 1 0 1Check against the document... yep passes the sniff test.And if you look really closely, you can see that...05: 0010106: 0101007: 1010008: 01101...Is the same as table 1.Nin: 0 0 1 0 1Nin: 0 1 0 1 0Nin: 1 0 1 0 0Nin: 0 1 1 0 1

author: promach
author_rank: Frequent Contributor
timestamp: August 18, 2020, 03:27:20 am
content: I do not quite understand the process before you obtainThe 00001 mapping is "min" : 1 0 0 0 0

author: hamster_nz
author_rank: Super Contributor
timestamp: August 18, 2020, 06:25:52 am
content: Quote from: promach on August 18, 2020, 03:27:20 amI've most likely worded it poorly. Can somebody chip in and help???

author: ataradov
author_rank: Super Contributor
timestamp: August 18, 2020, 06:57:41 am
content: I'm not sure how to explain that more clearly. The real issue here is that to understand the parallel version, you need to have a decent understanding of the serial version.So for the OP, I would strongly recommend to experiment with the serial version. Do that test with feeding a running one, and then see how that related to the CRC of an arbitrary value. Write an actual code (C or Verilog, whatever works) and feed it values and check the results. You won't get it unless you actually put in some effort.For smaller polynomials do the calculations by hand.

author: tru
author_rank: Regular Contributor
timestamp: August 18, 2020, 05:01:27 pm
content: Quote from: promach on August 14, 2020, 03:55:44 pmYou'll need understanding of basic matrix mathematics to calculate the first matrix.The fundamentals is described under "generator matrix of linear cyclic codes".I'll try to explain some things but will skip most of the standard mathematics stuff (just google them)...Please bear with the mathematics jargon, I cannot find alternative/equivalent wording for them.The first matrix is actually the "coefficient generator matrix" which you can get from calculating the "generator matrix (in standard form)".Since I cannot type in mathematical symbols I'll have to link in references.To get that coefficient matrix you start with the generator matrix in non-standard form (for the meaning of this google matrix in standard form):See link (2nd post) for the generalised generator matrix (in non-standard form):https://math.stackexchange.com/questions/1047535/generator-matrix-of-a-binary-cyclic-codeNote that generator matrix expressions given by most people are in reversed order, i.e. lowest bit position first from left to right.My examples will use the usual binary computer way, i.e. highest bit position first from left to right. So g0 starts from right side (instead of left in the link) followed by g1, then g2,.. etcSTEP 1.Let's apply this to the USB CRC5:The USB CRC5 generator polynomial is: g(x) = x^5 + x^2 + 1and in binary form is: 100101Our length parameters are:k = input data length: 4 bitsn-k = parity length (i.e. CRC length): 5 bitsn = codeword length (sum of above) = 9 bitsFrom the link the generator matrix is of dimension (row x column): k x nThat means for our example we need 4 rows, so following that generalised generator matrix expression we get a (4 x 9) generator matrix:G =You can probably see that it is made by taking the generator polynomial 100101 shifted right by one for each row and filling empty parts with zeroes.STEP 2.Next we need to go further and convert that matrix into the standard form.The generator matrix in standard form is given by: S = [I|P]where I = identity matrix (of size k x k) and P = another matrixAn identity matrix is simply diagonal ones with everything else zeroes.*For further explanation of identity matrix please google it (is standard matrix stuff)So basically we need to get it like this:S =To convert it we apply standard matrix operations to eliminate 1 values (aka Gaussian Elimination) so that left part of the matrix G is an identity matrix, but due to the staircase leading zeroes at start of each row there is a pattern so we only need to use row additions to eliminate.Here's the matrix operations to get identity matrix into the left side:Code:*Note arithmetic operations must be in finite field so addition is simply xor1) Convert row 0. Row addition: Row 0 + Row 3 (i.e. Row 0 ^ Row 3)G = -> R0 + R3 ->    2) Convert row 1. Is already correct so we do nothing3) Convert row 2. Is already correct so we do nothing4) Convert row 3. Is already correct so we do nothingOh dear, our example is too simple and only needs the first row to be operated on. Anyway we end up with this result:S =If we separate the identity matrix you can see that the right hand side matrix contains the same rows as in your post (except rows are reversed in yours):S =[1000 01101][0100 10100][0010 01010][0001 00101]

author: promach
author_rank: Frequent Contributor
timestamp: August 19, 2020, 07:52:31 am
content: @tru I have already understood how to generate the matrix 1.What I do not understand is the purpose of matrix 2 during parallel CRC equation generation and how to generate matrix 2 itself.

author: hamster_nz
author_rank: Super Contributor
timestamp: August 19, 2020, 08:56:38 am
content: Quote from: promach on August 19, 2020, 07:52:31 amOne matrix allows you to advance the CRC's state though the desired number of updates, without calculating the intermediate states (but assumes all new data bits are '0's).The other matrix allows you to update the updated CRC state to reflect the change that any '1' bits would have caused when they were included.This is why the first matrix is always NxN (where N is the size of the CRC) and the other is MxN (or is that NxM?), where M is the number of parallel bits being included in the CRC for each update.

author: promach
author_rank: Frequent Contributor
timestamp: August 19, 2020, 10:24:00 am
content: QuoteInhttp://outputlogic.com/my-stuff/circuit-cellar-january-2010-crc.pdf#page=4, step 6 wordings are so vague and confusing ...

author: tru
author_rank: Regular Contributor
timestamp: August 19, 2020, 02:12:46 pm
content: Quote from: promach on August 19, 2020, 07:52:31 amI don't know about matrix 2 myself, I believe hamster_nz made a good description, but if it helps I wrote C code that builds the two matrices as described in the article:Code:/*C code that builds the two matrix H1 and H2 for building CRC parallel code as described by Evgeni Stavinov in his article:http://outputlogic.com/my-stuff/circuit-cellar-january-2010-crc.pdfNote: for keeping with the same style as the article I've used arrays for the CRC and input data, normally I would use single wide variables,but in this case memcpy and memset needs to be used because C cannot copy arrays using the "=" operator.*/#include <stdio.h>#include <string.h>//M = CRC width#define M 5//N = Data width#define N 4//Hard coded USB CRC5 (g(x) = x^5 + x^2 + 1) serial CRC calculator. The algorithm is LFSR.unsigned char* crc_serial(unsigned char data_bit, unsigned char prev_crc){unsigned char new_crc;new_crc = prev_crc ^ data_bit;new_crc = prev_crc;new_crc = prev_crc ^ prev_crc ^ data_bit;new_crc = prev_crc;new_crc = prev_crc;return new_crc;}//For building the matrix for CRC parallel codeunsigned char* crc_parallel_builder(unsigned char n_in, unsigned char m_in){unsigned char m_out;int i;memcpy(m_out, m_in, M); //m_out = m_infor(i = 0; i < N; i++){memcpy(m_out, crc_serial(n_in, m_out), M); //m_out = crc_serial(n_in, m_out)}return m_out;}//Display matrix rowvoid disp_m_out(unsigned char m_out){int i;for(i = 0; i < M; i++){printf("%i\t", m_out[M - 1 - i]);}printf("\n");}void disp_header(){int i;for(i = 0; i < M; i++){printf("Mout[%i]\t", M - 1 - i);}printf("\n");}void main(){unsigned char m_in;unsigned char n_in;unsigned char m_out;int i;//Build matrix H1printf("Matrix H1:\n");printf("Min = 0\t");disp_header();memset(m_in, 0, M); //m_in = 0for(i = 0; i < N; i++){//Build matrix row..memset(n_in, 0, N); //n_in = 0n_in[N - 1 - i] = 1; //set only 1 bit for each row corresponding to n_in = 2^imemcpy(m_out, crc_parallel_builder(n_in, m_in), M); //m_out = crc_parallel_builder(n_in, m_in)//Display matrix row..printf("Nin[%i]\t", i);disp_m_out(m_out);}//Build matrix H2printf("\nMatrix H2:\n");printf("Nin = 0\t");disp_header();memset(n_in, 0, N); //n_in = 0for(i = 0; i < M; i++){//Build matrix row..memset(m_in, 0, M); //m_in = 0m_in = 1; //set only 1 bit for each row corresponding to m_in = 2^imemcpy(m_out, crc_parallel_builder(n_in, m_in), M); //m_out = crc_parallel_builder(n_in, m_in)//Display matrix row..printf("Min[%i]\t", i);disp_m_out(m_out);}}It will output this:Code:Matrix H1:Min = 0 Mout Mout Mout Mout MoutNin 0 0 1 0 1Nin 0 1 0 1 0Nin 1 0 1 0 0Nin 0 1 1 0 1Matrix H2:Nin = 0 Mout Mout Mout Mout MoutMin 1 0 0 0 0Min 0 0 1 0 1Min 0 1 0 1 0Min 1 0 1 0 0Min 0 1 1 0 1

author: tru
author_rank: Regular Contributor
timestamp: August 19, 2020, 02:38:01 pm
content: Quote from: promach on August 19, 2020, 10:24:00 amI think step 6 is same meaning as the slightly clearer step 9 on the webpage versionhttp://outputlogic.com/?p=158:QuoteIt basically just means the equations are made using the columns and rows of the two matrices, i.e. for each Mout column look at the rows where there is a 1 and xor them as an equation.So for instance the first equation Mout, if you look at the first column (right hand side) in the first matrix you see there is a 1 value for rows Nin and Nin, and similarly for the second matrix in Mout column there is a 1 value for rows Min and Min, these together gives you the first equation:Mout = Min^Min^Nin^Nin

author: promach
author_rank: Frequent Contributor
timestamp: August 19, 2020, 02:59:10 pm
content: Quotebut how does doing this cross-mapping across these two matrices generate a "parallel" CRC ?

author: promach
author_rank: Frequent Contributor
timestamp: August 24, 2020, 12:14:23 pm
content: I do not quite understand how the followingserial implementation of CRCworks ?Whycrc5_serial = crc ^ crc ^ data;?Code:/=============================================================// Verilog function that implements serial USB CRC5//=============================================================function [4:0] crc5_serial;input [4:0] crc;input data;begincrc5_serial = crc ^ data;crc5_serial = crc;crc5_serial = crc ^ crc ^ data;crc5_serial = crc;crc5_serial = crc;endendfunction//============================================================

author: ataradov
author_rank: Super Contributor
timestamp: August 24, 2020, 04:18:01 pm
content: This is a literal implementation of the most basic CRC circuit like thishttps://media.cheggcdn.com/media/611/61121185-c994-4bb8-829b-e2f0fa545114/phpOk2gly.pngNote that polynomial is different on the picture, but the same principle applies.EDIT: Well, your article has the actual circuit. I'm not really sure what the question is actually asking then. This is how you build CRC circuits.

author: tru
author_rank: Regular Contributor
timestamp: August 25, 2020, 07:28:15 am
content: Quote from: promach on August 24, 2020, 12:14:23 pmAs ataradov said it is "literally" the LFSR circuit as shown in figure 1 in the article.If you look at figure 1 there are two xor gates and five shift register bit boxes, let's label the xor gates xor0 and xor1, and shift boxes from right to left as box0 to box4.code from xor0 gate:the first xor gate is fed with input box4 and data bit and we can write this as:Code:xor0_output = box4 ^ datasince box4 is crc in the Verilog code so the above translates directly to the line:Code:crc5_serial = crc ^ datacode from xor1 gate:the second xor gate is fed with input box1 and the output of xor0 gate and we can write this as:Code:xor1_output = box1 ^ xor0_outputwhich is same as:xor1_output = box1 ^ box4 ^ datasince box1 is crc and box4 is crc in the Verilog code the above translates directly to the line:Code:crc5_serial = crc ^ crc ^ data

author: hamster_nz
author_rank: Super Contributor
timestamp: August 25, 2020, 08:05:15 am
content: That function combines the CRC's state and the input data bit to generate the next state value.It doesn't have the required storage elements to hold that state.That will be defined in whatever is using this function.

author: promach
author_rank: Frequent Contributor
timestamp: September 05, 2020, 02:32:14 pm
content: How does the following serial CRC code implementation works ?It is different from the long division operations.crc_serial_optimized.vCode:module crc_serial_optimized(clk, reset, data, crc);//=============================================================// Verilog function that implements serial USB CRC5//=============================================================input clk, reset;input data;output reg [4:0] crc;always @(posedge clk)beginif(reset) crc <= 0;else begincrc <= crc ^ data;crc <= crc;crc <= crc ^ crc ^ data;crc <= crc;crc <= crc;endend//============================================================endmodulecrc_serial_optimized_tb.vCode:module crc_serial_optmized_tb();reg clk;reg reset;reg data;wire [4:0] crc;wire new_data;crc_serial_optimized crc5(.clk(clk), .reset(reset), .data(data), .crc(crc));initialbegin$dumpfile("crc_serial_optimized.vcd");$dumpvars(1, crc5);clk <= 0;reset <= 1;data <= 0;@(posedge clk);@(posedge clk);reset <= 0;@(posedge clk);@(posedge clk);//data = 4'b1101; "0xD"data <= 1'b1;@(posedge clk);data <= 1'b1;@(posedge clk);data <= 1'b0;@(posedge clk);data <= 1'b1;@(posedge clk);// data = 4'b0101; "0xA"data <= 1'b1;@(posedge clk);data <= 1'b0;@(posedge clk);data <= 1'b1;@(posedge clk);data <= 1'b0;#50 $finish;endalways #5 clk = !clk;endmodule

author: ataradov
author_rank: Super Contributor
timestamp: September 05, 2020, 06:08:31 pm
content: Here is an article that explains the transition from the long division to the LFSR versionhttp://www.sunshine2k.de/articles/coding/crc/understanding_crc.htmlIt is a long division, you just don't keep the integer part of the result.

author: promach
author_rank: Frequent Contributor
timestamp: September 05, 2020, 06:30:02 pm
content: What do you exactly mean byIt is a long division, you just don't keep the integer part of the result.?

author: ataradov
author_rank: Super Contributor
timestamp: September 05, 2020, 06:32:48 pm
content: I mean exactly what I said. CRC is the remainder from the division. You don't need to keep the result of the division, just the remainder. And that what this LFSR circuit does. I have no way to explain that any better.Work though the first two examples in that link. It shows detailed operation of the long division and equivalent LFSR-based algorithm.

author: promach
author_rank: Frequent Contributor
timestamp: September 06, 2020, 07:29:34 am
content: Your so-called LFSR circuit is just long division which requires zeroes to be appended to the end of the message bits.crc_serial_long_division.vCode:module crc_serial_long_division(clk, reset, data, crc);//=============================================================// Verilog function that implements serial USB CRC5//=============================================================input clk, reset;input data;output reg [4:0] crc;always @(posedge clk)beginif(reset) crc <= 0;else begincrc <= crc ^ data;crc <= crc;crc <= crc ^ crc;crc <= crc;crc <= crc;endend//============================================================endmodulecrc_serial_long_division_tb.vCode:module crc_serial_long_division_tb();reg clk;reg reset;reg data;wire [4:0] crc;wire new_data;crc_serial_long_division crc5(.clk(clk), .reset(reset), .data(data), .crc(crc));initialbegin$dumpfile("crc_serial_long_division.vcd");$dumpvars(1, crc5);clk <= 0;reset <= 1;data <= 0;@(posedge clk);@(posedge clk);reset <= 0;@(posedge clk);@(posedge clk);//data = 4'b1101; "0xD"data <= 1'b1;@(posedge clk);data <= 1'b1;@(posedge clk);data <= 1'b0;@(posedge clk);data <= 1'b1;@(posedge clk);// data = 4'b1010; "0xA"data <= 1'b1;@(posedge clk);data <= 1'b0;@(posedge clk);data <= 1'b1;@(posedge clk);data <= 1'b0;@(posedge clk);// appends 5 zeroesdata <= 1'b0;@(posedge clk);data <= 1'b0;@(posedge clk);data <= 1'b0;@(posedge clk);data <= 1'b0;@(posedge clk);data <= 1'b0;#50 $finish;endalways #5 clk = !clk;endmodule

author: ataradov
author_rank: Super Contributor
timestamp: September 06, 2020, 07:41:00 am
content: What do you mean by "your"? Yes, LFSR is a way to implement a long division that discards quotient and produces just a remainder. Did I say anything else?I'm not really sure what do you want from us here.

author: promach
author_rank: Frequent Contributor
timestamp: September 06, 2020, 08:29:17 am
content: Whyoptimized version at reply #56does not require zero appending to the end of message bits , whilelong division version at reply #60requires so ?optimized versionlong division version

author: ataradov
author_rank: Super Contributor
timestamp: September 06, 2020, 08:41:00 am
content: Section 4.2 "Modified CRC-8 bitwise implementation for one byte input data" of the link I posted earlier explains the difference.

author: promach
author_rank: Frequent Contributor
timestamp: September 06, 2020, 11:08:02 am
content: Theexplanation in section 4.2:The first 8 left-shifts are useless because the CRC value is initialized with 0 so no XOR operation is performed. This means we can initialize the CRC value directly with the input byte.still does not explain thedifference between the top input of the XOR gate in the middleas shown inreply #62

author: hamster_nz
author_rank: Super Contributor
timestamp: September 06, 2020, 11:36:54 am
content: LFSRs are related to CRCs.LFSRs have the XNOR or XOR forms,So wondering if the same is true for CRCs, and they have different formas I Googled for "Different forms of CRC".Now Google thinks I have colo-rectal cancer.

author: tru
author_rank: Regular Contributor
timestamp: September 06, 2020, 02:30:30 pm
content: long division version (crc_serial_long_division.v):Is a LFSR circuit that performs a portion of long division to give remainders.Note: it does NOT produce traditional CRC at each shift stage, the CRC is produced at the end after you feed in zeroes of CRC width, see *key note below.optimized version (crc_serial_optimized.v)Is a LFSR circuit that produces CRC at each shift stage, hence optimized version (or perhaps better: direct version).The optimised one doesn't need to be fed with zeroes because it directly produces traditional CRC at each shift stage.Optimisation is possible because the zeroes are constant values. Feeding in zeroes will not affect the XOR operations (result remains unchanged if you xor with 0) but it does affect the INPUT of the XORs.If you feed in zeroes upto CRC width the first box will wrap around to the first, hence why the middle XOR's input is changed to the output of the first XOR logic gate.*The key note here is that the traditional CRC isn't just the remainder of the message, it is the remainder of the message appended with zeroes of CRC width.

author: promach
author_rank: Frequent Contributor
timestamp: September 06, 2020, 03:48:55 pm
content: QuoteWhat do you exactly mean bythe first box will wrap around to the first?

author: ataradov
author_rank: Super Contributor
timestamp: September 06, 2020, 05:14:05 pm
content: Quote from: promach on September 06, 2020, 11:08:02 amIt does. That's the exact modification you need to make to initialize the CRC without waiting for it to shift the initial zeros. Looks how optimized version feeds the input bit into all the taps (2 in this case). This way you don't need to wait for the initial zeros to shift out.

author: tru
author_rank: Regular Contributor
timestamp: September 06, 2020, 06:38:50 pm
content: Quote from: promach on September 06, 2020, 03:48:55 pmIf you feed in zeroes of CRC width the value in the first box will xor middle gates and wrap around.Let's look at the long division LFSR stages with a very simple example.We are using USB CRC5 with a data bit (message bit) width of 1.Suppose our message is 1:data = 1Note the results of each stage is calculated and shown in the next stage so I can show previous and current.About the stages:First we feed in message bit 1 at stage 0.Next we append zeroes, so feed in a zero for the following five stages (width of CRC).Notice the 1 coloured in red, it shows how this 1 bit moves inside the LFSR, this 1 is the XOR0 gate result from the start.Look at the last stage 5, the red coloured 1 has reached into the last box, and now begins to wrap around and will be the input to both of the XOR gates.You can see that the input to those XOR gates are:XOR0 (first gate) = 1 ^ 0XOR1 (middle gate) = 1 ^ 0For the optimised version we only care for the last stage and all intermediate stage values can be thrown away or ignored. The last stage XOR1 is equivalent to inputting the XOR0 gate result and the previous box, which we could have done from the start without going through all those stages.

author: BrianHG
author_rank: Super Contributor
timestamp: September 07, 2020, 12:33:20 am
content: Since it's partially relevant, error detection and correction, part 1 of 2, hamming codes:This 3Blue1Brown visualizes the error detection and correction process.

author: promach
author_rank: Frequent Contributor
timestamp: September 07, 2020, 09:15:22 am
content: Thanks, @truI have understood the reasoning behind the optimized version of serial crc implementation.Now, how do I makeparallelimplementationof both the "optimized" and "long division" versions of serial crc implementation ?

author: tru
author_rank: Regular Contributor
timestamp: September 07, 2020, 03:50:08 pm
content: Quote from: promach on September 07, 2020, 09:15:22 amhttp://outputlogic.com/?p=158The parallel generation method described in the article works for both LFSR type.If you take my C code from an earlier post and put in your chosen USB CRC5 LFSR version (in C of course) or modify the existing LFSR code, then the resulting two matrices will give you the parallel code for that particular version.In fact the example in that article is the parallel code (with chosen input width of 4 bits parallel) of the optimised version (USB CRC5 LFSR):Code:Mout = Min ^ Min ^ Nin ^ NinMout = Min ^ NinMout = Min ^ Min ^ Min ^ Nin ^ Nin ^ NinMout = Min ^ Min ^ Nin ^ NinMout = Min ^ Min ^ NinWhere Mout = CRC, Min = Previous CRC, Nin = DataAbove can be rewritten as:Code:CRC = PrevCRC ^ PrevCRC ^ Data ^ DataCRC = PrevCRC ^ DataCRC = PrevCRC ^ PrevCRC ^ PrevCRC ^ Data ^ Data ^ DataCRC = PrevCRC ^ PrevCRC ^ Data ^ DataCRC = PrevCRC ^ PrevCRC ^ DataPerhaps if we look at a data input example using the LFSR optimised version:If we input 4 bit data into the LFSR:Initial seed value = 00000Data = 1010We get CRC = 00111*Note with this particular LFSR the data bits needs to be fed starting from the highest bit order.Try the same 4 bit input data with the above parallel code:Data = 1010 (Data = 1, Data = 0, Data = 1, Data = 0)Since we are at the start the PrevCRC is the initialisation value, let's use 00000 for easier calculation (but bear in mind that USB CRC5 uses 11111 as initial value).Code:CRC = 0 ^ 0 ^ 0 ^ 1 = 1CRC = 0 ^ 1 = 1CRC = 0 ^ 0 ^ 0 ^ 0 ^ 0 ^ 1 = 1CRC = 0 ^ 0 ^ 1 ^ 1 = 0CRC = 0 ^ 0 ^ 0 = 0As you can see it gives the same result of 00111.

author: promach
author_rank: Frequent Contributor
timestamp: September 08, 2020, 01:42:13 am
content: QuoteI was asking the reasoning or purpose behind having two matrices.

author: etherbladenet
author_rank: Newbie
timestamp: February 19, 2022, 02:46:00 am
content: I believe this video will be of help - visualisation of CRC and Parallel CRC on FPGA: