#!/usr/bin/env python3
"""Generate expected LFSR output states for rng_sync module.

Computes the Galois LFSR sequence for the RTL default seed and writes
expected states to rng_input.hex (one 256-bit hex word per line).

The RTL uses a Galois LFSR with taps at bits 255, 253, 252, 247, 0.

On each valid_i pulse, the LFSR advances to the next state. valid_o
is asserted the following cycle with data_o = new state.
"""

import os

# Default seed from rng_sync.v
SEED = 0xDEADBEEFCAFEBABEFEEDFACEDECAFBAD1234567887654321ABCDEF010FEDCBA9

# Number of test vectors to generate
NUM_VECTORS = 32


def lfsr_advance(state):
    """
    Advance the 256-bit Galois LFSR by one step.

    RTL tap positions (0-indexed): 255, 253, 252, 247, 0.

    Algorithm (matching the RTL):
      1. feedback = state[0] (LSB)
      2. Shift right by 1: lfsr_next[i] = state[i+1] for i=0..254
      3. lfsr_next[255] = feedback
      4. XOR feedback into lfsr_next at tap-derived positions:
         - bit 254 (tap 255 after shift: 255 -> 254)
         - bit 252 (tap 253 after shift: 253 -> 252)
         - bit 251 (tap 252 after shift: 252 -> 251)
         - bit 246 (tap 247 after shift: 247 -> 246)
    """
    feedback = state & 1

    # Shift right by 1
    next_state = state >> 1

    # MSB gets feedback
    if feedback:
        next_state |= (1 << 255)

    # XOR feedback at tap-derived positions
    if feedback:
        next_state ^= (1 << 254)
        next_state ^= (1 << 252)
        next_state ^= (1 << 251)
        next_state ^= (1 << 246)

    return next_state


def format_hex_256(val):
    """Format 256-bit integer as 64-character hex string."""
    return f"{val:064x}"


def main():
    vectors_dir = os.path.join(os.path.dirname(__file__), "vectors")
    os.makedirs(vectors_dir, exist_ok=True)

    output_path = os.path.join(vectors_dir, "rng_input.hex")

    state = SEED
    with open(output_path, "w") as f:
        print(f"Seed: {format_hex_256(SEED)}")
        print(f"Generating {NUM_VECTORS} expected LFSR states...")
        print()

        for i in range(NUM_VECTORS):
            # Each valid_i advances the LFSR; the next state is what
            # appears on data_o when valid_o is asserted.
            state = lfsr_advance(state)
            f.write(format_hex_256(state) + "\n")
            print(f"[{i:3d}] step {i+1}: {format_hex_256(state)}")

    print(f"\nWrote {NUM_VECTORS} vectors to {output_path}")


if __name__ == "__main__":
    main()
