Last active
January 21, 2025 18:23
-
-
Save brabect1/9dca224918fbbebc9d7ecdb8e7b50795 to your computer and use it in GitHub Desktop.
LFSR based implementation of CRC-8-CCITT #crc #lfsr #SystemVerilog
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Copyright 2025 Tomas Brabec | |
Licensed under the Apache License, Version 2.0 (the "License"); | |
you may not use this file except in compliance with the License. | |
You may obtain a copy of the License at | |
http://www.apache.org/licenses/LICENSE-2.0 | |
Unless required by applicable law or agreed to in writing, software | |
distributed under the License is distributed on an "AS IS" BASIS, | |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
See the License for the specific language governing permissions and | |
limitations under the License. | |
Changelog: | |
2025, Jan, Tomas Brabec | |
- Created. | |
*/ | |
// CRC-8-CCITT: x^8 + x^2 + x + 1 | |
// | |
// +----------------------------------------------------------------+ | |
// | +-->NOT---> Data_out | | |
// | | | | |
// v | +--+--+--+--+--+--+ +--+ +--+ | | |
// +<--XOR------+---| 7| 6| 5| 4| 3| 2|<--XOR<--| 1|<--XOR<--| 0|<---+ +-- Serial_Input | |
// | +--+--+--+--+--+--+ ^ +--+ ^ +--+ | | |
// | | | | | |
// +---------------------------------------+------------+------------+ | |
// Fig.1. Principal schematic of CRC-CCITT computation block | |
// (so-called Galois form of LFSR) | |
// | |
// | |
// Output <--- XOR <-------------- Input_A | |
// ^ | |
// | ___ | |
// | / |---------- CE (Count Enable) | |
// +--( & | | |
// \ |---------- Input_B | |
// --- | |
// Fig.2. Schematic of modified XOR gate | |
// (Output=Input_A when CE=0 and the LFSR behaves like a simple shift register) | |
// | |
// Use the following link for calculating reference CRC: | |
// https://crccalc.com/?crc=00,%2078,%20f0&method=CRC-8/ROHC&datatype=hex&outtype=hex | |
/** | |
* Implements LFSR (Linear Feedback Shift Register) in Galois form implementing the | |
* CRC-8-CCITT with polynomial x^8+x^2+x+1. | |
* | |
* Serial data would come LSB first; e.g. 96h would come in as the following sequence of bits: | |
* 0 1 1 0 1 0 0 1. | |
* | |
* `se` (shift enable) signals valid input data. `ce` (count enable) signals when to calculate | |
* CRC and when to simply shift-in the serial input data. | |
* | |
* Serial data out is meant to shift-out the inverted value of CRC, LSB first, during the post | |
* computation LFSR reload (i.e. se=1 and ce=0). The bit stream can be simply concatenated to | |
* the input stream and to yield the magic constant in the validating CRC module. | |
* | |
* The parallel data out represents the LFSR value. Note that the CRC value is then bit-reverse | |
* of the LFSR value. | |
*/ | |
module crc_8_ccitt( | |
input logic clk, | |
input logic rst_n, | |
input logic din, | |
output logic dout, | |
output logic[7:0] lfsr, | |
input logic ce, // count enable | |
input logic se // shift enable (or data valid) | |
); | |
logic[7:0] lfsr_comb; | |
logic lfsr_in; | |
assign dout = ~lfsr[7]; | |
assign lfsr_in = (lfsr[7] & ce) ^ din; | |
assign lfsr_comb = {lfsr[6:0] ^ {5'd0, (ce & lfsr_in), (ce & lfsr_in)}, lfsr_in}; | |
always_ff @(posedge clk or negedge rst_n) begin | |
if (~rst_n) begin | |
lfsr <= 8'hFF; | |
end | |
else if (se) begin | |
lfsr <= lfsr_comb; | |
end | |
end | |
endmodule | |
module tb; | |
logic clk; | |
logic rst_n = 1'b1; | |
logic ce; | |
logic se; | |
logic din; | |
logic dout; | |
logic[7:0] lfsr_act; | |
logic[7:0] lfsr_chk; | |
crc_8_ccitt u_crc_act( | |
.clk, | |
.rst_n, | |
.ce, | |
.se, | |
.din, | |
.dout, | |
.lfsr(lfsr_act) | |
); | |
logic chkin; | |
assign chkin = (se & ~ce) ? dout : din; | |
crc_8_ccitt u_crc_chk( | |
.clk, | |
.rst_n, | |
.ce(se), | |
.se, | |
.din(chkin), | |
.dout(), | |
.lfsr(lfsr_chk) | |
); | |
initial begin | |
clk = 1'b0; | |
while (1) begin | |
#10ns; | |
clk = ~clk; | |
end | |
end | |
logic[7:0] chk_reg; | |
always_ff @(posedge clk) begin | |
if (se & ~ce) begin | |
chk_reg <= {chkin, chk_reg[7:1]}; | |
end | |
end | |
task reset; | |
rst_n = 1'b0; | |
repeat(3) @(negedge clk); | |
rst_n = 1'b1; | |
endtask | |
task calculate( | |
input logic[7:0] data[$] | |
); | |
automatic string s; | |
s = ""; | |
foreach(data[i]) begin | |
s = {s, i==0 ? "" : ", ", $sformatf("%2hh", data[i])}; | |
end | |
$display("\n%0s\ndata=%0s", "---------------", s); | |
@(posedge clk); #1; | |
se = 1; | |
ce = 1; | |
foreach(data[i]) begin | |
//for (int j=7; j >=0; j--) begin | |
for (int j=0; j < 8; j++) begin | |
din = data[i][j]; | |
@(posedge clk); #1; | |
end | |
end | |
ce = 0; | |
// Note: The CRC value is bit reversed of the LFSR value. That is, | |
// if LFSR is [n:0], then CRC value is [0:n]. | |
$display("\n act=%2hh\n chk=%2hh\n crc=%2hh\n~crc=%2hh", lfsr_act, lfsr_chk, {<<{lfsr_act}}, ~{<<{lfsr_act}}); | |
din = 1; | |
repeat($size(lfsr_act)) @(posedge clk); #1; | |
se = 0; | |
din = 0; | |
$display("\nact=%2hh\nchk=%2hh\nreg=%2hh", lfsr_act, lfsr_chk, chk_reg); | |
reset(); | |
repeat(16) @(negedge clk); | |
endtask | |
initial begin | |
automatic logic[7:0] data[$]; | |
din = 0; | |
se = 0; | |
ce = 0; | |
reset(); | |
data.delete(); | |
data.push_back(8'h00); | |
calculate(data); | |
data.delete(); | |
data.push_back(8'h11); | |
calculate(data); | |
data.delete(); | |
data.push_back(8'h88); | |
calculate(data); | |
data.delete(); | |
data.push_back(8'h88); | |
data.push_back(8'h11); | |
calculate(data); | |
data.delete(); | |
data.push_back(8'h11); | |
data.push_back(8'h88); | |
calculate(data); | |
// data.delete(); | |
// data.push_back(8'h00); | |
// data.push_back(8'he1); | |
// data.push_back(8'hf0); | |
// calculate(data); | |
// | |
// data.delete(); | |
// data.push_back(8'h00); | |
// data.push_back(8'hf0); | |
// data.push_back(8'he1); | |
// calculate(data); | |
// | |
// data.delete(); | |
// data.push_back(8'h00); | |
// data.push_back(8'h0f); | |
// data.push_back(8'h87); | |
// calculate(data); | |
data.delete(); | |
data.push_back(8'h00); | |
calculate(data); | |
data.delete(); | |
data.push_back(8'h00); | |
data.push_back(8'h87); | |
data.push_back(8'h0f); | |
calculate(data); | |
data.delete(); | |
data.push_back(8'h00); | |
data.push_back(8'h78); | |
data.push_back(8'hf0); | |
calculate(data); | |
repeat(16) @(negedge clk); | |
reset(); | |
$stop; | |
end | |
endmodule |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment