2023-04-23 11:42:18 +08:00
|
|
|
from migen import *
|
2023-04-24 03:55:01 +08:00
|
|
|
from sync_serdes import PhaseReader, DelayOptimizer, BitSlipReader, SlaveAligner
|
2023-04-23 11:42:18 +08:00
|
|
|
import random
|
|
|
|
|
|
|
|
|
|
|
|
def reader_testbench(dut, rxdata_list):
|
|
|
|
yield dut.delay_tap.eq(0)
|
|
|
|
yield dut.start.eq(1)
|
|
|
|
assert (yield dut.stab_timer.wait) == 0
|
|
|
|
|
|
|
|
for i in range(32):
|
|
|
|
yield dut.loopback_rxdata.eq(rxdata_list[i])
|
|
|
|
yield
|
|
|
|
yield
|
|
|
|
assert (yield dut.stab_timer.wait) == 1
|
|
|
|
|
|
|
|
# Keep yielding until the DUT gives CE signal
|
|
|
|
while (yield dut.inc_en) == 0:
|
|
|
|
yield
|
|
|
|
|
|
|
|
# Check that inc_en is deassrted after 1 clock cycle
|
|
|
|
yield
|
|
|
|
assert (yield dut.inc_en) == 0
|
|
|
|
|
|
|
|
# Load a new tap value
|
|
|
|
yield dut.delay_tap.eq(i + 1)
|
|
|
|
yield
|
|
|
|
# Nothing to check in the READ_TAP state
|
|
|
|
yield
|
|
|
|
|
|
|
|
assert(yield dut.done) == 1
|
|
|
|
|
|
|
|
for i in range(32):
|
|
|
|
signal = yield dut.data_result[i]
|
|
|
|
expected = rxdata_list[i]
|
|
|
|
assert signal == expected
|
|
|
|
|
|
|
|
for i in range(200):
|
|
|
|
assert (yield dut.inc_en) == 0
|
|
|
|
yield
|
|
|
|
|
|
|
|
# Untouched delay: Record should be invariant
|
|
|
|
for i in range(32):
|
|
|
|
signal = yield dut.data_result[i]
|
|
|
|
expected = rxdata_list[i]
|
|
|
|
assert signal == expected
|
|
|
|
|
|
|
|
|
|
|
|
def optimal_delay_testbench(dut, pulse_list, cycles, pulse_index, min_delay, max_offset, opt_delay_tap):
|
|
|
|
# Start the module
|
|
|
|
yield dut.delay_tap.eq(0)
|
|
|
|
yield dut.start.eq(1)
|
|
|
|
assert (yield dut.stab_timer.wait) == 0
|
|
|
|
|
|
|
|
for i in range(cycles):
|
|
|
|
# Pass in a new rxdata for sampling
|
|
|
|
# The stab_timer should start waiting after
|
|
|
|
yield dut.loopback_rxdata.eq(pulse_list[i])
|
|
|
|
yield
|
|
|
|
yield
|
|
|
|
assert (yield dut.stab_timer.wait) == 1
|
|
|
|
|
|
|
|
# Eventually, the wait will end
|
|
|
|
# Either it triggers an increment or a finished signal
|
|
|
|
# And we will get the expected pulse location
|
|
|
|
# inc_en is pulsed after this is found
|
|
|
|
if i == (cycles - 1):
|
|
|
|
while (yield dut.done) == 0:
|
|
|
|
yield
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
while (yield dut.inc_en) == 0:
|
|
|
|
yield
|
|
|
|
|
|
|
|
# Then we increment the rxdata index
|
|
|
|
yield dut.delay_tap.eq(i + 1)
|
|
|
|
yield
|
|
|
|
|
|
|
|
# Fast-forward to the result
|
|
|
|
# while (yield dut.done) == 0:
|
|
|
|
# yield
|
|
|
|
|
|
|
|
assert (yield dut.done) == 1
|
|
|
|
assert (yield dut.expected_pulse) == pulse_index
|
|
|
|
assert (yield dut.min_delay) == min_delay
|
|
|
|
assert (yield dut.max_offset) == max_offset
|
|
|
|
assert (yield dut.opt_delay_tap) == opt_delay_tap
|
|
|
|
|
|
|
|
for _ in range(100):
|
|
|
|
yield
|
|
|
|
|
|
|
|
# Invariant test: Everything is frozen after done
|
|
|
|
assert (yield dut.done) == 1
|
|
|
|
assert (yield dut.expected_pulse) == pulse_index
|
|
|
|
assert (yield dut.min_delay) == min_delay
|
|
|
|
assert (yield dut.max_offset) == max_offset
|
|
|
|
assert (yield dut.opt_delay_tap) == opt_delay_tap
|
|
|
|
|
|
|
|
|
|
|
|
def bitslip_reader_tb(dut, rxdata_list):
|
|
|
|
# Start the module
|
|
|
|
yield dut.start.eq(1)
|
|
|
|
assert (yield dut.stab_timer.wait) == 0
|
|
|
|
|
|
|
|
for i in range(5):
|
|
|
|
yield dut.loopback_rxdata.eq(rxdata_list[i])
|
|
|
|
yield
|
|
|
|
yield
|
|
|
|
assert (yield dut.stab_timer.wait) == 1
|
|
|
|
|
|
|
|
# Keep yielding until the DUT gives BITSLIP signal
|
|
|
|
while (yield dut.bitslip) == 0:
|
|
|
|
yield
|
|
|
|
|
|
|
|
# There will be 2 BITSLIP pulses
|
|
|
|
# Both BITSLIP pulses should last for 1 cycle
|
|
|
|
assert (yield dut.bitslip) == 1
|
|
|
|
yield
|
|
|
|
assert (yield dut.bitslip) == 0
|
|
|
|
yield
|
|
|
|
assert (yield dut.bitslip) == 1
|
|
|
|
yield
|
|
|
|
assert (yield dut.bitslip) == 0
|
|
|
|
|
|
|
|
assert (yield dut.done) == 1
|
|
|
|
# The result in the module should contain all rxdata
|
|
|
|
for i, rxdata in enumerate(rxdata_list):
|
|
|
|
assert (yield dut.data_result[i]) == rxdata
|
|
|
|
|
|
|
|
yield
|
|
|
|
yield
|
|
|
|
|
|
|
|
|
2023-04-24 03:55:01 +08:00
|
|
|
def bitslip_aligner_tb(dut, rxdata_list, adjust_list):
|
|
|
|
# Start the module
|
|
|
|
yield dut.start.eq(1)
|
|
|
|
assert (yield dut.stab_timer.wait) == 0
|
|
|
|
|
|
|
|
for i in range(len(rxdata_list)):
|
|
|
|
yield dut.loopback_rxdata.eq(rxdata_list[i])
|
|
|
|
yield
|
|
|
|
yield
|
|
|
|
assert (yield dut.stab_timer.wait) == 1
|
|
|
|
|
|
|
|
# Wait until the timer runs out
|
|
|
|
while (yield dut.stab_timer.done) == 0:
|
|
|
|
yield
|
|
|
|
|
|
|
|
# There will not be unnecessary pulses
|
|
|
|
if i == (len(rxdata_list) - 1):
|
|
|
|
break
|
|
|
|
|
|
|
|
# Keep yielding until the DUT gives BITSLIP signal
|
|
|
|
while (((yield dut.master_bitslip) == 0) and ((yield dut.slave_bitslip) == 0)):
|
|
|
|
yield
|
|
|
|
|
|
|
|
# There will be 2 BITSLIP pulses
|
|
|
|
# Both BITSLIP pulses should last for 1 cycle
|
|
|
|
assert (yield dut.master_bitslip) == 1
|
|
|
|
assert (yield dut.slave_bitslip) == 1
|
|
|
|
yield
|
|
|
|
assert (yield dut.master_bitslip) == 0
|
|
|
|
assert (yield dut.slave_bitslip) == 0
|
|
|
|
yield
|
|
|
|
assert (yield dut.master_bitslip) == 1
|
|
|
|
assert (yield dut.slave_bitslip) == 1
|
|
|
|
yield
|
|
|
|
assert (yield dut.master_bitslip) == 0
|
|
|
|
assert (yield dut.slave_bitslip) == 0
|
|
|
|
|
|
|
|
# Skip ahead 2 cycles for state transitions
|
|
|
|
yield
|
|
|
|
yield
|
|
|
|
|
|
|
|
for i in range(len(adjust_list)):
|
|
|
|
# Eventually the master bitslip signal will be pulled up
|
|
|
|
while (yield dut.master_bitslip) == 0:
|
|
|
|
yield
|
|
|
|
|
|
|
|
assert (yield dut.master_bitslip) == 1
|
|
|
|
assert (yield dut.slave_bitslip) == 0
|
|
|
|
yield
|
|
|
|
assert (yield dut.master_bitslip) == 0
|
|
|
|
assert (yield dut.slave_bitslip) == 0
|
|
|
|
yield
|
|
|
|
assert (yield dut.master_bitslip) == 1
|
|
|
|
assert (yield dut.slave_bitslip) == 0
|
|
|
|
yield
|
|
|
|
assert (yield dut.master_bitslip) == 0
|
|
|
|
assert (yield dut.slave_bitslip) == 0
|
|
|
|
|
|
|
|
# Give the new rxdata
|
|
|
|
yield dut.loopback_rxdata.eq(adjust_list[i])
|
|
|
|
while (yield dut.stab_timer.done) == 0:
|
|
|
|
yield
|
|
|
|
|
|
|
|
yield
|
|
|
|
yield
|
|
|
|
assert (yield dut.done) == 1
|
|
|
|
|
2023-04-23 11:42:18 +08:00
|
|
|
# # Random testing for delay reader
|
|
|
|
# for _ in range(32):
|
|
|
|
# rxdata_list = [ random.getrandbits(10) for _ in range(32) ]
|
|
|
|
# dut = PhaseReader()
|
|
|
|
# run_simulation(dut, reader_testbench(dut, rxdata_list), vcd_name="phase_reader.vcd")
|
|
|
|
|
|
|
|
# # Random testing for optimal delay calculation
|
|
|
|
# # Generate a delay list
|
|
|
|
# start = random.randint(0, 9)
|
|
|
|
# start_length = random.randint(1, 10)
|
|
|
|
# offset = random.randint(4, 5)
|
|
|
|
|
|
|
|
# current_index = start
|
|
|
|
# remaining_length = start_length
|
|
|
|
# single_pulse_list = []
|
|
|
|
|
|
|
|
# expected_index = (current_index + 1) % 10
|
|
|
|
# expected_length = 10
|
|
|
|
|
|
|
|
# for tap in range(32 + offset):
|
|
|
|
# single_pulse_list.append(1 << current_index)
|
|
|
|
# remaining_length -= 1
|
|
|
|
|
|
|
|
# if remaining_length == 0:
|
|
|
|
# current_index = (current_index + 1) % 10
|
|
|
|
# remaining_length = 10
|
|
|
|
|
|
|
|
# pulse_list = list(single_pulse_list)
|
|
|
|
# for i in range(offset, 32):
|
|
|
|
# pulse_list[i] |= single_pulse_list[i - offset]
|
|
|
|
|
|
|
|
# found_start_edge = False
|
|
|
|
# max_offset = 0
|
|
|
|
|
|
|
|
# # Calculate min_delay
|
|
|
|
# for i, pulse in enumerate(pulse_list):
|
|
|
|
# if (pulse & (1 << expected_index)) != 0:
|
|
|
|
# if not found_start_edge:
|
|
|
|
# min_delay = i
|
|
|
|
# found_start_edge = True
|
|
|
|
# else:
|
|
|
|
# max_offset += 1
|
|
|
|
# if (pulse & (1 << expected_index)) == 0 and found_start_edge:
|
|
|
|
# cycles = i + 1
|
|
|
|
# break
|
|
|
|
|
|
|
|
# print(min_delay)
|
|
|
|
# print(max_offset)
|
|
|
|
# print(cycles)
|
|
|
|
# opt_delay = int(min_delay + (max_offset / 2))
|
|
|
|
# print(opt_delay)
|
|
|
|
|
|
|
|
# # Simulate
|
|
|
|
# dut = DelayOptimizer()
|
|
|
|
# run_simulation(dut, optimal_delay_testbench(
|
|
|
|
# dut, pulse_list, cycles, expected_index,
|
|
|
|
# min_delay, max_offset, opt_delay),
|
|
|
|
# vcd_name="delay_opt.vcd"
|
|
|
|
# )
|
|
|
|
|
2023-04-24 03:55:01 +08:00
|
|
|
# # Random test for bitslip reader
|
|
|
|
# for _ in range(32):
|
|
|
|
# rxdata_list = [ random.getrandbits(10) for _ in range(5) ]
|
|
|
|
# dut = BitSlipReader()
|
|
|
|
# run_simulation(dut, bitslip_reader_tb(dut, rxdata_list), vcd_name="bitslip_reader.vcd")
|
|
|
|
|
|
|
|
# Test for bitslip alignment
|
|
|
|
def generate_aligner_tb_list(mocked_pair, start_pair):
|
|
|
|
print("Mocked pair", str(mocked_pair))
|
|
|
|
print("Start pair", str(start_pair))
|
|
|
|
double_bit_pattern = bool(random.randint(0, 1))
|
|
|
|
pulsed_indices = [ random.randint(0, 9) ]
|
|
|
|
print("Pulsed indices", str(pulsed_indices))
|
|
|
|
|
|
|
|
if double_bit_pattern:
|
|
|
|
pulsed_indices.append((pulsed_indices[0] + 1) % 10)
|
|
|
|
|
|
|
|
def generate_rxdata(pair_shift):
|
|
|
|
mocked_data = 0
|
|
|
|
|
|
|
|
rxdata = 0
|
|
|
|
for index in pulsed_indices:
|
|
|
|
rxdata |= (1 << ((index + 2*pair_shift) % 10))
|
|
|
|
|
|
|
|
mocking_mask = (1 << (2*mocked_pair)) | (1 << ((2*mocked_pair) + 1))
|
|
|
|
mocked_data = ((rxdata & mocking_mask) >> (2*mocked_pair))
|
|
|
|
|
|
|
|
# Wipe out the 2 lsb
|
|
|
|
rxdata &= 0x3FC
|
|
|
|
# Copy the mocked data to the 2 lsb
|
|
|
|
rxdata |= mocked_data
|
|
|
|
return mocked_data, rxdata
|
|
|
|
|
|
|
|
rxdata_list = []
|
|
|
|
for i in range(5):
|
|
|
|
mocked_data, rxdata = generate_rxdata((start_pair + i) % 5)
|
|
|
|
rxdata_list.append(rxdata)
|
|
|
|
if mocked_data:
|
|
|
|
break
|
|
|
|
|
|
|
|
print("Mocked data", str(mocked_data))
|
|
|
|
|
|
|
|
def is_mocking(original):
|
|
|
|
if original == 0:
|
|
|
|
return False
|
|
|
|
if (original & 0b11) == mocked_data:
|
|
|
|
return True
|
|
|
|
return is_mocking(original >> 2)
|
|
|
|
|
|
|
|
adjust_list = []
|
|
|
|
master_rxdata = rxdata_list[-1] & 0x3FC
|
|
|
|
if mocked_data and is_mocking(master_rxdata):
|
|
|
|
# Keep adding shifted variant to the adjust_list
|
|
|
|
# Until the 2 lsb is not mocking other pairs
|
|
|
|
while True:
|
|
|
|
master_rxdata <<= 2
|
|
|
|
master_rxdata &= 0x3FF
|
|
|
|
adjust_list.append(master_rxdata | mocked_data)
|
|
|
|
if not is_mocking(master_rxdata):
|
|
|
|
break
|
|
|
|
|
|
|
|
return rxdata_list, adjust_list
|
|
|
|
|
|
|
|
for mocked_pair in range(5):
|
|
|
|
for start_pair in range(5):
|
|
|
|
for _ in range(12):
|
|
|
|
rxdata_list, adjust_list = generate_aligner_tb_list(mocked_pair, start_pair)
|
|
|
|
print(rxdata_list)
|
|
|
|
print(adjust_list)
|
|
|
|
dut = SlaveAligner()
|
|
|
|
run_simulation(dut, bitslip_aligner_tb(dut, rxdata_list, adjust_list), vcd_name="bitslip_aligner.vcd")
|
|
|
|
print(mocked_pair, start_pair)
|