#!/usr/bin/env python3
"""gen_vectors.py — Generate BRAM test vectors for tb_storage_xsim.v

Vector format (64 bits = 16 hex chars per line):
  bit [63]     : module (0=s_bram, 1=sd_bram)
  bit [62]     : cmd    (0=write, 1=read-verify)
  bits [61:56] : addr   (6-bit address)
  bits [55:32] : reserved (zeros)
  bits [31:0]  : data   (write data / expected read data)

Output: vectors/storage_input.hex
"""

import os

VECTORS_DIR = os.path.join(os.path.dirname(__file__), "vectors")
OUTPUT_FILE = os.path.join(VECTORS_DIR, "storage_input.hex")

# Module selects
S_BRAM  = 0  # bit 63 = 0
SD_BRAM = 1  # bit 63 = 1

# Commands
CMD_WRITE = 0  # bit 62 = 0
CMD_READ  = 1  # bit 62 = 1

def encode(module: int, cmd: int, addr: int, data: int) -> int:
    """Pack module, cmd, addr, data into a 64-bit test vector word."""
    word = 0
    word |= (module & 0x1) << 63
    word |= (cmd    & 0x1) << 62
    word |= (addr   & 0x3F) << 56   # 6-bit addr in bits 61:56
    # bits 55:32 reserved (zero)
    word |= (data   & 0xFFFF_FFFF)   # bits 31:0
    return word


def main():
    os.makedirs(VECTORS_DIR, exist_ok=True)

    vectors = []

    # ── s_bram writes ──
    vectors.append(encode(S_BRAM, CMD_WRITE, 0,  0x00000000))   # all-zeros edge
    vectors.append(encode(S_BRAM, CMD_WRITE, 1,  0x11111111))
    vectors.append(encode(S_BRAM, CMD_WRITE, 2,  0x22222222))
    vectors.append(encode(S_BRAM, CMD_WRITE, 10, 0xAAAAAAAA))
    vectors.append(encode(S_BRAM, CMD_WRITE, 20, 0xCCCCCCCC))
    vectors.append(encode(S_BRAM, CMD_WRITE, 63, 0xFFFFFFFF))   # max addr edge
    vectors.append(encode(S_BRAM, CMD_WRITE, 30, 0xDEADBEEF))

    # ── s_bram reads (verify) ──
    vectors.append(encode(S_BRAM, CMD_READ, 0,  0x00000000))
    vectors.append(encode(S_BRAM, CMD_READ, 1,  0x11111111))
    vectors.append(encode(S_BRAM, CMD_READ, 2,  0x22222222))
    vectors.append(encode(S_BRAM, CMD_READ, 10, 0xAAAAAAAA))
    vectors.append(encode(S_BRAM, CMD_READ, 20, 0xCCCCCCCC))
    vectors.append(encode(S_BRAM, CMD_READ, 63, 0xFFFFFFFF))
    vectors.append(encode(S_BRAM, CMD_READ, 30, 0xDEADBEEF))

    # ── sd_bram writes ──
    vectors.append(encode(SD_BRAM, CMD_WRITE, 0,  0x00000000))   # all-zeros edge
    vectors.append(encode(SD_BRAM, CMD_WRITE, 1,  0x33333333))
    vectors.append(encode(SD_BRAM, CMD_WRITE, 2,  0x44444444))
    vectors.append(encode(SD_BRAM, CMD_WRITE, 10, 0x55555555))
    vectors.append(encode(SD_BRAM, CMD_WRITE, 63, 0xFFFFFFFF))   # max addr edge
    vectors.append(encode(SD_BRAM, CMD_WRITE, 15, 0xCAFEBABE))
    vectors.append(encode(SD_BRAM, CMD_WRITE, 20, 0xBEEFCAFE))

    # ── sd_bram reads (verify) ──
    vectors.append(encode(SD_BRAM, CMD_READ, 0,  0x00000000))
    vectors.append(encode(SD_BRAM, CMD_READ, 1,  0x33333333))
    vectors.append(encode(SD_BRAM, CMD_READ, 2,  0x44444444))
    vectors.append(encode(SD_BRAM, CMD_READ, 10, 0x55555555))
    vectors.append(encode(SD_BRAM, CMD_READ, 63, 0xFFFFFFFF))
    vectors.append(encode(SD_BRAM, CMD_READ, 15, 0xCAFEBABE))
    vectors.append(encode(SD_BRAM, CMD_READ, 20, 0xBEEFCAFE))

    # Write hex file (16 hex chars = 64 bits per line, uppercase, no prefix)
    with open(OUTPUT_FILE, "w") as f:
        for v in vectors:
            f.write(f"{v:016X}\n")

    print(f"Generated {len(vectors)} vectors → {OUTPUT_FILE}")


if __name__ == "__main__":
    main()
