Esempio n. 1
0
def test_counter():
    """Simple testbench for the Counter above."""

    # Create a counter with a rollover at 18.
    # This awkward non-power-of-two value will help test that we're not
    # rolling over by accident of the bit width of the counter.
    counter = Counter(limit=18)

    # Test benches are written as Python generators, which yield
    # commands to the simulator such as "send me the current value of this
    # signal" or "advance the simulation by one clock cycle".
    def testbench():
        for step in range(20):
            # Check outputs are correct at each step.
            assert (yield counter.counter) == (step % 18)
            if step == 17:
                assert (yield counter.rollover)
            else:
                assert not (yield counter.rollover)

            # Advance simulation by one cycle.
            yield

    sim = Simulator(counter)

    # To test synchronous processes, we create a clock at some nominal
    # frequency (which only changes the displayed timescale in the output),
    # and add our testbench as a "synchronous" process.
    sim.add_clock(1 / 10e6)
    sim.add_sync_process(testbench)

    sim.run()
Esempio n. 2
0
class TestBase(unittest.TestCase):
    """Base class for testing an Amaranth module.

    The module can use sync, comb or both.
    """
    def setUp(self):
        # Ensure IS_SIM_RUN set
        global _IS_SIM_RUN
        _IS_SIM_RUN = True
        # Create DUT and add to simulator
        self.m = Module()
        self.dut = self.create_dut()
        self.m.submodules['dut'] = self.dut
        self.m.submodules['dummy'] = _DummySyncModule()
        self.sim = Simulator(self.m)

    def create_dut(self):
        """Returns an instance of the device under test"""
        raise NotImplementedError

    def add_process(self, process):
        """Add main test process to the simulator"""
        self.sim.add_sync_process(process)

    def add_sim_clocks(self):
        """Add clocks as required by sim.
        """
        self.sim.add_clock(1, domain='sync')

    def run_sim(self, process, write_trace=False):
        self.add_process(process)
        self.add_sim_clocks()
        if write_trace:
            with self.sim.write_vcd("zz.vcd", "zz.gtkw"):
                self.sim.run()
            # Discourage commiting code with tracing active
            self.fail("Simulation tracing active. "
                      "Turn off after debugging complete.")
        else:
            self.sim.run()
Esempio n. 3
0
def basic_vm_test():
	cpu = MtkCpu(
		mem_config=EBRMemConfig(
			mem_size_words=0x123,
    		mem_content_words=None, # Optional[List[int]]
    		mem_addr=CODE_START_ADDR,
    		simulate=True,
		)
	)

	def wait_decode() -> int: # returns pc of instr being decoded
		while True:
			is_decode = yield cpu.fetch
			if is_decode:
				return (yield cpu.pc)
			yield

	def wait_pc(target_pc : int, instr_limit: Optional[int]=None):
		import logging
		logging.info(f"== waiting for pc {target_pc}")
		miss = 0
		while True:
			pc = wait_decode()
			logging.info(f"pc: {pc}")
			if pc == target_pc:
				logging(f"pc {target_pc} found")
			else:
				miss += 1
				if miss == instr_limit:
					raise ValueError(f"limit of {instr_limit} instructions exceeded while waiting for {target_pc}")
		
	# TODO test is not finished.
	def main():
		yield cpu.current_priv_mode.eq(PrivModeBits.USER)
		yield cpu.csr_unit.satp.eq(0x8000_0123)
		res = []
		for _ in range (30):
			priv = yield cpu.current_priv_mode
			priv = yield cpu.arbiter.addr_translation_en
			priv = yield cpu.csr_unit.satp.mode
			priv = yield cpu.pc
			res.append(hex(priv))
			yield
		raise ValueError(res)


	sim = Simulator(cpu)
	sim.add_clock(1e-6)
	sim.add_sync_process(main)

	from mtkcpu.utils.tests.sim_tests import get_state_name, find_fsm

	# fsm = find_fsm(cpu.arbiter, "fsm")
	# main_fsm = find_fsm(cpu, "fsm")
	# raise ValueError(fsm)

	traces = [
		sim._fragment.domains["sync"].clk,
		cpu.pc,
		cpu.arbiter.addr_translation_en,
		cpu.arbiter.translation_ack,
		cpu.arbiter.start_translation,
		# fsm.state,
		cpu.arbiter.pe.i,
		cpu.arbiter.pe.o,
		cpu.arbiter.pe.none,
		cpu.csr_unit.satp.mode,
		cpu.csr_unit.satp.ppn,
		cpu.arbiter.first,
		cpu.arbiter.error_code,
		# main_fsm.state
	]

	with sim.write_vcd(f"vm.vcd", "vm.gtkw", traces=traces):
		sim.run()
