X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fopenpower%2Ftest%2Frunner.py;h=656e2b5bf948f15162c6d37ead2df22201f62582;hb=af3624a79b0506bfcb2ec96b33f651793eb93fa3;hp=8987c3f13522e33038ed0ee88f06e49614b8a7a3;hpb=1418c44189e4fbcaa60d352d48b5595b6c8af007;p=openpower-isa.git diff --git a/src/openpower/test/runner.py b/src/openpower/test/runner.py index 8987c3f1..656e2b5b 100644 --- a/src/openpower/test/runner.py +++ b/src/openpower/test/runner.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: LGPL-2-or-later """TestRunner class, part of the Test API SPDX-License: LGPLv2+ @@ -14,9 +15,10 @@ related bugs: * https://bugs.libre-soc.org/show_bug.cgi?id=686#c51 """ +from unittest.mock import Mock from nmigen import Module, ClockSignal -from copy import copy -from pprint import pprint +from copy import copy, deepcopy +from pprint import pformat # NOTE: to use cxxsim, export NMIGEN_SIM_MODE=cxxsim from the shell # Also, check out the cxxsim nmigen branch, and latest yosys from git @@ -29,24 +31,27 @@ from openpower.endian import bigendian from openpower.decoder.power_decoder2 import PowerDecode2 -from soc.config.test.test_loadstore import TestMemPspec from nmutil.util import wrap from openpower.test.wb_get import wb_get import openpower.test.wb_get as wbget from openpower.test.state import TestState, StateRunner, ExpectedState +from openpower.util import log, LogKind class SimRunner(StateRunner): """SimRunner: Implements methods for the setup, preparation, and running of tests using ISACaller simulation """ + def __init__(self, dut, m, pspec): super().__init__("sim", SimRunner) self.dut = dut self.mmu = pspec.mmu == True + fp_en = pspec.fp_en == True regreduce_en = pspec.regreduce_en == True - self.simdec2 = simdec2 = PowerDecode2(None, regreduce_en=regreduce_en) + self.simdec2 = simdec2 = PowerDecode2( + None, regreduce_en=regreduce_en, fp_en=fp_en) m.submodules.simdec2 = simdec2 # pain in the neck def prepare_for_test(self, test): @@ -68,15 +73,23 @@ class SimRunner(StateRunner): disassembly=insncode, bigendian=bigendian, initial_svstate=test.svstate, - mmu=self.mmu) + mmu=self.mmu, + fpregfile=test.fpregs, + initial_fpscr=test.initial_fpscr) # run the loop of the instructions on the current test index = sim.pc.CIA.value//4 while index < len(instructions): ins, code = instructions[index] - print("sim instr: 0x{:X}".format(ins & 0xffffffff)) - print(index, code) + # extra new-line so it's easier to visually separate each + # instruction in output + log(f"\n0x{sim.pc.CIA.value:04X}: {ins % (1 << 32):08X} {code}", + kind=LogKind.InstrInOuts) + + log("sim instr: 0x{:X} pc=0x{:X}".format(ins & 0xffffffff, + sim.pc.CIA.value)) + log(index, code) # set up simulated instruction (in simdec2) try: @@ -86,7 +99,7 @@ class SimRunner(StateRunner): yield Settle() # call simulated operation - print("sim", code) + log("sim", code) yield from sim.execute_one() yield Settle() index = sim.pc.CIA.value//4 @@ -95,6 +108,8 @@ class SimRunner(StateRunner): state = yield from TestState("sim", sim, dut, code) sim_states.append(state) + log(f"final pc: 0x{sim.pc.CIA.value:X}", kind=LogKind.InstrInOuts) + if self.dut.allow_overlap: # get last state, at end of run state = yield from TestState("sim", sim, dut, code) @@ -113,17 +128,20 @@ class TestRunnerBase(FHDLTestCase): When using an Expected state to test with, the expected state is passed in with tst_data. """ + def __init__(self, tst_data, microwatt_mmu=False, rom=None, - svp64=True, run_hdl=None, run_sim=True, - allow_overlap=False): + svp64=True, run_hdl=None, run_sim=True, + allow_overlap=False, inorder=False, fp=False): super().__init__("run_all") self.test_data = tst_data self.microwatt_mmu = microwatt_mmu self.rom = rom self.svp64 = svp64 self.allow_overlap = allow_overlap + self.inorder = inorder self.run_hdl = run_hdl self.run_sim = run_sim + self.fp = fp def run_all(self): m = Module() @@ -140,22 +158,25 @@ class TestRunnerBase(FHDLTestCase): ldst_ifacetype = 'test_bare_wb' imem_ifacetype = 'test_bare_wb' - pspec = TestMemPspec(ldst_ifacetype=ldst_ifacetype, - imem_ifacetype=imem_ifacetype, - addr_wid=48, - mask_wid=8, - imem_reg_wid=64, - # wb_data_width=32, - use_pll=False, - nocore=False, - xics=False, - gpio=False, - regreduce=not self.allow_overlap, - core_domain="sync", # no alternative domain - svp64=self.svp64, - allow_overlap=self.allow_overlap, - mmu=self.microwatt_mmu, - reg_wid=64) + pspec = Mock(ldst_ifacetype=ldst_ifacetype, + imem_ifacetype=imem_ifacetype, + addr_wid=64, + mask_wid=8, + XLEN=64, + imem_reg_wid=64, + # wb_data_width=32, + use_pll=False, + nocore=False, + xics=False, + gpio=False, + regreduce=not self.allow_overlap, + core_domain="sync", # no alternative domain + svp64=self.svp64, + allow_overlap=self.allow_overlap, + inorder=self.inorder, + mmu=self.microwatt_mmu, + reg_wid=64, + fp_en=self.fp) ###### SETUP PHASE ####### # Determine the simulations needed and add to state_list @@ -200,22 +221,60 @@ class TestRunnerBase(FHDLTestCase): # get each test, completely reset the core, and run it for test in self.test_data: - - with self.subTest(test.name): + with self.subTest(test.name, **test.subtest_args): ###### PREPARATION PHASE AT START OF TEST ####### + # HACK: if there is test memory and wb_get is in use, + # overwrite (reset) the wb_get memory dictionary with + # the test's memory contents (oh, and put the wb_get + # memory back in as well) + self.default_mem.clear() + if self.rom is not None: + self.default_mem.update(deepcopy(self.rom)) + if test.mem is not None: + self.default_mem.update(deepcopy(test.mem)) + for runner in state_list: yield from runner.prepare_for_test(test) - print(test.name) + log("running test: ", test.name, test.subtest_args, + kind=LogKind.InstrInOuts) program = test.program - print("regs", test.regs) - print("sprs", test.sprs) - print("cr", test.cr) - print("mem", test.mem) - print("msr", test.msr) - print("assem", program.assembly) + + def format_regs(regs): + # type: (list[int]) -> str + out = [] + for i, v in enumerate(regs): + values = "" + for sz in (32, 64): + for signed in ("u", "i"): + value = v % (1 << sz) + if signed == "i" and \ + value & (1 << (sz - 1)) != 0: + value -= 1 << sz + values += f" {signed}{sz}:{value}" + out.append(f"r{i} = 0x{v:X} {values}") + return "\n".join(out) + log("regs:", format_regs(test.regs), + kind=LogKind.InstrInOuts) + log("sprs", test.sprs, kind=LogKind.InstrInOuts) + log("cr", test.cr, kind=LogKind.InstrInOuts) + log("mem", test.mem) + log("msr", test.msr, kind=LogKind.InstrInOuts) + + def format_assembly(assembly): + # type: (str) -> str + pc = 0 + out = [] + for line in assembly.splitlines(): + out.append(f"pc=0x{pc:04X}: {line}") + if not line.startswith(".set ") and \ + line.partition('#')[0].strip() != "": + pc += 4 + return "\n".join(out) + log("assembly:\n" + format_assembly(program.assembly), + kind=LogKind.InstrInOuts) gen = list(program.generate_instructions()) insncode = program.assembly.splitlines() instructions = list(zip(gen, insncode)) @@ -244,8 +303,8 @@ class TestRunnerBase(FHDLTestCase): if self.run_sim: sim_states = yield from simrun.run_test( - instructions, gen, - insncode) + instructions, gen, + insncode) ###### COMPARING THE TESTS ####### @@ -262,34 +321,35 @@ class TestRunnerBase(FHDLTestCase): elif self.run_hdl: last_sim = copy(hdl_states[-1]) else: - last_sim = None # err what are you doing?? + last_sim = None # err what are you doing?? if self.run_hdl: - print ("hdl_states") + log("hdl_states") for state in hdl_states: - print (state) + log(state) - if self.run_sim: - print ("sim_states") - for state in sim_states: - print (state) + # FIXME: commented until SimState has a __repr__ + # if self.run_sim: + # log("sim_states") + # for state in sim_states: + # log(state) # compare the states if self.run_hdl and self.run_sim: # if allow_overlap is enabled, because allow_overlap # can commit out-of-order, only compare the last ones if self.allow_overlap: - print ("allow_overlap: truncating %d %d " - "states to last" % (len(sim_states), - len(hdl_states))) + log("allow_overlap: truncating %d %d " + "states to last" % (len(sim_states), + len(hdl_states))) sim_states = sim_states[-1:] hdl_states = hdl_states[-1:] sim_states[-1].dump_state_tofile() - print ("allow_overlap: last hdl_state") + log("allow_overlap: last hdl_state") hdl_states[-1].dump_state_tofile() for simstate, hdlstate in zip(sim_states, hdl_states): simstate.compare(hdlstate) # register check - simstate.compare_mem(hdlstate) # memory check + simstate.compare_mem(hdlstate) # memory check # if no expected, create /tmp/case_name.py with code # setting expected state to last_sim @@ -311,20 +371,20 @@ class TestRunnerBase(FHDLTestCase): n_hdl = len(hdl_states) n_sim = len(sim_states) self.assertTrue(n_hdl == n_sim, - "number of instructions %d %d " - "run not the same" % (n_hdl, n_sim)) + "number of instructions %d %d " + "run not the same" % (n_hdl, n_sim)) ###### END OF A TEST ####### # StateRunner.end_test() for runner in state_list: - yield from runner.end_test() # TODO, some arguments? + yield from runner.end_test() # TODO, some arguments? ###### END OF EVERYTHING (but none needs doing, still call fn) #### # StateRunner.cleanup() for runner in state_list: - yield from runner.cleanup() # TODO, some arguments? + yield from runner.cleanup() # TODO, some arguments? # finally stop wb_get from going if self.rom is not None: @@ -469,9 +529,13 @@ class TestRunnerBase(FHDLTestCase): 'core.l0.pimem.bus__dat_we', ] - write_gtkw("issuer_simulator.gtkw", - "issuer_simulator.vcd", - traces, styles, module='top.issuer') + gtkname = "issuer_simulator" + if self.rom: + gtkname += "_mmu" + + write_gtkw("%s.gtkw" % gtkname, + "%s.vcd" % gtkname, + traces, styles, module='bench.top.issuer') # add run of instructions sim.add_sync_process(process) @@ -482,16 +546,17 @@ class TestRunnerBase(FHDLTestCase): # optionally, if a wishbone-based ROM is passed in, run that as an # extra emulated process + self.default_mem = {} if self.rom is not None: - print ("TestRunner with MMU ROM") - pprint (self.rom) + log("TestRunner with MMU ROM") + log(pformat(self.rom)) dcache = hdlrun.issuer.core.fus.fus["mmu0"].alu.dcache icache = hdlrun.issuer.core.fus.fus["mmu0"].alu.icache - default_mem = self.rom + self.default_mem = deepcopy(self.rom) sim.add_sync_process(wrap(wb_get(dcache.bus, - default_mem, "DCACHE"))) + self.default_mem, "DCACHE"))) sim.add_sync_process(wrap(wb_get(icache.ibus, - default_mem, "ICACHE"))) + self.default_mem, "ICACHE"))) - with sim.write_vcd("issuer_simulator.vcd"): + with sim.write_vcd("%s.vcd" % gtkname): sim.run()