diff --git a/tests/conftest.py b/tests/conftest.py index b280eaf..bc66a05 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -88,42 +88,48 @@ def memory(request): return mem +async def mproc_inner(mod, ctx, memory): + m = mod + + stims = [m.bus.cyc & m.bus.stb, m.bus.adr, m.bus.dat_w, m.bus.we, + m.bus.sel] + + while True: + clk_hit, rst_active, wb_cyc, addr, dat_w, we, sel = \ + await ctx.tick().sample(*stims) + + if rst_active: + pass + elif clk_hit and wb_cyc and addr in memory.range: + if we: + dat_r = memory[addr - memory.range.start] + + if sel & 0x1: + dat_r = (dat_r & 0xffffff00) | (dat_w & 0x000000ff) + if sel & 0x2: + dat_r = (dat_r & 0xffff00ff) | (dat_w & 0x0000ff00) + if sel & 0x4: + dat_r = (dat_r & 0xff00ffff) | (dat_w & 0x00ff0000) + if sel & 0x8: + dat_r = (dat_r & 0x00ffffff) | (dat_w & 0xff000000) + + memory[addr] = dat_r + else: + # TODO: Some memories will dup byte/half data on the + # inactive lines. Worth adding? + ctx.set(m.bus.dat_r, memory[addr - memory.range.start]) + ctx.set(m.bus.ack, 1) + # TODO: Wait states? See bus_proc_aux in previous versions for + # inspiration. + await ctx.tick() + ctx.set(m.bus.ack, 0) + + @pytest.fixture def memory_process(mod, memory): m = mod async def memory_process(ctx): - stims = [m.bus.cyc & m.bus.stb, m.bus.adr, m.bus.dat_w, m.bus.we, - m.bus.sel] - - while True: - clk_hit, rst_active, wb_cyc, addr, dat_w, we, sel = \ - await ctx.tick().sample(*stims) - - if rst_active: - pass - elif clk_hit and wb_cyc and addr in memory.range: - if we: - dat_r = memory[addr - memory.range.start] - - if sel & 0x1: - dat_r = (dat_r & 0xffffff00) | (dat_w & 0x000000ff) - if sel & 0x2: - dat_r = (dat_r & 0xffff00ff) | (dat_w & 0x0000ff00) - if sel & 0x4: - dat_r = (dat_r & 0xff00ffff) | (dat_w & 0x00ff0000) - if sel & 0x8: - dat_r = (dat_r & 0x00ffffff) | (dat_w & 0xff000000) - - memory[addr] = dat_r - else: - # TODO: Some memories will dup byte/half data on the - # inactive lines. Worth adding? - ctx.set(m.bus.dat_r, memory[addr - memory.range.start]) - ctx.set(m.bus.ack, 1) - # TODO: Wait states? See bus_proc_aux in previous versions for - # inspiration. - await ctx.tick() - ctx.set(m.bus.ack, 0) + await mproc_inner(m, ctx, memory) return memory_process diff --git a/tests/riscof/sentinel/riscof_sentinel.py b/tests/riscof/sentinel/riscof_sentinel.py index c72d4b4..d899b49 100644 --- a/tests/riscof/sentinel/riscof_sentinel.py +++ b/tests/riscof/sentinel/riscof_sentinel.py @@ -8,55 +8,28 @@ import riscof.utils as utils from riscof.pluginTemplate import pluginTemplate +import sys + +# FIXME: This is unfortunate... but we need some code from the tests :(... +this_dir = Path(os.path.realpath(__file__)).parent +sentinel_root_dir = this_dir.parent.parent.parent +sys.path.insert(0, str(sentinel_root_dir)) + +from tests.conftest import Memory, mproc_inner # noqa: E402 +from tests.upstream.test_upstream import wfhw_inner # noqa: E402 + logger = logging.getLogger() -class HOST_STATE(Enum): - WAITING_FIRST = auto() - FIRST_ACCESS_ACK = auto() - WAITING_SECOND = auto() - SECOND_ACCESS_ACK = auto() - DONE = auto() - TIMEOUT = auto() - - -def wait_for_host_write(top, sig_file, bin_): - def wait_for_host_write(): - i = 0 - state = HOST_STATE.WAITING_FIRST - - while True: - match state: - case HOST_STATE.WAITING_FIRST: - if ((yield top.bus.adr) == 0x4000000 >> 2) and \ - (yield top.bus.sel == 0b1111) and \ - (yield top.bus.cyc) and (yield top.bus.stb): - # yield top.bus.ack.eq(1) - state = HOST_STATE.FIRST_ACCESS_ACK - case HOST_STATE.FIRST_ACCESS_ACK: - begin_sig = (yield top.bus.dat_w) - # yield top.bus.ack.eq(0) - state = HOST_STATE.WAITING_SECOND - case HOST_STATE.WAITING_SECOND: - if (yield top.bus.adr) == ((0x4000000 + 4) >> 2) and \ - (yield top.bus.sel == 0b1111) and \ - (yield top.bus.cyc) and (yield top.bus.stb): - # yield top.bus.ack.eq(1) - state = HOST_STATE.SECOND_ACCESS_ACK - case HOST_STATE.SECOND_ACCESS_ACK: - end_sig = (yield top.bus.dat_w) - # yield top.bus.ack.eq(0) - state = HOST_STATE.DONE - case HOST_STATE.DONE: - break - case HOST_STATE.TIMEOUT: - raise AssertionError("CPU (but not microcode) probably " - "stuck in infinite loop") - - yield - i += 1 - if i > 65535: - state = HOST_STATE.TIMEOUT +def mk_wait_for_host_write(top, sig_file, memory): + async def wait_for_host_write(ctx): + val = await wfhw_inner(top, ctx) + begin_sig = val & 0xffffffff + end_sig = (val >> 32) & 0xffffffff + + # I don't feel like doing alignment so convert the 32-bit memory + # list into bytes and index on a byte-basis. + bin_ = b"".join(b.to_bytes(4, 'little') for b in memory) # The end state of the simulation is to print out the locations # of the beginning and ending signatures. They can then @@ -73,51 +46,9 @@ def wait_for_host_write(): return wait_for_host_write -def read_write_mem(top, bin_): - def read_write_mem(): - yield Passive() - - ios = (0x4000000 >> 2, 0x4000000 + 4 >> 2) - while True: - yield top.bus.dat_r.eq(0) - yield top.bus.ack.eq(0) - - if ((yield top.bus.cyc) and (yield top.bus.stb)): - if not (yield top.bus.ack): - yield top.bus.ack.eq(1) - - if ((yield top.bus.we) and (yield top.bus.ack) and - ((yield top.bus.adr) not in ios)): - data_word = (yield top.bus.dat_w) - sel = (yield top.bus.sel) - word_adr = (yield top.bus.adr) << 2 - - if sel & 0b0001: - bin_[word_adr] = data_word & 0xff - if sel & 0b0010: - bin_[word_adr + 1] = (data_word >> 8) & 0xff - if sel & 0b0100: - bin_[word_adr + 2] = (data_word >> 16) & 0xff - if sel & 0b1000: - bin_[word_adr + 3] = (data_word >> 24) & 0xff - - elif ((not (yield top.bus.ack)) and - ((yield top.bus.adr) not in ios)): - data_word = 0 - sel = (yield top.bus.sel) - word_adr = (yield top.bus.adr) << 2 - - if sel & 0b0001: - data_word |= bin_[word_adr] - if sel & 0b0010: - data_word |= bin_[word_adr + 1] << 8 - if sel & 0b0100: - data_word |= bin_[word_adr + 2] << 16 - if sel & 0b1000: - data_word |= bin_[word_adr + 3] << 24 - - yield top.bus.dat_r.eq(data_word) - yield +def mk_read_write_mem(top, memory): + async def read_write_mem(ctx): + await mproc_inner(top, ctx, memory) return read_write_mem @@ -289,11 +220,17 @@ def runTests(self, testList): with open(test_dir / bin, "rb") as fp: bin_ = bytearray(fp.read()) + mem = Memory(start=0, size=len(bin_)) + + for adr in range(0, len(bin_) // 4): + mem[adr] = int.from_bytes(bin_[4 * adr:4 * adr + 4], + byteorder="little") + logger.debug("Executing in Amaranth simulator") sim = Simulator(top) sim.add_clock(1/(12e6)) - sim.add_sync_process(wait_for_host_write(top, sig_file, bin_)) - sim.add_sync_process(read_write_mem(top, bin_)) + sim.add_testbench(mk_wait_for_host_write(top, sig_file, mem)) + sim.add_process(mk_read_write_mem(top, mem)) vcd = test_dir / Path(test.stem).with_suffix(".vcd") gtkw = test_dir / Path(test.stem).with_suffix(".gtkw") diff --git a/tests/upstream/test_upstream.py b/tests/upstream/test_upstream.py index 3ac2977..b6f3c4a 100644 --- a/tests/upstream/test_upstream.py +++ b/tests/upstream/test_upstream.py @@ -35,8 +35,7 @@ def memory(request): return mem -@pytest.fixture -def wait_for_host_write(mod, request): +async def wfhw_inner(mod, ctx): class HOST_STATE(Enum): WAITING_FIRST = auto() FIRST_ACCESS_ACK = auto() @@ -46,46 +45,52 @@ class HOST_STATE(Enum): TIMEOUT = auto() m = mod + i = 0 + state = HOST_STATE.WAITING_FIRST + val = 0xdeadbeef + + while True: + stims = [m.bus.cyc & m.bus.stb, m.bus.adr, m.bus.dat_w, m.bus.we, + m.bus.sel] + *_, wb_cyc, addr, dat_w, we, sel = await ctx.tick().sample(*stims) + + i += 1 + if i > 65535: + state = HOST_STATE.TIMEOUT + + match state: + case HOST_STATE.WAITING_FIRST: + if (addr == 0x4000000 >> 2) and (sel == 0b1111) and wb_cyc: + ctx.set(m.bus.ack, 1) + state = HOST_STATE.FIRST_ACCESS_ACK + case HOST_STATE.FIRST_ACCESS_ACK: + val = dat_w + ctx.set(m.bus.ack, 0) + state = HOST_STATE.WAITING_SECOND + case HOST_STATE.WAITING_SECOND: + if addr == ((0x4000000 + 4) >> 2) and (sel == 0b1111) and \ + wb_cyc: + ctx.set(m.bus.ack, 1) + state = HOST_STATE.SECOND_ACCESS_ACK + case HOST_STATE.SECOND_ACCESS_ACK: + val |= (dat_w << 32) + ctx.set(m.bus.ack, 0) + state = HOST_STATE.DONE + case HOST_STATE.DONE: + break + case HOST_STATE.TIMEOUT: + raise AssertionError("CPU (but not microcode) probably " + "stuck in infinite loop") + + return val + +@pytest.fixture +def wait_for_host_write(mod, request): # TODO: Convert into SoC module (use wishbone.Decoder and friends)? async def wait_for_host_write(ctx): - i = 0 - state = HOST_STATE.WAITING_FIRST - val = 0xdeadbeef - - while True: - stims = [m.bus.cyc & m.bus.stb, m.bus.adr, m.bus.dat_w, m.bus.we, - m.bus.sel] - *_, wb_cyc, addr, dat_w, we, sel = await ctx.tick().sample(*stims) - - i += 1 - if i > 65535: - state = HOST_STATE.TIMEOUT - - match state: - case HOST_STATE.WAITING_FIRST: - if (addr == 0x4000000 >> 2) and (sel == 0b1111) and wb_cyc: - ctx.set(m.bus.ack, 1) - state = HOST_STATE.FIRST_ACCESS_ACK - case HOST_STATE.FIRST_ACCESS_ACK: - val = dat_w - ctx.set(m.bus.ack, 0) - state = HOST_STATE.WAITING_SECOND - case HOST_STATE.WAITING_SECOND: - if addr == ((0x4000000 + 4) >> 2) and (sel == 0b1111) and \ - wb_cyc: - ctx.set(m.bus.ack, 1) - state = HOST_STATE.SECOND_ACCESS_ACK - case HOST_STATE.SECOND_ACCESS_ACK: - val |= (dat_w << 32) - ctx.set(m.bus.ack, 0) - state = HOST_STATE.DONE - case HOST_STATE.DONE: - assert (val >> 1, val & 1) == (0, 1) - break - case HOST_STATE.TIMEOUT: - raise AssertionError("CPU (but not microcode) probably " - "stuck in infinite loop") + val = await wfhw_inner(mod, ctx) + assert (val >> 1, val & 1) == (0, 1) return wait_for_host_write