Esempio n. 4
0
def reg_test(
    name: str,
    timeout_cycles: Optional[int],
    reg_num: int,
    expected_val: Optional[int],
    expected_mem: Optional[MemoryContents],
    reg_init: RegistryContents,
    mem_cfg: EBRMemConfig,
    verbose: bool = False,
):

    cpu = MtkCpu(
        reg_init=reg_init.reg, 
        with_debug=False, # XXX
        mem_config=mem_cfg
    )

    sim = Simulator(cpu)
    sim.add_clock(1e-6)

    assert (reg_num is None and expected_val is None) or (
        reg_num is not None and expected_val is not None
    )
            
    # Since Amaranth HDL's 'Memory' instance simulation in included,
    # we don't need to use custom implementation (however some coverage drop
    # is present - 'Memory' class is assumed single-cycle-access, while
    # 'get_sim_memory_test' processing delay is random).
    # sim.add_sync_process(get_sim_memory_test(cpu=cpu, mem_dict=mem_dict))
    # instead only collect write transactions directly on a bus.
    result_mem = {}
    sim.add_sync_process(capture_write_transactions(cpu=cpu, dict_reference=result_mem))
    
    sim.add_sync_process(
        get_sim_register_test(
            name=name,
            cpu=cpu,
            reg_num=reg_num,
            expected_val=expected_val,
            timeout_cycles=timeout_cycles,
        )
    )

    csr_unit : CsrUnit = cpu.csr_unit
    # frag = Fragment.get(cpu, platform=None)
    # main_fsm = frag.find_generated("fsm")
    e = cpu.exception_unit
    sim_traces = [
        # main_fsm.state,
        # e.m_instruction,
        # e.mtval.value,
        # csr_unit.mtvec.base,
        # csr_unit.mtvec.mode,
        # *csr_unit.mepc.fields.values(),
        *csr_unit.mcause.fields.values(),
        *csr_unit.satp.fields.values(),
        # *csr_unit.mie.fields.values(),
        # *csr_unit.mstatus.fields.values(),
        # *csr_unit.mtime.fields.values(),
        # *csr_unit.mtimecmp.fields.values(),
        cpu.instr,
        cpu.pc,
        # csr_unit.rs1,
        # csr_unit.csr_idx,
        # csr_unit.rd,
        # csr_unit.rd_val,
        # csr_unit.vld,
        # csr_unit.ONREAD,
        # csr_unit.ONWRITE,
        cpu.arbiter.pe.i,
        cpu.arbiter.pe.o,
        cpu.arbiter.pe.none,
        cpu.arbiter.bus_free_to_latch,

        cpu.arbiter.error_code,
        cpu.arbiter.addr_translation_en,
        cpu.arbiter.translation_ack,
        cpu.arbiter.start_translation,
        cpu.arbiter.phys_addr,
        cpu.arbiter.root_ppn,

        *cpu.arbiter.pte.fields.values(),

        cpu.arbiter.generic_bus.addr,
        cpu.arbiter.generic_bus.read_data,
        cpu.arbiter.vpn,
    ]

    # from amaranth.back import verilog
    # s = verilog.convert(cpu)
    # open("cpu.v", "w").write(s)

    with sim.write_vcd("cpu.vcd", "cpu.gtkw", traces=sim_traces):
        sim.run()

    if expected_mem is not None:
        MemoryContents(result_mem).assert_equality(expected_mem)
Esempio n. 5
0
            
    return m, f


def unit_testbench(case: ComponentTestbenchCase):
    if case.component_type == MemoryArbiter:
        m, f = memory_arbiter_tb()
    elif case.component_type == GPIO_Wishbone:
        m, f = gpio_tb()
    else:
        print(f"===== Skipping not covered type {case.component_type}")
        return

    sim = Simulator(m)
    sim.add_clock(1e-6)
    sim.add_sync_process(f)

    with sim.write_vcd(f"{case.name}.vcd"):
        sim.run()


