# SPDX-License-Identifier: AGPL-3.0-Only # Copyright (C) 2022 Sean Anderson import itertools import random import cocotb from cocotb.clock import Clock from cocotb.regression import TestFactory from cocotb.result import SimTimeoutError from cocotb.triggers import ClockCycles, FallingEdge, RisingEdge, Timer, with_timeout from .util import compare_lists, send_recovered_bits, timeout, with_valids def scramble(bits): lfsr = random.randrange(1, 0x7ff) for bit in bits: ldd = (lfsr >> 10) ^ ((lfsr >> 8) & 1) yield bit ^ ldd lfsr <<= 1 lfsr &= 0x7ff lfsr |= ldd async def send_scrambled(descrambler, data, valids): descrambler.signal_status.value = 1 await send_recovered_bits(descrambler.clk, descrambler.scrambled, descrambler.scrambled_valid, scramble(data), valids) descrambler.signal_status.value = 0 @timeout(10, 'us') async def test_unlock(descrambler, valids): descrambler.signal_status.value = 0 descrambler.scrambled_valid.value = 0 descrambler.test_mode.value = 1 await Timer(1) await cocotb.start(Clock(descrambler.clk, 8, units='ns').start()) await cocotb.start(send_scrambled(descrambler, itertools.chain(itertools.repeat(1, 60), itertools.repeat(0, 625//2), itertools.repeat(1, 29), itertools.repeat(0)), valids)) await ClockCycles(descrambler.clk, 60) assert descrambler.locked.value try: await with_timeout(FallingEdge(descrambler.locked), 6, 'us') except SimTimeoutError: pass else: assert False await FallingEdge(descrambler.locked) with_valids(globals(), test_unlock) @timeout(10, 'us') async def test_descramble(descrambler, valids): descrambler.signal_status.value = 0 descrambler.scrambled_valid.value = 0 descrambler.test_mode.value = 0 await Timer(1) await cocotb.start(Clock(descrambler.clk, 8, units='ns').start()) ins = [1] * 60 + [0] + [random.randrange(2) for _ in range(1000)] await cocotb.start(send_scrambled(descrambler, ins, valids)) outs = [] await RisingEdge(descrambler.locked) while descrambler.locked.value: await RisingEdge(descrambler.clk) valid = descrambler.descrambled_valid.value if valid == 0: pass elif valid == 1: outs.append(descrambler.descrambled[1].value) else: outs.append(descrambler.descrambled[1].value) outs.append(descrambler.descrambled[0].value) best_corr = -1 best_off = None for off in range(28, 42): corr = sum(i == o for i, o in zip(ins[off:], outs)) if corr > best_corr: best_corr = corr best_off = off print(f"best offset is {best_off} correlation {best_corr/(len(ins) - best_off)}") compare_lists(ins[best_off:], outs) with_valids(globals(), test_descramble)