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:
Alex Forencich
2026-05-11 15:02:30 -07:00
parent ffb49f1e9c
commit 2063e47a4e
8 changed files with 443 additions and 81 deletions

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0 // SPDX-License-Identifier: CERN-OHL-S-2.0
/* /*
Copyright (c) 2016-2025 FPGA Ninja, LLC Copyright (c) 2016-2026 FPGA Ninja, LLC
Authors: Authors:
- Alex Forencich - Alex Forencich
@@ -31,7 +31,10 @@ module taxi_lfsr #
parameter DATA_W = 8, parameter DATA_W = 8,
// enable data input and output // enable data input and output
parameter logic DATA_IN_EN = 1'b1, 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, 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 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. 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: Settings for common LFSR/CRC implementations:
Name Configuration Length Polynomial Initial value Notes 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 // simulate shift register
if (LFSR_GALOIS) begin if (LFSR_GALOIS) begin
// Galois configuration // 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 // Shift state alone before shifting data
for (integer j = LFSR_W-1; j > 0; j = j - 1) begin if (STATE_SHIFT_PRE > 0) begin
lfsr_mask_state[j] = lfsr_mask_state[j-1]; // forward shift
lfsr_mask_data[j] = lfsr_mask_data[j-1]; for (integer i = 0; i < STATE_SHIFT_PRE; i = i + 1) begin
end // determine shift in value
for (integer j = DATA_W-1; j > 0; j = j - 1) begin // current value in last FF, XOR with input data bit (MSB first)
output_mask_state[j] = output_mask_state[j-1]; state_val = lfsr_mask_state[LFSR_W-1];
output_mask_data[j] = output_mask_data[j-1]; data_val = lfsr_mask_data[LFSR_W-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 // shift
for (integer j = 1; j < LFSR_W; j = j + 1) begin for (integer j = LFSR_W-1; j > 0; j = j - 1) begin
if (LFSR_POLY[j]) begin lfsr_mask_state[j] = lfsr_mask_state[j-1];
lfsr_mask_state[j] = lfsr_mask_state[j] ^ state_val; lfsr_mask_data[j] = lfsr_mask_data[j-1];
lfsr_mask_data[j] = lfsr_mask_data[j] ^ data_val;
end 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 end
end else begin end else begin
// Fibonacci configuration // 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 // Shift state alone before shifting data
for (integer j = 1; j < LFSR_W; j = j + 1) begin if (STATE_SHIFT_PRE > 0) begin
if (LFSR_POLY[j]) begin // forward shift
state_val = lfsr_mask_state[j-1] ^ state_val; for (integer i = 0; i < STATE_SHIFT_PRE; i = i + 1) begin
data_val = lfsr_mask_data[j-1] ^ data_val; // 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 end
end
// shift // Shift data
for (integer j = LFSR_W-1; j > 0; j = j - 1) begin if (DATA_IN_EN || DATA_OUT_EN) begin
lfsr_mask_state[j] = lfsr_mask_state[j-1]; for (data_mask = {1'b1, {DATA_W-1{1'b0}}}; data_mask != 0; data_mask = data_mask >> 1) begin
lfsr_mask_data[j] = lfsr_mask_data[j-1]; // 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 end
for (integer j = DATA_W-1; j > 0; j = j - 1) begin end
output_mask_state[j] = output_mask_state[j-1];
output_mask_data[j] = output_mask_data[j-1]; // 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 end
output_mask_state[0] = state_val; end else if (STATE_SHIFT_POST < 0) begin
output_mask_data[0] = data_val; // reverse shift
if (LFSR_FEED_FORWARD) begin for (integer i = 0; i < -STATE_SHIFT_POST; i = i + 1) begin
// only shift in new input data state_val = lfsr_mask_state[0];
state_val = '0; data_val = lfsr_mask_data[0];
data_val = data_mask;
// 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
lfsr_mask_state[0] = state_val;
lfsr_mask_data[0] = data_val;
end end
end end

View File

@@ -157,7 +157,9 @@ taxi_lfsr #(
.REVERSE(REVERSE), .REVERSE(REVERSE),
.DATA_W(DATA_W), .DATA_W(DATA_W),
.DATA_IN_EN(1'b1), .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 ( lfsr_inst (
.data_in(data_in), .data_in(data_in),

View File

@@ -164,7 +164,9 @@ taxi_lfsr #(
.REVERSE(REVERSE), .REVERSE(REVERSE),
.DATA_W(DATA_W), .DATA_W(DATA_W),
.DATA_IN_EN(SELF_SYNC), .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 ( lfsr_inst (
.data_in(SELF_SYNC ? data_in : '0), .data_in(SELF_SYNC ? data_in : '0),

View File

@@ -167,7 +167,9 @@ taxi_lfsr #(
.REVERSE(REVERSE), .REVERSE(REVERSE),
.DATA_W(DATA_W), .DATA_W(DATA_W),
.DATA_IN_EN(1'b1), .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 ( lfsr_inst (
.data_in(INVERT ? ~data_in : data_in), .data_in(INVERT ? ~data_in : data_in),

View File

@@ -161,7 +161,9 @@ taxi_lfsr #(
.REVERSE(REVERSE), .REVERSE(REVERSE),
.DATA_W(DATA_W), .DATA_W(DATA_W),
.DATA_IN_EN(1'b0), .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 ( lfsr_inst (
.data_in('0), .data_in('0),

View File

@@ -164,7 +164,9 @@ taxi_lfsr #(
.REVERSE(REVERSE), .REVERSE(REVERSE),
.DATA_W(DATA_W), .DATA_W(DATA_W),
.DATA_IN_EN(SELF_SYNC), .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 ( lfsr_inst (
.data_in(SELF_SYNC ? data_in : '0), .data_in(SELF_SYNC ? data_in : '0),

View File

@@ -37,6 +37,8 @@ export PARAM_REVERSE ?= "1'b1"
export PARAM_DATA_W ?= 8 export PARAM_DATA_W ?= 8
export PARAM_DATA_IN_EN ?= "1'b1" export PARAM_DATA_IN_EN ?= "1'b1"
export PARAM_DATA_OUT_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) ifeq ($(SIM), icarus)
PLUSARGS += -fst PLUSARGS += -fst

View File

@@ -2,7 +2,7 @@
# SPDX-License-Identifier: CERN-OHL-S-2.0 # SPDX-License-Identifier: CERN-OHL-S-2.0
""" """
Copyright (c) 2023-2025 FPGA Ninja, LLC Copyright (c) 2023-2026 FPGA Ninja, LLC
Authors: Authors:
- Alex Forencich - Alex Forencich
@@ -37,8 +37,40 @@ def chunks(lst, n, padvalue=None):
return itertools.zip_longest(*[iter(lst)]*n, fillvalue=padvalue) return itertools.zip_longest(*[iter(lst)]*n, fillvalue=padvalue)
def crc32(data): def crc32(data, crc=0xffffffff, poly=0xedb88320):
return zlib.crc32(data) & 0xffffffff # 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): def crc32c(data, crc=0xffffffff, poly=0x82f63b78):
@@ -149,12 +181,65 @@ async def run_test_prbs(dut, ref_prbs):
await Timer(10, 'ns') 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 getattr(cocotb, 'top', None) is not None:
if cocotb.top.LFSR_POLY.value == 0x4c11db7: if cocotb.top.LFSR_POLY.value == 0x4c11db7:
factory = TestFactory(run_test_crc) if cocotb.top.STATE_SHIFT_PRE.value == 0:
factory.add_option("ref_crc", [crc32]) factory = TestFactory(run_test_crc)
factory.generate_tests() 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: if cocotb.top.LFSR_POLY.value == 0x1edc6f41:
factory = TestFactory(run_test_crc) factory = TestFactory(run_test_crc)
@@ -191,17 +276,19 @@ def process_f_files(files):
return list(lst.values()) return list(lst.values())
@pytest.mark.parametrize(("lfsr_w", "lfsr_poly", "lfsr_galois", "reverse", "data_w"), [ @pytest.mark.parametrize(("lfsr_w", "lfsr_poly", "lfsr_galois", "reverse", "data_w", "data_shift", "pre_shift"), [
(32, "32'h4c11db7", 1, 1, 8), (32, "32'h4c11db7", 1, 1, 8, 1, 0),
(32, "32'h4c11db7", 1, 1, 64), (32, "32'h4c11db7", 1, 1, 64, 1, 0),
(32, "32'h1edc6f41", 1, 1, 8), (32, "32'h4c11db7", 1, 1, 64, 0, 8),
(32, "32'h1edc6f41", 1, 1, 64), (32, "32'h4c11db7", 1, 1, 64, 0, -8),
(9, "9'h021", 0, 0, 8), (32, "32'h1edc6f41", 1, 1, 8, 1, 0),
(9, "9'h021", 0, 0, 64), (32, "32'h1edc6f41", 1, 1, 64, 1, 0),
(31, "31'h10000001", 0, 0, 8), (9, "9'h021", 0, 0, 8, 1, 0),
(31, "31'h10000001", 0, 0, 64), (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" dut = "taxi_lfsr"
module = os.path.splitext(os.path.basename(__file__))[0] module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = dut 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['LFSR_FEED_FORWARD'] = "1'b0"
parameters['REVERSE'] = f"1'b{reverse}" parameters['REVERSE'] = f"1'b{reverse}"
parameters['DATA_W'] = data_w parameters['DATA_W'] = data_w
parameters['DATA_IN_EN'] = "1'b1" parameters['DATA_IN_EN'] = f"1'b{data_shift}"
parameters['DATA_OUT_EN'] = "1'b1" 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()} extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}