# returns ELF path
def compile_sw_project(proj_name : str) -> Path:
    sw_dir = Path(__file__).parent.parent.parent / "sw"
    proj_dir = sw_dir / proj_name
    if not proj_dir.exists() or not proj_dir.is_dir():
        raise ValueError(f"Compilation failed: Directory {proj_dir} does not exists!")
    from mtkcpu.utils.linker import write_linker_script
    write_linker_script(sw_dir / "common" / "linker.ld", CODE_START_ADDR)
    process = subprocess.Popen(f"make -B", cwd=proj_dir, shell=True)
    process.communicate()
Esempio n. 6
0
def test_with_samplerate(samplerate: int=48000):
    """run adat signal simulation with the given samplerate"""
    # 24 bit plus the 6 nibble separator bits for eight channel
    # then 1 separator, 10 sync bits (zero), 1 separator and 4 user bits

    clk_freq = 100e6
    dut = ADATReceiverTester(clk_freq)
    adat_freq = NRZIDecoder.adat_freq(samplerate)
    clockratio = clk_freq / adat_freq

    sim = Simulator(dut)
    sim.add_clock(1.0/clk_freq, domain="sync")
    sim.add_clock(1.0/adat_freq, domain="adat")

    sixteen_adat_frames = sixteen_frames_with_channel_num_msb_and_sample_num()

    testdata = \
        one_empty_adat_frame() + \
        sixteen_adat_frames[0:256] + \
        [0] * 64 + \
        sixteen_adat_frames[256:]

    testdata_nrzi = encode_nrzi(testdata)

    print(f"FPGA clock freq: {clk_freq}")
    print(f"ADAT clock freq: {adat_freq}")
    print(f"FPGA/ADAT freq: {clockratio}")

    no_cycles = len(testdata_nrzi) + 500

    # Send the adat stream
    def adat_process():
        for bit in testdata_nrzi:  # [224:512 * 2]:
            yield dut.adat_in.eq(bit)
            yield Tick("adat")

    # Process the adat stream and validate output
    def sync_process():
        # Obtain the output data
        out_data = [[0 for x in range(9)] for y in range(16)] #store userdata in the 9th column
        sample = 0
        for _ in range(int(clockratio) * no_cycles):
            yield Tick("sync")
            if (yield dut.output_enable == 1):
                channel = yield dut.addr_out

                out_data[sample][channel] = yield dut.sample_out

                if (channel == 7):
                    out_data[sample][8] = yield dut.user_data_out
                    sample += 1

        #print(out_data)


        #
        # The receiver needs 2 sync pads before it starts outputting data:
        #   * The first sync pad is needed for the nrzidecoder to sync
        #   * The second sync pad is needed for the receiver to sync
        #   Therefore each time after the connection was lost the first frame will be lost while syncing.
        # In our testdata we loose the initial one_empty_adat_frame and the second sample (#1, count starts with 0)
        #

        sampleno = 0
        for i in range(16):
            if (sampleno == 1): #skip the first frame while the receiver syncs after an interruption
                sampleno += 1
            elif (sampleno == 16): #ensure the data ended as expected
                assert out_data[i] == [0, 0, 0, 0, 0, 0, 0, 0, 0], "Sample {} was: {}".format(sampleno, print_frame(out_data[sampleno]))
            else:
                assert out_data[i] == [((0 << 20) | sampleno), ((1 << 20) | sampleno), ((2 << 20) | sampleno),
                                       ((3 << 20) | sampleno), ((4 << 20) | sampleno), ((5 << 20) | sampleno),
                                       ((6 << 20) | sampleno), ((7 << 20) | sampleno), 0b0101]\
                    , "Sample #{} was: {}".format(sampleno, print_frame(out_data[sampleno]))
            sampleno += 1

        print("Success!")

    sim.add_sync_process(sync_process, domain="sync")
    sim.add_sync_process(adat_process, domain="adat")
    with sim.write_vcd(f'receiver-smoke-test-{str(samplerate)}.vcd'):
        sim.run()
Esempio n. 7
0
            if i == 700:
                yield buffer.send_tlp.eq(1)
                yield buffer.send_tlp_id.eq(0xCA)

            if i == 800:
                yield buffer.send_tlp.eq(1)
                yield buffer.send_tlp_id.eq(0x1EF)

            if (yield buffer.tlp_source.valid[0]):
                print(i,
                      hex((yield buffer.send_tlp_id))[2:],
                      hex((yield buffer.tlp_source.symbol[0]))[2:])

            #store = (yield buffer.store_tlp)
            #
            #if not store and not sm1:
            #    yield buffer.send_tlp.eq(1)
            #    yield buffer.send_tlp_id.eq(123)
            #
            #sm1 = store

            #if i == 700:
            #    yield buffer.delete_tlp.eq(1)
            #    yield buffer.delete_tlp_id.eq(123)

            yield

    sim.add_sync_process(process, domain="rx")

    with sim.write_vcd("test_memory.vcd", "test_memory.gtkw"):
        sim.run()
