import cocotb from cocotb.handle import Immediate from cocotb.clock import Clock from cocotb.triggers import Timer, RisingEdge from collections import defaultdict CLK_PERIOD = 5 memory = defaultdict(int) def write_dword(addr: int, data: int): memory[addr + 0] = (data >> 0) & 0xff memory[addr + 1] = (data >> 8) & 0xff memory[addr + 2] = (data >> 16) & 0xff memory[addr + 3] = (data >> 24) & 0xff def write_byte(addr: int, data: int): memory[addr] = data & 0xff def write_bytes(addr: int, data: bytes| list[int]): for i, val in enumerate(data): memory[addr + i] = int(val) async def handle_memory(dut): while True: await RisingEdge(dut.clk) addr = int(dut.AB.value) we = bool(dut.WE.value) dut.DI.value = memory[addr] if we: memory[addr] = int(dut.DO.value) @cocotb.test async def test_reset(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) write_dword(0xfffffff4, 0x12345678) dut.RDY.value = Immediate(1) dut.reset.value = Immediate(1) for _ in range(10): await RisingEdge(dut.clk) dut.reset.value = 0 expected_cpu_outputs = [ (0x00000100, True, (int(dut.PC.value) >> 24) & 0xff), # High addr (0x000001ff, True, (int(dut.PC.value) >> 16) & 0xff), # Mid high addr (0x000001fe, True, (int(dut.PC.value) >> 8) & 0xff), # Mid low addr (0x000001fd, True, (int(dut.PC.value) >> 0) & 0xff), # Low addr (0x000001fc, True, int(dut.P.value)), # Status (0xfffffff4, False, int(dut.regfile.value)), # read vector byte 0 (0xfffffff5, False, int(dut.regfile.value)), # read vector byte 1 (0xfffffff6, False, int(dut.regfile.value)), # read vector byte 2 (0xfffffff7, False, int(dut.regfile.value)), # read vector byte 3 (0x12345678, False, int(dut.regfile.value)), # Read first instruction (0x12345679, False, int(dut.regfile.value)), # Read second byte ] for expected_output in expected_cpu_outputs: await RisingEdge(dut.clk) expected_addr, expected_we, expected_do = expected_output dut_addr = int(dut.AB.value) dut_we = bool(dut.WE.value) dut_do = int(dut.DO.value) assert dut_addr == expected_addr assert dut_we == expected_we assert dut_do == expected_do @cocotb.test async def test_absolute(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) write_dword(0xfffffff4, 0x200) # lda #$abcd1234 # wai write_bytes(0x200, [0xad, 0x34, 0x12, 0xcd, 0xab]) write_bytes(0x205, [0x8d, 0x53, 0x52, 0x51, 0x50]) write_byte(0x20a, 0xcb) write_byte(0xabcd1234, 0x55) dut.RDY.value = Immediate(1) dut.reset.value = Immediate(1) for _ in range(10): await RisingEdge(dut.clk) dut.reset.value = 0 expected_cpu_outputs = [ None, # ignore reset sequence None, None, None, None, None, None, None, None, (0x00000200, False, None), # Read first instruction (0x00000201, False, None), # Read address byte 0 (0x00000202, False, None), # Read address byte 1 (0x00000203, False, None), # Read address byte 2 (0x00000204, False, None), # Read address byte 3 (0xabcd1234, False, None), # Read from absolute address (0x00000205, False, None), # Read second instruction (0x00000206, False, None), # Read address byte 0 (0x00000207, False, None), # Read address byte 1 (0x00000208, False, None), # Read address byte 2 (0x00000209, False, None), # Read address byte 3 (0x50515253, True, 0x55), # Write to absolute address ] for expected_output in expected_cpu_outputs: await RisingEdge(dut.clk) if expected_output: expected_addr, expected_we, expected_do = expected_output dut_addr = int(dut.AB.value) dut_we = bool(dut.WE.value) dut_do = int(dut.DO.value) assert dut_addr == expected_addr assert dut_we == expected_we if dut_we: assert dut_do == expected_do