Add script to calculate LFSR values
Add a script to calculate the initial value to load into an LFSR based on how many cycles it should run for. The calculation is based on [1]. It takes advantage of the commutative and properties of exclusive or to recursively break down the number of steps. This lets us achieve an O(log(n)) runtime by caching our results. There's an alternative version of this algoritm which stores bits by value (0x100) instead of position (8). It's probably easier to do things that way in C or verilog, but this was more elegant in python. When calculating the number of cycles, we subtract one to get the number of cycles instead of the number of steps. [1] https://www.eevblog.com/forum/projects/algorithm-for-calculating-previous-states-of-lfsr-counters/msg2524395/#msg2524395 Signed-off-by: Sean Anderson <seanga2@gmail.com>
This commit is contained in:
parent
cd5a4b28a0
commit
c5df9ff5d5
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: AGPL-3.0-Only
|
||||
# Copyright (C) 2023 Sean Anderson <seanga2@gmail.com>
|
||||
|
||||
import functools
|
||||
import sys
|
||||
|
||||
def logbits(x):
|
||||
b = 0
|
||||
while x:
|
||||
if x & 1:
|
||||
yield b
|
||||
b += 1
|
||||
x >>= 1
|
||||
|
||||
@functools.cache
|
||||
def logstep_bit(taps, bit, logsteps):
|
||||
if not logsteps:
|
||||
return (bit < taps[0]) << (bit + 1) | (bit in taps)
|
||||
return logstep_state(taps, logstep_bit(taps, bit, logsteps - 1), logsteps - 1)
|
||||
|
||||
def logstep_state(taps, state, logsteps):
|
||||
lfsr = 0
|
||||
for bit in logbits(state):
|
||||
lfsr ^= logstep_bit(taps, bit, logsteps)
|
||||
return lfsr
|
||||
|
||||
def step_state(taps, state, steps):
|
||||
for logsteps in logbits(steps):
|
||||
state = logstep_state(taps, state, logsteps)
|
||||
return state
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print(f"""Usage: {sys.argv[0]} TAPS CYCLES...
|
||||
Calculate the starting state to use with the LFSR defined by TAPS (as an
|
||||
integer) which will go through CYCLES states before finishing.""", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
taps = tuple(reversed(tuple(logbits(int(sys.argv[1], base=0)))))
|
||||
max_cycles = (1 << taps[0] + 1) - 1
|
||||
for cycles in sys.argv[2:]:
|
||||
cycles = int(cycles, base=0)
|
||||
if cycles > max_cycles:
|
||||
print(f"Maximum cycles is {max_cycles:#x}, got {cycles:#x}",
|
||||
file=sys.stderr)
|
||||
elif cycles <= 0:
|
||||
print(f"Minimum cycles is 1, got {cycles}", file=sys.stderr)
|
||||
else:
|
||||
state = step_state(taps, max_cycles, max_cycles - cycles + 1)
|
||||
print(f"{taps[0] + 1}'h{state:0{(taps[0] + 4) // 4}x}")
|
Loading…
Reference in New Issue