Esempio n. 8
0
    p_action.add_parser("simulate")
    p_action.add_parser("generate")

    args = parser.parse_args()
    if args.action == "simulate":
        from amaranth.sim import Simulator, Passive

        sim = Simulator(uart)
        sim.add_clock(1e-6)

        def loopback_proc():
            yield Passive()
            while True:
                yield uart.rx_i.eq((yield uart.tx_o))
                yield
        sim.add_sync_process(loopback_proc)

        def transmit_proc():
            assert (yield uart.tx_ack)
            assert not (yield uart.rx_rdy)

            yield uart.tx_data.eq(0x5A)
            yield uart.tx_rdy.eq(1)
            yield
            yield uart.tx_rdy.eq(0)
            yield
            assert not (yield uart.tx_ack)

            for _ in range(uart.divisor * 12): yield

            assert (yield uart.tx_ack)
            yield Tick("usb")
        # send USB MIDI sysex
        yield from sysex(0x04, 0xf0, 0x0a, 0x0b, 0x07, 0x0c, 0x0d, 0xf7)
        for _ in range(40):
            yield Tick("usb")
        yield dut.midi_stream.valid.eq(1)
        yield from midi_message(0x93, 60, 0x7f, set_valid=False)
        yield Tick("usb")
        yield from midi_message(0x93, 61, 0x7f, set_valid=False)
        yield dut.midi_stream.valid.eq(0)
        for _ in range(128):
            yield Tick("usb")

    def jt51_process():
        yield Tick("jt51")
        yield Tick("jt51")
        yield Tick("jt51")
        yield Tick("jt51")
        yield dut.jt51_stream.ready.eq(1)
        for _ in range(50):
            yield Tick("jt51")

    sim = Simulator(dut)
    sim.add_clock(1.0/60e6, domain="usb")
    sim.add_clock(1.0/3e6,  domain="jt51")
    sim.add_sync_process(usb_process, domain="usb")
    sim.add_sync_process(jt51_process, domain="jt51")

    with sim.write_vcd(f'midicontroller.vcd'):
        sim.run()
Esempio n. 10
0
    # Disabled counter should not overflow.
    yield dut.en.eq(0)
    for _ in range(30):
        yield
        assert not (yield dut.ovf)

    # Once enabled, the counter should overflow in 25 cycles.
    yield dut.en.eq(1)
    for _ in range(25):
        yield
        assert not (yield dut.ovf)
    yield
    assert (yield dut.ovf)

    # The overflow should clear in one cycle.
    yield
    assert not (yield dut.ovf)


sim = Simulator(dut)
sim.add_clock(1e-6)  # 1 MHz
sim.add_sync_process(bench)
with sim.write_vcd("up_counter.vcd"):
    sim.run()
# --- CONVERT ---
from amaranth.back import verilog

top = UpCounter(25)
with open("up_counter.v", "w") as f:
    f.write(verilog.convert(top, ports=[top.en, top.ovf]))
