mirror of
https://github.com/fpganinja/taxi.git
synced 2026-05-17 21:10:55 -07:00
lfsr: Update LFSR module to support shifting the state before/after shifting the data, including backwards shifts
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: CERN-OHL-S-2.0
|
||||
/*
|
||||
|
||||
Copyright (c) 2016-2025 FPGA Ninja, LLC
|
||||
Copyright (c) 2016-2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
@@ -31,7 +31,10 @@ module taxi_lfsr #
|
||||
parameter DATA_W = 8,
|
||||
// enable data input and output
|
||||
parameter logic DATA_IN_EN = 1'b1,
|
||||
parameter logic DATA_OUT_EN = 1'b1
|
||||
parameter logic DATA_OUT_EN = 1'b1,
|
||||
// shift control
|
||||
parameter STATE_SHIFT_PRE = 0,
|
||||
parameter STATE_SHIFT_POST = 0
|
||||
)
|
||||
(
|
||||
input wire logic [DATA_W-1:0] data_in,
|
||||
@@ -150,6 +153,21 @@ Specify width of input and output data bus. The module will perform one shift p
|
||||
data bit, so if the input data bus is not required tie data_in to zero and set DATA_W
|
||||
to the required number of shifts per clock cycle.
|
||||
|
||||
DATA_IN_EN, DATA_OUT_EN
|
||||
|
||||
Enable data input and/or output ports. Useful for CRC computation where the
|
||||
data shifted out of the register is not used, or PRBS generation where no data
|
||||
is shifted in to the register. Disabling unused inputs and outputs will
|
||||
increase simulation speed.
|
||||
|
||||
STATE_SHIFT_PRE, STATE_SHIFT_POST
|
||||
|
||||
Shift the state before/after shifting the data. Useful for either shifting the
|
||||
state only, or for performing a split CRC computation on a wide/segmented data
|
||||
bus. Positive shift values are equivalent to extending the data input port with
|
||||
zeros. Negative shift amounts shift the state backwards, useful for removing
|
||||
zero padding and similar.
|
||||
|
||||
Settings for common LFSR/CRC implementations:
|
||||
|
||||
Name Configuration Length Polynomial Initial value Notes
|
||||
@@ -210,75 +228,318 @@ function [OUT_W-1:0][IN_W-1:0] lfsr_mask();
|
||||
// simulate shift register
|
||||
if (LFSR_GALOIS) begin
|
||||
// Galois configuration
|
||||
for (data_mask = {1'b1, {DATA_W-1{1'b0}}}; data_mask != 0; data_mask = data_mask >> 1) begin
|
||||
// determine shift in value
|
||||
// current value in last FF, XOR with input data bit (MSB first)
|
||||
state_val = lfsr_mask_state[LFSR_W-1];
|
||||
data_val = lfsr_mask_data[LFSR_W-1];
|
||||
data_val = data_val ^ data_mask;
|
||||
|
||||
// shift
|
||||
for (integer j = LFSR_W-1; j > 0; j = j - 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j-1];
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j-1];
|
||||
end
|
||||
for (integer j = DATA_W-1; j > 0; j = j - 1) begin
|
||||
output_mask_state[j] = output_mask_state[j-1];
|
||||
output_mask_data[j] = output_mask_data[j-1];
|
||||
end
|
||||
output_mask_state[0] = state_val;
|
||||
output_mask_data[0] = data_val;
|
||||
if (LFSR_FEED_FORWARD) begin
|
||||
// only shift in new input data
|
||||
state_val = '0;
|
||||
data_val = data_mask;
|
||||
end
|
||||
lfsr_mask_state[0] = state_val;
|
||||
lfsr_mask_data[0] = data_val;
|
||||
// Shift state alone before shifting data
|
||||
if (STATE_SHIFT_PRE > 0) begin
|
||||
// forward shift
|
||||
for (integer i = 0; i < STATE_SHIFT_PRE; i = i + 1) begin
|
||||
// determine shift in value
|
||||
// current value in last FF, XOR with input data bit (MSB first)
|
||||
state_val = lfsr_mask_state[LFSR_W-1];
|
||||
data_val = lfsr_mask_data[LFSR_W-1];
|
||||
|
||||
// add XOR inputs at correct indicies
|
||||
for (integer j = 1; j < LFSR_W; j = j + 1) begin
|
||||
if (LFSR_POLY[j]) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j] ^ state_val;
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j] ^ data_val;
|
||||
// shift
|
||||
for (integer j = LFSR_W-1; j > 0; j = j - 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j-1];
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j-1];
|
||||
end
|
||||
if (LFSR_FEED_FORWARD) begin
|
||||
// only shift in new input data
|
||||
state_val = '0;
|
||||
data_val = '0;
|
||||
end
|
||||
lfsr_mask_state[0] = state_val;
|
||||
lfsr_mask_data[0] = data_val;
|
||||
|
||||
// add XOR inputs at correct indicies
|
||||
for (integer j = 1; j < LFSR_W; j = j + 1) begin
|
||||
if (LFSR_POLY[j]) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j] ^ state_val;
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j] ^ data_val;
|
||||
end
|
||||
end
|
||||
end
|
||||
end else if (STATE_SHIFT_PRE < 0) begin
|
||||
// reverse shift
|
||||
for (integer i = 0; i < -STATE_SHIFT_PRE; i = i + 1) begin
|
||||
state_val = lfsr_mask_state[0];
|
||||
data_val = lfsr_mask_data[0];
|
||||
|
||||
// add XOR inputs at correct indicies
|
||||
for (integer j = 1; j < LFSR_W; j = j + 1) begin
|
||||
if (LFSR_POLY[j]) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j] ^ state_val;
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j] ^ data_val;
|
||||
end
|
||||
end
|
||||
|
||||
// shift
|
||||
for (integer j = 0; j < LFSR_W-1; j = j + 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j+1];
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j+1];
|
||||
end
|
||||
if (LFSR_FEED_FORWARD) begin
|
||||
// only shift in new input data
|
||||
state_val = '0;
|
||||
data_val = '0;
|
||||
end
|
||||
lfsr_mask_state[LFSR_W-1] = state_val;
|
||||
lfsr_mask_data[LFSR_W-1] = data_val;
|
||||
end
|
||||
end
|
||||
|
||||
// Shift data
|
||||
if (DATA_IN_EN || DATA_OUT_EN) begin
|
||||
for (data_mask = {1'b1, {DATA_W-1{1'b0}}}; data_mask != 0; data_mask = data_mask >> 1) begin
|
||||
// determine shift in value
|
||||
// current value in last FF, XOR with input data bit (MSB first)
|
||||
state_val = lfsr_mask_state[LFSR_W-1];
|
||||
data_val = lfsr_mask_data[LFSR_W-1];
|
||||
data_val = data_val ^ data_mask;
|
||||
|
||||
// shift
|
||||
for (integer j = LFSR_W-1; j > 0; j = j - 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j-1];
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j-1];
|
||||
end
|
||||
for (integer j = DATA_W-1; j > 0; j = j - 1) begin
|
||||
output_mask_state[j] = output_mask_state[j-1];
|
||||
output_mask_data[j] = output_mask_data[j-1];
|
||||
end
|
||||
output_mask_state[0] = state_val;
|
||||
output_mask_data[0] = data_val;
|
||||
if (LFSR_FEED_FORWARD) begin
|
||||
// only shift in new input data
|
||||
state_val = '0;
|
||||
data_val = data_mask;
|
||||
end
|
||||
lfsr_mask_state[0] = state_val;
|
||||
lfsr_mask_data[0] = data_val;
|
||||
|
||||
// add XOR inputs at correct indicies
|
||||
for (integer j = 1; j < LFSR_W; j = j + 1) begin
|
||||
if (LFSR_POLY[j]) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j] ^ state_val;
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j] ^ data_val;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Shift state alone after shifting data
|
||||
if (STATE_SHIFT_POST > 0) begin
|
||||
// forward shift
|
||||
for (integer i = 0; i < STATE_SHIFT_POST; i = i + 1) begin
|
||||
// determine shift in value
|
||||
// current value in last FF, XOR with input data bit (MSB first)
|
||||
state_val = lfsr_mask_state[LFSR_W-1];
|
||||
data_val = lfsr_mask_data[LFSR_W-1];
|
||||
|
||||
// shift
|
||||
for (integer j = LFSR_W-1; j > 0; j = j - 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j-1];
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j-1];
|
||||
end
|
||||
if (LFSR_FEED_FORWARD) begin
|
||||
// only shift in new input data
|
||||
state_val = '0;
|
||||
data_val = '0;
|
||||
end
|
||||
lfsr_mask_state[0] = state_val;
|
||||
lfsr_mask_data[0] = data_val;
|
||||
|
||||
// add XOR inputs at correct indicies
|
||||
for (integer j = 1; j < LFSR_W; j = j + 1) begin
|
||||
if (LFSR_POLY[j]) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j] ^ state_val;
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j] ^ data_val;
|
||||
end
|
||||
end
|
||||
end
|
||||
end else if (STATE_SHIFT_POST < 0) begin
|
||||
// reverse shift
|
||||
for (integer i = 0; i < -STATE_SHIFT_POST; i = i + 1) begin
|
||||
state_val = lfsr_mask_state[0];
|
||||
data_val = lfsr_mask_data[0];
|
||||
|
||||
// add XOR inputs at correct indicies
|
||||
for (integer j = 1; j < LFSR_W; j = j + 1) begin
|
||||
if (LFSR_POLY[j]) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j] ^ state_val;
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j] ^ data_val;
|
||||
end
|
||||
end
|
||||
|
||||
// shift
|
||||
for (integer j = 0; j < LFSR_W-1; j = j + 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j+1];
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j+1];
|
||||
end
|
||||
if (LFSR_FEED_FORWARD) begin
|
||||
// only shift in new input data
|
||||
state_val = '0;
|
||||
data_val = '0;
|
||||
end
|
||||
lfsr_mask_state[LFSR_W-1] = state_val;
|
||||
lfsr_mask_data[LFSR_W-1] = data_val;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
// Fibonacci configuration
|
||||
for (data_mask = {1'b1, {DATA_W-1{1'b0}}}; data_mask != 0; data_mask = data_mask >> 1) begin
|
||||
// determine shift in value
|
||||
// current value in last FF, XOR with input data bit (MSB first)
|
||||
state_val = lfsr_mask_state[LFSR_W-1];
|
||||
data_val = lfsr_mask_data[LFSR_W-1];
|
||||
data_val = data_val ^ data_mask;
|
||||
|
||||
// add XOR inputs from correct indicies
|
||||
for (integer j = 1; j < LFSR_W; j = j + 1) begin
|
||||
if (LFSR_POLY[j]) begin
|
||||
state_val = lfsr_mask_state[j-1] ^ state_val;
|
||||
data_val = lfsr_mask_data[j-1] ^ data_val;
|
||||
// Shift state alone before shifting data
|
||||
if (STATE_SHIFT_PRE > 0) begin
|
||||
// forward shift
|
||||
for (integer i = 0; i < STATE_SHIFT_PRE; i = i + 1) begin
|
||||
// determine shift in value
|
||||
// current value in last FF, XOR with input data bit (MSB first)
|
||||
state_val = lfsr_mask_state[LFSR_W-1];
|
||||
data_val = lfsr_mask_data[LFSR_W-1];
|
||||
|
||||
// add XOR inputs from correct indicies
|
||||
for (integer j = 1; j < LFSR_W; j = j + 1) begin
|
||||
if (LFSR_POLY[j]) begin
|
||||
state_val = lfsr_mask_state[j-1] ^ state_val;
|
||||
data_val = lfsr_mask_data[j-1] ^ data_val;
|
||||
end
|
||||
end
|
||||
|
||||
// shift
|
||||
for (integer j = LFSR_W-1; j > 0; j = j - 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j-1];
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j-1];
|
||||
end
|
||||
if (LFSR_FEED_FORWARD) begin
|
||||
// only shift in new input data
|
||||
state_val = '0;
|
||||
data_val = '0;
|
||||
end
|
||||
lfsr_mask_state[0] = state_val;
|
||||
lfsr_mask_data[0] = data_val;
|
||||
end
|
||||
end else if (STATE_SHIFT_PRE < 0) begin
|
||||
// reverse shift
|
||||
for (integer i = 0; i < -STATE_SHIFT_PRE; i = i + 1) begin
|
||||
state_val = lfsr_mask_state[0];
|
||||
data_val = lfsr_mask_data[0];
|
||||
|
||||
// shift
|
||||
for (integer j = 0; j < LFSR_W-1; j = j + 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j+1];
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j+1];
|
||||
end
|
||||
if (LFSR_FEED_FORWARD) begin
|
||||
// only shift in new input data
|
||||
state_val = '0;
|
||||
data_val = '0;
|
||||
end
|
||||
lfsr_mask_state[LFSR_W-1] = state_val;
|
||||
lfsr_mask_data[LFSR_W-1] = data_val;
|
||||
|
||||
// add XOR inputs from correct indicies
|
||||
for (integer j = 1; j < LFSR_W; j = j + 1) begin
|
||||
if (LFSR_POLY[j]) begin
|
||||
state_val = lfsr_mask_state[j-1] ^ state_val;
|
||||
data_val = lfsr_mask_data[j-1] ^ data_val;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// shift
|
||||
for (integer j = LFSR_W-1; j > 0; j = j - 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j-1];
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j-1];
|
||||
// Shift data
|
||||
if (DATA_IN_EN || DATA_OUT_EN) begin
|
||||
for (data_mask = {1'b1, {DATA_W-1{1'b0}}}; data_mask != 0; data_mask = data_mask >> 1) begin
|
||||
// determine shift in value
|
||||
// current value in last FF, XOR with input data bit (MSB first)
|
||||
state_val = lfsr_mask_state[LFSR_W-1];
|
||||
data_val = lfsr_mask_data[LFSR_W-1];
|
||||
data_val = data_val ^ data_mask;
|
||||
|
||||
// add XOR inputs from correct indicies
|
||||
for (integer j = 1; j < LFSR_W; j = j + 1) begin
|
||||
if (LFSR_POLY[j]) begin
|
||||
state_val = lfsr_mask_state[j-1] ^ state_val;
|
||||
data_val = lfsr_mask_data[j-1] ^ data_val;
|
||||
end
|
||||
end
|
||||
|
||||
// shift
|
||||
for (integer j = LFSR_W-1; j > 0; j = j - 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j-1];
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j-1];
|
||||
end
|
||||
for (integer j = DATA_W-1; j > 0; j = j - 1) begin
|
||||
output_mask_state[j] = output_mask_state[j-1];
|
||||
output_mask_data[j] = output_mask_data[j-1];
|
||||
end
|
||||
output_mask_state[0] = state_val;
|
||||
output_mask_data[0] = data_val;
|
||||
if (LFSR_FEED_FORWARD) begin
|
||||
// only shift in new input data
|
||||
state_val = '0;
|
||||
data_val = data_mask;
|
||||
end
|
||||
lfsr_mask_state[0] = state_val;
|
||||
lfsr_mask_data[0] = data_val;
|
||||
end
|
||||
for (integer j = DATA_W-1; j > 0; j = j - 1) begin
|
||||
output_mask_state[j] = output_mask_state[j-1];
|
||||
output_mask_data[j] = output_mask_data[j-1];
|
||||
end
|
||||
|
||||
// Shift state alone after shifting data
|
||||
if (STATE_SHIFT_POST > 0) begin
|
||||
for (integer i = 0; i < STATE_SHIFT_POST; i = i + 1) begin
|
||||
// determine shift in value
|
||||
// current value in last FF, XOR with input data bit (MSB first)
|
||||
state_val = lfsr_mask_state[LFSR_W-1];
|
||||
data_val = lfsr_mask_data[LFSR_W-1];
|
||||
|
||||
// add XOR inputs from correct indicies
|
||||
for (integer j = 1; j < LFSR_W; j = j + 1) begin
|
||||
if (LFSR_POLY[j]) begin
|
||||
state_val = lfsr_mask_state[j-1] ^ state_val;
|
||||
data_val = lfsr_mask_data[j-1] ^ data_val;
|
||||
end
|
||||
end
|
||||
|
||||
// shift
|
||||
for (integer j = LFSR_W-1; j > 0; j = j - 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j-1];
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j-1];
|
||||
end
|
||||
if (LFSR_FEED_FORWARD) begin
|
||||
// only shift in new input data
|
||||
state_val = '0;
|
||||
data_val = '0;
|
||||
end
|
||||
lfsr_mask_state[0] = state_val;
|
||||
lfsr_mask_data[0] = data_val;
|
||||
end
|
||||
output_mask_state[0] = state_val;
|
||||
output_mask_data[0] = data_val;
|
||||
if (LFSR_FEED_FORWARD) begin
|
||||
// only shift in new input data
|
||||
state_val = '0;
|
||||
data_val = data_mask;
|
||||
end else if (STATE_SHIFT_POST < 0) begin
|
||||
// reverse shift
|
||||
for (integer i = 0; i < -STATE_SHIFT_POST; i = i + 1) begin
|
||||
state_val = lfsr_mask_state[0];
|
||||
data_val = lfsr_mask_data[0];
|
||||
|
||||
// shift
|
||||
for (integer j = 0; j < LFSR_W-1; j = j + 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j+1];
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j+1];
|
||||
end
|
||||
if (LFSR_FEED_FORWARD) begin
|
||||
// only shift in new input data
|
||||
state_val = '0;
|
||||
data_val = '0;
|
||||
end
|
||||
lfsr_mask_state[LFSR_W-1] = state_val;
|
||||
lfsr_mask_data[LFSR_W-1] = data_val;
|
||||
|
||||
// add XOR inputs from correct indicies
|
||||
for (integer j = 1; j < LFSR_W; j = j + 1) begin
|
||||
if (LFSR_POLY[j]) begin
|
||||
state_val = lfsr_mask_state[j-1] ^ state_val;
|
||||
data_val = lfsr_mask_data[j-1] ^ data_val;
|
||||
end
|
||||
end
|
||||
end
|
||||
lfsr_mask_state[0] = state_val;
|
||||
lfsr_mask_data[0] = data_val;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ DATA_W
|
||||
|
||||
Specify width of input data bus. The module will perform one shift per input data bit,
|
||||
so if the input data bus is not required tie data_in to zero and set DATA_W to the
|
||||
required number of shifts per clock cycle.
|
||||
required number of shifts per clock cycle.
|
||||
|
||||
Settings for common LFSR/CRC implementations:
|
||||
|
||||
@@ -157,7 +157,9 @@ taxi_lfsr #(
|
||||
.REVERSE(REVERSE),
|
||||
.DATA_W(DATA_W),
|
||||
.DATA_IN_EN(1'b1),
|
||||
.DATA_OUT_EN(1'b0)
|
||||
.DATA_OUT_EN(1'b0),
|
||||
.STATE_SHIFT_PRE(0),
|
||||
.STATE_SHIFT_POST(0)
|
||||
)
|
||||
lfsr_inst (
|
||||
.data_in(data_in),
|
||||
|
||||
@@ -164,7 +164,9 @@ taxi_lfsr #(
|
||||
.REVERSE(REVERSE),
|
||||
.DATA_W(DATA_W),
|
||||
.DATA_IN_EN(SELF_SYNC),
|
||||
.DATA_OUT_EN(1'b1)
|
||||
.DATA_OUT_EN(1'b1),
|
||||
.STATE_SHIFT_PRE(0),
|
||||
.STATE_SHIFT_POST(0)
|
||||
)
|
||||
lfsr_inst (
|
||||
.data_in(SELF_SYNC ? data_in : '0),
|
||||
|
||||
@@ -167,7 +167,9 @@ taxi_lfsr #(
|
||||
.REVERSE(REVERSE),
|
||||
.DATA_W(DATA_W),
|
||||
.DATA_IN_EN(1'b1),
|
||||
.DATA_OUT_EN(1'b1)
|
||||
.DATA_OUT_EN(1'b1),
|
||||
.STATE_SHIFT_PRE(0),
|
||||
.STATE_SHIFT_POST(0)
|
||||
)
|
||||
lfsr_inst (
|
||||
.data_in(INVERT ? ~data_in : data_in),
|
||||
|
||||
@@ -161,7 +161,9 @@ taxi_lfsr #(
|
||||
.REVERSE(REVERSE),
|
||||
.DATA_W(DATA_W),
|
||||
.DATA_IN_EN(1'b0),
|
||||
.DATA_OUT_EN(1'b1)
|
||||
.DATA_OUT_EN(1'b1),
|
||||
.STATE_SHIFT_PRE(0),
|
||||
.STATE_SHIFT_POST(0)
|
||||
)
|
||||
lfsr_inst (
|
||||
.data_in('0),
|
||||
|
||||
@@ -164,7 +164,9 @@ taxi_lfsr #(
|
||||
.REVERSE(REVERSE),
|
||||
.DATA_W(DATA_W),
|
||||
.DATA_IN_EN(SELF_SYNC),
|
||||
.DATA_OUT_EN(1'b1)
|
||||
.DATA_OUT_EN(1'b1),
|
||||
.STATE_SHIFT_PRE(0),
|
||||
.STATE_SHIFT_POST(0)
|
||||
)
|
||||
lfsr_inst (
|
||||
.data_in(SELF_SYNC ? data_in : '0),
|
||||
|
||||
@@ -37,6 +37,8 @@ export PARAM_REVERSE ?= "1'b1"
|
||||
export PARAM_DATA_W ?= 8
|
||||
export PARAM_DATA_IN_EN ?= "1'b1"
|
||||
export PARAM_DATA_OUT_EN ?= "1'b1"
|
||||
export PARAM_STATE_SHIFT_PRE ?= 0
|
||||
export PARAM_STATE_SHIFT_POST ?= 0
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# SPDX-License-Identifier: CERN-OHL-S-2.0
|
||||
"""
|
||||
|
||||
Copyright (c) 2023-2025 FPGA Ninja, LLC
|
||||
Copyright (c) 2023-2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
@@ -37,8 +37,40 @@ def chunks(lst, n, padvalue=None):
|
||||
return itertools.zip_longest(*[iter(lst)]*n, fillvalue=padvalue)
|
||||
|
||||
|
||||
def crc32(data):
|
||||
return zlib.crc32(data) & 0xffffffff
|
||||
def crc32(data, crc=0xffffffff, poly=0xedb88320):
|
||||
# return zlib.crc32(data) & 0xffffffff
|
||||
for d in data:
|
||||
crc = crc ^ d
|
||||
for bit in range(0, 8):
|
||||
if crc & 1:
|
||||
crc = (crc >> 1) ^ poly
|
||||
else:
|
||||
crc = crc >> 1
|
||||
return ~crc & 0xffffffff
|
||||
|
||||
|
||||
def crc32_shift(crc, count, poly=0xedb88320):
|
||||
crc = ~crc & 0xffffffff
|
||||
|
||||
if count > 0:
|
||||
# shift forwards
|
||||
for i in range(count):
|
||||
if crc & 1:
|
||||
crc = (crc >> 1) ^ poly
|
||||
else:
|
||||
crc = crc >> 1
|
||||
|
||||
elif count < 0:
|
||||
# shift backwards
|
||||
for i in range(-count):
|
||||
if crc & 0x80000000:
|
||||
crc ^= poly
|
||||
crc = (crc << 1) | 1
|
||||
else:
|
||||
crc = crc << 1
|
||||
crc = crc & 0xffffffff
|
||||
|
||||
return ~crc & 0xffffffff
|
||||
|
||||
|
||||
def crc32c(data, crc=0xffffffff, poly=0x82f63b78):
|
||||
@@ -149,12 +181,65 @@ async def run_test_prbs(dut, ref_prbs):
|
||||
await Timer(10, 'ns')
|
||||
|
||||
|
||||
async def run_test_shift_crc(dut):
|
||||
|
||||
data_width = len(dut.data_in)
|
||||
byte_lanes = data_width // 8
|
||||
|
||||
state_width = len(dut.state_in)
|
||||
state_mask = 2**state_width-1
|
||||
|
||||
shift = int(dut.STATE_SHIFT_PRE.value)
|
||||
if shift > 0 and shift & 0x80000000:
|
||||
shift -= 0x100000000
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await Timer(10, 'ns')
|
||||
|
||||
val = 0x12345678
|
||||
|
||||
dut.state_in.value = ~val & state_mask
|
||||
dut.data_in.value = 0
|
||||
await Timer(10, 'ns')
|
||||
|
||||
crc = ~int(dut.state_out.value) & state_mask
|
||||
ref = crc32_shift(val, shift)
|
||||
|
||||
tb.log.info("Shifted CRC: 0x%x (ref: 0x%x)", crc, ref)
|
||||
|
||||
assert crc == ref
|
||||
|
||||
await Timer(10, 'ns')
|
||||
|
||||
for k in range(10):
|
||||
|
||||
val = crc32(bytearray(k))
|
||||
|
||||
dut.state_in.value = ~val & state_mask
|
||||
dut.data_in.value = 0
|
||||
await Timer(10, 'ns')
|
||||
|
||||
crc = ~int(dut.state_out.value) & state_mask
|
||||
ref = crc32_shift(val, shift)
|
||||
|
||||
tb.log.info("Shifted CRC: 0x%x (ref: 0x%x)", crc, ref)
|
||||
|
||||
assert crc == ref
|
||||
|
||||
await Timer(10, 'ns')
|
||||
|
||||
|
||||
if getattr(cocotb, 'top', None) is not None:
|
||||
|
||||
if cocotb.top.LFSR_POLY.value == 0x4c11db7:
|
||||
factory = TestFactory(run_test_crc)
|
||||
factory.add_option("ref_crc", [crc32])
|
||||
factory.generate_tests()
|
||||
if cocotb.top.STATE_SHIFT_PRE.value == 0:
|
||||
factory = TestFactory(run_test_crc)
|
||||
factory.add_option("ref_crc", [crc32])
|
||||
factory.generate_tests()
|
||||
else:
|
||||
factory = TestFactory(run_test_shift_crc)
|
||||
factory.generate_tests()
|
||||
|
||||
if cocotb.top.LFSR_POLY.value == 0x1edc6f41:
|
||||
factory = TestFactory(run_test_crc)
|
||||
@@ -191,17 +276,19 @@ def process_f_files(files):
|
||||
return list(lst.values())
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("lfsr_w", "lfsr_poly", "lfsr_galois", "reverse", "data_w"), [
|
||||
(32, "32'h4c11db7", 1, 1, 8),
|
||||
(32, "32'h4c11db7", 1, 1, 64),
|
||||
(32, "32'h1edc6f41", 1, 1, 8),
|
||||
(32, "32'h1edc6f41", 1, 1, 64),
|
||||
(9, "9'h021", 0, 0, 8),
|
||||
(9, "9'h021", 0, 0, 64),
|
||||
(31, "31'h10000001", 0, 0, 8),
|
||||
(31, "31'h10000001", 0, 0, 64),
|
||||
@pytest.mark.parametrize(("lfsr_w", "lfsr_poly", "lfsr_galois", "reverse", "data_w", "data_shift", "pre_shift"), [
|
||||
(32, "32'h4c11db7", 1, 1, 8, 1, 0),
|
||||
(32, "32'h4c11db7", 1, 1, 64, 1, 0),
|
||||
(32, "32'h4c11db7", 1, 1, 64, 0, 8),
|
||||
(32, "32'h4c11db7", 1, 1, 64, 0, -8),
|
||||
(32, "32'h1edc6f41", 1, 1, 8, 1, 0),
|
||||
(32, "32'h1edc6f41", 1, 1, 64, 1, 0),
|
||||
(9, "9'h021", 0, 0, 8, 1, 0),
|
||||
(9, "9'h021", 0, 0, 64, 1, 0),
|
||||
(31, "31'h10000001", 0, 0, 8, 1, 0),
|
||||
(31, "31'h10000001", 0, 0, 64, 1, 0),
|
||||
])
|
||||
def test_taxi_lfsr(request, lfsr_w, lfsr_poly, lfsr_galois, reverse, data_w):
|
||||
def test_taxi_lfsr(request, lfsr_w, lfsr_poly, lfsr_galois, reverse, data_w, data_shift, pre_shift):
|
||||
dut = "taxi_lfsr"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
@@ -220,8 +307,10 @@ def test_taxi_lfsr(request, lfsr_w, lfsr_poly, lfsr_galois, reverse, data_w):
|
||||
parameters['LFSR_FEED_FORWARD'] = "1'b0"
|
||||
parameters['REVERSE'] = f"1'b{reverse}"
|
||||
parameters['DATA_W'] = data_w
|
||||
parameters['DATA_IN_EN'] = "1'b1"
|
||||
parameters['DATA_OUT_EN'] = "1'b1"
|
||||
parameters['DATA_IN_EN'] = f"1'b{data_shift}"
|
||||
parameters['DATA_OUT_EN'] = f"1'b{data_shift}"
|
||||
parameters['STATE_SHIFT_PRE'] = pre_shift
|
||||
parameters['STATE_SHIFT_POST'] = 0
|
||||
|
||||
extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user