Skip to content

Commit

Permalink
Simplify adding mock processes (#540)
Browse files Browse the repository at this point in the history
  • Loading branch information
lekcyjna123 authored Jan 11, 2024
1 parent c6819eb commit 14efcc9
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 206 deletions.
22 changes: 21 additions & 1 deletion test/common/infrastructure.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
import os
import random
import unittest
Expand Down Expand Up @@ -39,7 +40,10 @@ def __init__(self, dut: _T_HasElaborate):
self._io: dict[str, _T_nested_collection[TestbenchIO]] = {}

def __getattr__(self, name: str) -> Any:
return self._io[name]
try:
return self._io[name]
except KeyError:
raise AttributeError(f"No mock for '{name}'")

def elaborate(self, platform):
def transform_methods_to_testbenchios(
Expand Down Expand Up @@ -181,6 +185,21 @@ def run(self) -> bool:


class TestCaseWithSimulator(unittest.TestCase):
def add_class_mocks(self, sim: PysimSimulator) -> None:
for key in dir(self):
val = getattr(self, key)
if hasattr(val, "_transactron_testing_process"):
sim.add_sync_process(val)

def add_local_mocks(self, sim: PysimSimulator, frame_locals: dict) -> None:
for key, val in frame_locals.items():
if hasattr(val, "_transactron_testing_process"):
sim.add_sync_process(val)

def add_all_mocks(self, sim: PysimSimulator, frame_locals: dict) -> None:
self.add_class_mocks(sim)
self.add_local_mocks(sim, frame_locals)

@contextmanager
def run_simulation(self, module: HasElaborate, max_cycles: float = 10e4, add_transaction_module=True):
traces_file = None
Expand All @@ -190,6 +209,7 @@ def run_simulation(self, module: HasElaborate, max_cycles: float = 10e4, add_tra
sim = PysimSimulator(
module, max_cycles=max_cycles, add_transaction_module=add_transaction_module, traces_file=traces_file
)
self.add_all_mocks(sim, sys._getframe(2).f_locals)
yield sim
res = sim.run()

Expand Down
1 change: 1 addition & 0 deletions test/common/sugar.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def mock(func_self=None, /) -> TestGen[None]:
assert isinstance(tb, TestbenchIO)
yield from tb.method_handle_loop(f, extra_settle_count=sched_prio, **kw)

mock._transactron_testing_process = 1 # type: ignore
return mock

return decorator
138 changes: 61 additions & 77 deletions test/frontend/test_fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,63 +56,59 @@ def setUp(self) -> None:

self.instr_queue = deque()
self.iterations = 500
self.input_q = deque()
self.output_q = deque()

random.seed(422)

def cache_processes(self):
input_q = deque()
output_q = deque()
def cache_process(self):
yield Passive()

def cache_process():
yield Passive()
next_pc = self.gen_params.start_pc

next_pc = self.gen_params.start_pc

while True:
while len(input_q) == 0:
yield

while random.random() < 0.5:
yield
while True:
while len(self.input_q) == 0:
yield

addr = input_q.popleft()
is_branch = random.random() < 0.15
while random.random() < 0.5:
yield

# exclude branches and jumps
data = random.randrange(2**self.gen_params.isa.ilen) & ~0b1111111
addr = self.input_q.popleft()
is_branch = random.random() < 0.15

# randomize being a branch instruction
if is_branch:
data |= 0b1100000
# exclude branches and jumps
data = random.randrange(2**self.gen_params.isa.ilen) & ~0b1111111

output_q.append({"instr": data, "error": 0})
# randomize being a branch instruction
if is_branch:
data |= 0b1100000

# Speculative fetch. Skip, because this instruction shouldn't be executed.
if addr != next_pc:
continue
self.output_q.append({"instr": data, "error": 0})

next_pc = addr + self.gen_params.isa.ilen_bytes
if is_branch:
next_pc = random.randrange(2**self.gen_params.isa.ilen) & ~0b11
# Speculative fetch. Skip, because this instruction shouldn't be executed.
if addr != next_pc:
continue

self.instr_queue.append(
{
"instr": data,
"pc": addr,
"is_branch": is_branch,
"next_pc": next_pc,
}
)
next_pc = addr + self.gen_params.isa.ilen_bytes
if is_branch:
next_pc = random.randrange(2**self.gen_params.isa.ilen) & ~0b11

@def_method_mock(lambda: self.icache.issue_req_io, enable=lambda: len(input_q) < 2, sched_prio=1)
def issue_req_mock(addr):
input_q.append(addr)
self.instr_queue.append(
{
"instr": data,
"pc": addr,
"is_branch": is_branch,
"next_pc": next_pc,
}
)

@def_method_mock(lambda: self.icache.accept_res_io, enable=lambda: len(output_q) > 0)
def accept_res_mock():
return output_q.popleft()
@def_method_mock(lambda self: self.icache.issue_req_io, enable=lambda self: len(self.input_q) < 2, sched_prio=1)
def issue_req_mock(self, addr):
self.input_q.append(addr)

return issue_req_mock, accept_res_mock, cache_process
@def_method_mock(lambda self: self.icache.accept_res_io, enable=lambda self: len(self.output_q) > 0)
def accept_res_mock(self):
return self.output_q.popleft()

def fetch_out_check(self):
for _ in range(self.iterations):
Expand All @@ -129,12 +125,8 @@ def fetch_out_check(self):
self.assertEqual(v["instr"], instr["instr"])

def test(self):
issue_req_mock, accept_res_mock, cache_process = self.cache_processes()

with self.run_simulation(self.m) as sim:
sim.add_sync_process(issue_req_mock)
sim.add_sync_process(accept_res_mock)
sim.add_sync_process(cache_process)
sim.add_sync_process(self.cache_process)
sim.add_sync_process(self.fetch_out_check)


Expand All @@ -154,6 +146,8 @@ def setUp(self) -> None:

self.mem = {}
self.memerr = set()
self.input_q = deque()
self.output_q = deque()

random.seed(422)

Expand Down Expand Up @@ -201,39 +195,33 @@ def gen_instr_seq(self):

pc = next_pc

def cache_processes(self):
input_q = deque()
output_q = deque()
def cache_process(self):
yield Passive()

def cache_process():
yield Passive()

while True:
while len(input_q) == 0:
yield

while random.random() < 0.5:
yield
while True:
while len(self.input_q) == 0:
yield

req_addr = input_q.popleft()
while random.random() < 0.5:
yield

def get_mem_or_random(addr):
return self.mem[addr] if addr in self.mem else random.randrange(2**16)
req_addr = self.input_q.popleft()

data = (get_mem_or_random(req_addr + 2) << 16) | get_mem_or_random(req_addr)
def get_mem_or_random(addr):
return self.mem[addr] if addr in self.mem else random.randrange(2**16)

err = (req_addr in self.memerr) or (req_addr + 2 in self.memerr)
output_q.append({"instr": data, "error": err})
data = (get_mem_or_random(req_addr + 2) << 16) | get_mem_or_random(req_addr)

@def_method_mock(lambda: self.icache.issue_req_io, enable=lambda: len(input_q) < 2, sched_prio=1)
def issue_req_mock(addr):
input_q.append(addr)
err = (req_addr in self.memerr) or (req_addr + 2 in self.memerr)
self.output_q.append({"instr": data, "error": err})

@def_method_mock(lambda: self.icache.accept_res_io, enable=lambda: len(output_q) > 0)
def accept_res_mock():
return output_q.popleft()
@def_method_mock(lambda self: self.icache.issue_req_io, enable=lambda self: len(self.input_q) < 2, sched_prio=1)
def issue_req_mock(self, addr):
self.input_q.append(addr)

return issue_req_mock, accept_res_mock, cache_process
@def_method_mock(lambda self: self.icache.accept_res_io, enable=lambda self: len(self.output_q) > 0)
def accept_res_mock(self):
return self.output_q.popleft()

def fetch_out_check(self):
while self.instr_queue:
Expand All @@ -254,12 +242,8 @@ def fetch_out_check(self):
yield from self.verify_branch.call(next_pc=instr["next_pc"])

def test(self):
issue_req_mock, accept_res_mock, cache_process = self.cache_processes()

self.gen_instr_seq()

with self.run_simulation(self.m) as sim:
sim.add_sync_process(issue_req_mock)
sim.add_sync_process(accept_res_mock)
sim.add_sync_process(cache_process)
sim.add_sync_process(self.cache_process)
sim.add_sync_process(self.fetch_out_check)
Loading

0 comments on commit 14efcc9

Please sign in to comment.