Esempio n. 11
0
def test_with_samplerate(samplerate: int = 48000):
    clk_freq = 50e6
    dut = ADATTransmitter()
    adat_freq = NRZIDecoder.adat_freq(samplerate)
    clockratio = clk_freq / adat_freq

    print(f"FPGA clock freq: {clk_freq}")
    print(f"ADAT clock freq: {adat_freq}")
    print(f"FPGA/ADAT freq: {clockratio}")

    sim = Simulator(dut)
    sim.add_clock(1.0 / clk_freq, domain="sync")
    sim.add_clock(1.0 / adat_freq, domain="adat")

    def write(addr: int,
              sample: int,
              last: bool = False,
              drop_valid: bool = False):
        while (yield dut.ready_out == 0):
            yield from wait(1)
        if last:
            yield dut.last_in.eq(1)
        yield dut.addr_in.eq(addr)
        yield dut.sample_in.eq(sample)
        yield dut.valid_in.eq(1)
        yield Tick("sync")
        if drop_valid:
            yield dut.valid_in.eq(0)
        if last:
            yield dut.last_in.eq(0)

    def wait(n_cycles: int):
        for _ in range(int(clockratio) * n_cycles):
            yield Tick("sync")

    def sync_process():
        yield Tick("sync")
        yield Tick("sync")
        yield dut.user_data_in.eq(0xf)
        for i in range(4):
            yield from write(i, i, drop_valid=True)
        for i in range(4):
            yield from write(4 + i, 0xc + i, i == 3, drop_valid=True)
        yield dut.user_data_in.eq(0xa)
        yield Tick("sync")
        for i in range(8):
            yield from write(i, (i + 1) << 4, i == 7)
        yield dut.user_data_in.eq(0xb)
        yield Tick("sync")
        for i in range(8):
            yield from write(i, (i + 1) << 8, i == 7)
        yield dut.user_data_in.eq(0xc)
        yield Tick("sync")
        for i in range(8):
            yield from write(i, (i + 1) << 12, i == 7)
        yield dut.user_data_in.eq(0xd)
        yield Tick("sync")
        for i in range(8):
            yield from write(i, (i + 1) << 16, i == 7)
        yield dut.user_data_in.eq(0xe)
        yield Tick("sync")
        for i in range(8):
            yield from write(i, (i + 1) << 20, i == 7, drop_valid=True)
        yield from wait(900)

    def adat_process():
        nrzi = []
        i = 0
        while i < 1800:
            yield Tick("adat")
            out = yield dut.adat_out
            nrzi.append(out)
            i += 1

        # skip initial zeros
        nrzi = nrzi[nrzi.index(1):]
        signal = decode_nrzi(nrzi)
        decoded = adat_decode(signal)
        print(decoded)
        user_bits = [decoded[frame][0] for frame in range(7)]
        assert user_bits == [0x0, 0xf, 0xa, 0xb, 0xc, 0xd,
                             0xe], print_assert_failure(user_bits)
        assert decoded[0][1:] == [0, 0, 0, 0, 0, 0, 0,
                                  0], print_assert_failure(decoded[0][1:])
        assert decoded[1][1:] == [0, 1, 2, 3, 0xc, 0xd, 0xe,
                                  0xf], print_assert_failure(decoded[1][1:])
        assert decoded[2][1:] == [
            0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80
        ], print_assert_failure(decoded[2][1:])
        assert decoded[3][1:] == [
            0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800
        ], print_assert_failure(decoded[3][1:])
        assert decoded[4][1:] == [
            0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000
        ], print_assert_failure(decoded[4][1:])
        assert decoded[5][1:] == [
            0x10000, 0x20000, 0x30000, 0x40000, 0x50000, 0x60000, 0x70000,
            0x80000
        ], print_assert_failure(decoded[5][1:])

    sim.add_sync_process(sync_process, domain="sync")
    sim.add_sync_process(adat_process, domain="adat")

    with sim.write_vcd(f'transmitter-smoke-test-{str(samplerate)}.vcd'):
        sim.run()
Esempio n. 12
0
def test_riscv_dv(cfg: RiscvDvTestConfig):
    sys.setrecursionlimit(10**6) # otherwise amaranth/sim/_pyrtl.py:441: RecursionError, because of huge memory size
    max_code_size = cfg.test_elf.stat().st_size
    program = read_elf(cfg.test_elf)
    mem_cfg = EBRMemConfig.from_mem_dict(
        start_addr=cfg.start_addr,
        num_bytes=max_code_size,
        simulate=True,
        mem_dict=MemoryContents(program),
    )

    cpu = MtkCpu(
        with_debug=False,
        mem_config=mem_cfg
    )

    sim = Simulator(cpu)
    sim.add_clock(1e-6)

    traces = [
        cpu.pc,
        cpu.instr,
        cpu.rd,
        cpu.should_write_rd,
        *cpu.csr_unit.satp.fields.values(),
        cpu.exception_unit.current_priv_mode,
        
        cpu.arbiter.pe.i,
        cpu.arbiter.pe.o,
        cpu.arbiter.pe.none,
        cpu.arbiter.bus_free_to_latch,

        cpu.arbiter.error_code,
        cpu.arbiter.addr_translation_en,
        cpu.arbiter.translation_ack,
        cpu.arbiter.start_translation,
        cpu.arbiter.phys_addr,
        cpu.arbiter.root_ppn,

        *cpu.arbiter.pte.fields.values(),

        cpu.arbiter.generic_bus.addr,
        cpu.arbiter.generic_bus.read_data,
        cpu.arbiter.vpn,
        cpu.arbiter.error_code,
    ]

    csv_output = tempfile.NamedTemporaryFile(
        suffix=f".mtkcpu.{cfg.test_name}.csv", 
        dir=Path(__file__).parent.name, 
        delete=False
    )
    fn = riscv_dv_sim_process(
        cpu=cpu,
        iss_csv=cfg.iss_csv,
        compare_every=cfg.compare_every,
        csv_output=Path(csv_output.name),
    )
    sim.add_sync_process(fn)
    
    with sim.write_vcd("cpu.vcd", "cpu.gtkw", traces=traces):
        sim.run()
    print("== Waveform dumped to cpu.vcd file")
Esempio n. 13
0
def test_with_samplerate(samplerate: int=48000):
    """run adat signal simulation with the given samplerate"""
    # 24 bit plus the 6 nibble separator bits for eight channel
    # then 1 separator, 10 sync bits (zero), 1 separator and 4 user bits

    clk_freq = 100e6
    dut = NRZIDecoderTester(clk_freq)
    adat_freq = NRZIDecoder.adat_freq(samplerate)
    clockratio = clk_freq / adat_freq


    sim = Simulator(dut)
    sim.add_clock(1.0/clk_freq, domain="sync")
    sim.add_clock(1.0/adat_freq, domain="adat")

    print(f"FPGA clock freq: {clk_freq}")
    print(f"ADAT clock freq: {adat_freq}")
    print(f"FPGA/ADAT freq: {clockratio}")

    sixteen_adat_frames = sixteen_frames_with_channel_num_msb_and_sample_num()
    interrupted_adat_stream = [0] * 64

    testdata = one_empty_adat_frame() + \
        sixteen_adat_frames[0:256] + \
        interrupted_adat_stream + \
        sixteen_adat_frames[256:]

    testdata_nrzi = encode_nrzi(testdata)

    no_cycles = len(testdata_nrzi)

    # Send the adat stream
    def adat_process():
        bitcount :int = 0
        for bit in testdata_nrzi: #[224:512 * 2]:
            if (bitcount == 4 * 256 + 64):
                yield dut.invalid_frame_in.eq(1)
                yield Tick("adat")
                yield dut.invalid_frame_in.eq(0)
                for _ in range(20):
                    yield Tick("adat")
            else:
                yield dut.invalid_frame_in.eq(0)

            yield dut.nrzi_in.eq(bit)
            yield Tick("adat")
            bitcount += 1

    # Process the adat stream and validate output
    def sync_process():
        # Obtain the output data
        out_data = []
        for _ in range(int(clockratio) * no_cycles):
            yield Tick("sync")
            if (yield dut.data_out_en == 1):
                bit = yield dut.data_out
                yield out_data.append(bit)

        #
        # Validate output
        #

        # omit a 1 at the end of the sync pad
        out_data = out_data[1:]

        # Whenever the state machine switches from SYNC to DECODE we need to omit the first 11 sync bits
        validate_output(out_data[:256 - 12], one_empty_adat_frame()[12:256])
        out_data = out_data[256-12:]

        validate_output(out_data[:256], sixteen_adat_frames[:256])
        out_data = out_data[256:]

        # now the adat stream was interrupted, it continues to output zeroes, until it enters the SYNC state
        validate_output(out_data[:10], interrupted_adat_stream[:10])
        out_data = out_data[10:]

        # followed by 2 well formed adat frames

        # omit the first 11 sync bits
        validate_output(out_data[:256 - 12], sixteen_adat_frames[256 + 12:2 * 256])
        out_data = out_data[256 - 12:]

        validate_output(out_data[:256], sixteen_adat_frames[2 * 256:3 * 256])
        out_data = out_data[256:]

        # followed by one invalid frame - the state machine SYNCs again

        # followed by 13 well-formed frames

        # omit the first 11 sync bits
        validate_output(out_data[:256 - 12], sixteen_adat_frames[3 * 256 + 12:4 * 256])
        out_data = out_data[256-12:]

        for i in range(4, 16):
            validate_output(out_data[:256], sixteen_adat_frames[i * 256:(i + 1) * 256])
            out_data = out_data[256:]

        print("Success!")


    sim.add_sync_process(sync_process, domain="sync")
    sim.add_sync_process(adat_process, domain="adat")
    with sim.write_vcd(f'nrzi-decoder-bench-{str(samplerate)}.vcd'):
        sim.run()