From: Luke Kenneth Casson Leighton Date: Fri, 1 Oct 2021 16:54:39 +0000 (+0100) Subject: move TestRunner to openpower-isa now that it is part of the Test API X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b92900d30a555a0b05edc1f5b51ad576a494e387;p=soc.git move TestRunner to openpower-isa now that it is part of the Test API https://bugs.libre-soc.org/show_bug.cgi?id=686 commit 5d5a1807d553985c25bdc8bf4d04aedfecddf34f openpower-isa repo --- diff --git a/src/soc/simple/test/test_runner.py b/src/soc/simple/test/test_runner.py index 096bb88c..461007de 100644 --- a/src/soc/simple/test/test_runner.py +++ b/src/soc/simple/test/test_runner.py @@ -5,7 +5,7 @@ related bugs: * https://bugs.libre-soc.org/show_bug.cgi?id=363 * https://bugs.libre-soc.org/show_bug.cgi?id=686#c51 """ -from nmigen import Module, Signal, Cat, ClockSignal +from nmigen import Module, Signal from nmigen.hdl.xfrm import ResetInserter from copy import copy @@ -13,17 +13,10 @@ from copy import copy # Also, check out the cxxsim nmigen branch, and latest yosys from git from nmutil.sim_tmp_alternative import Simulator, Settle -from nmutil.formaltest import FHDLTestCase -from nmutil.gtkw import write_gtkw -from nmigen.cli import rtlil -from openpower.decoder.isa.caller import special_sprs, SVP64State +from openpower.decoder.isa.caller import SVP64State from openpower.decoder.isa.all import ISA from openpower.endian import bigendian -from openpower.decoder.power_decoder import create_pdecode -from openpower.decoder.power_decoder2 import PowerDecode2 -from soc.regfile.regfiles import StateRegs - from soc.simple.issuer import TestIssuerInternal from soc.config.test.test_loadstore import TestMemPspec @@ -36,6 +29,7 @@ from soc.debug.dmi import DBGCore, DBGCtrl, DBGStat from nmutil.util import wrap from soc.experiment.test.test_mmu_dcache import wb_get from openpower.test.state import TestState, StateRunner +from openpower.test.runner import TestRunnerBase def setup_i_memory(imem, startaddr, instructions): @@ -124,63 +118,6 @@ def get_dmi(dmi, addr): return data -class SimRunner(StateRunner): - def __init__(self, dut, m, pspec): - super().__init__("sim", SimRunner) - self.dut = dut - - regreduce_en = pspec.regreduce_en == True - self.simdec2 = simdec2 = PowerDecode2(None, regreduce_en=regreduce_en) - m.submodules.simdec2 = simdec2 # pain in the neck - - def prepare_for_test(self, test): - self.test = test - if False: - yield - - def run_test(self, instructions, gen, insncode): - """run_sim_state - runs an ISACaller simulation - """ - - dut, test, simdec2 = self.dut, self.test, self.simdec2 - sim_states = [] - - # set up the Simulator (which must track TestIssuer exactly) - sim = ISA(simdec2, test.regs, test.sprs, test.cr, test.mem, - test.msr, - initial_insns=gen, respect_pc=True, - disassembly=insncode, - bigendian=bigendian, - initial_svstate=test.svstate) - - # 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) - - # set up simulated instruction (in simdec2) - try: - yield from sim.setup_one() - except KeyError: # instruction not in imem: stop - break - yield Settle() - - # call simulated operation - print("sim", code) - yield from sim.execute_one() - yield Settle() - index = sim.pc.CIA.value//4 - - # get sim register and memory TestState, add to list - state = yield from TestState("sim", sim, dut, code) - sim_states.append(state) - - return sim_states - - class HDLRunner(StateRunner): def __init__(self, dut, m, pspec): super().__init__("hdl", HDLRunner) @@ -335,327 +272,12 @@ class HDLRunner(StateRunner): yield -class TestRunner(FHDLTestCase): +class TestRunner(TestRunnerBase): def __init__(self, tst_data, microwatt_mmu=False, rom=None, svp64=True, run_hdl=True, run_sim=True): - super().__init__("run_all") - self.test_data = tst_data - self.microwatt_mmu = microwatt_mmu - self.rom = rom - self.svp64 = svp64 - self.run_hdl = run_hdl - self.run_sim = run_sim - - def run_all(self): - m = Module() - comb = m.d.comb - if self.microwatt_mmu: - ldst_ifacetype = 'test_mmu_cache_wb' - else: - 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=True, - svp64=self.svp64, - mmu=self.microwatt_mmu, - reg_wid=64) - - ###### SETUP PHASE ####### - # StateRunner.setup_for_test() - - state_list = [] - - # TODO https://bugs.libre-soc.org/show_bug.cgi?id=686#c73 - if self.run_hdl: - hdlrun = HDLRunner(self, m, pspec) - state_list.append(hdlrun) - - if self.run_sim: - simrun = SimRunner(self, m, pspec) - state_list.append(simrun) - - # run core clock at same rate as test clock - # XXX this has to stay here! TODO, work out why, - # but Simulation-only fails without it - intclk = ClockSignal("coresync") - comb += intclk.eq(ClockSignal()) - - # nmigen Simulation - everything runs around this, so it - # still has to be created. - sim = Simulator(m) - sim.add_clock(1e-6) - - def process(): - - ###### PREPARATION PHASE AT START OF RUNNING ####### - # StateRunner.setup_during_test() - # TODO https://bugs.libre-soc.org/show_bug.cgi?id=686#c73 - # but "normalise" the APIs, make openpower-isa StateRunner - # dummy "yield" functions so if they're not provided at least - # there is a fallback which can be "yielded". - - for runner in state_list: - yield from runner.setup_during_test() - - # get each test, completely reset the core, and run it - - for test in self.test_data: - - with self.subTest(test.name): - - ###### PREPARATION PHASE AT START OF TEST ####### - # StateRunner.prepare_for_test() - # TODO https://bugs.libre-soc.org/show_bug.cgi?id=686#c73 - - for runner in state_list: - yield from runner.prepare_for_test(test) - - print(test.name) - 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) - gen = list(program.generate_instructions()) - insncode = program.assembly.splitlines() - instructions = list(zip(gen, insncode)) - - ###### RUNNING OF EACH TEST ####### - # StateRunner.step_test() - - # Run two tests (TODO, move these to functions) - # * first the Simulator, collate a batch of results - # * then the HDL, likewise - # (actually, the other way round because running - # Simulator somehow modifies the test state!) - # * finally, compare all the results - - # TODO https://bugs.libre-soc.org/show_bug.cgi?id=686#c73 - - ########## - # 1. HDL - ########## - if self.run_hdl: - hdl_states = yield from hdlrun.run_test(instructions) - - ########## - # 2. Simulator - ########## - - if self.run_sim: - sim_states = yield from simrun.run_test( - instructions, gen, - insncode) - - ###### COMPARING THE TESTS ####### - - ############### - # 3. Compare - ############### - - # TODO: here just grab one entry from list_of_sim_runners - # (doesn't matter which one, honestly) - # TODO https://bugs.libre-soc.org/show_bug.cgi?id=686#c73 - - if self.run_sim: - last_sim = copy(sim_states[-1]) - elif self.run_hdl: - last_sim = copy(hdl_states[-1]) - else: - last_sim = None # err what are you doing?? - - if self.run_hdl: - print ("hdl_states") - for state in hdl_states: - print (state) - - if self.run_sim: - print ("sim_states") - for state in sim_states: - print (state) - - if self.run_hdl and self.run_sim: - for simstate, hdlstate in zip(sim_states, hdl_states): - simstate.compare(hdlstate) # register check - simstate.compare_mem(hdlstate) # memory check - - # compare against expected results - if test.expected is not None: - # have to put these in manually - test.expected.to_test = test.expected - test.expected.dut = self - test.expected.state_type = "expected" - test.expected.code = 0 - # do actual comparison, against last item - last_sim.compare(test.expected) - - if self.run_hdl and self.run_sim: - self.assertTrue(len(hdl_states) == len(sim_states), - "number of instructions run not the same") - - ###### END OF A TEST ####### - # StateRunner.end_test() - # TODO https://bugs.libre-soc.org/show_bug.cgi?id=686#c73 - - for runner in state_list: - yield from runner.end_test() # TODO, some arguments? - - ###### END OF EVERYTHING (but none needs doing, still call fn) #### - # StateRunner.cleanup() - # TODO https://bugs.libre-soc.org/show_bug.cgi?id=686#c73 - - for runner in state_list: - yield from runner.cleanup() # TODO, some arguments? - - styles = { - 'dec': {'base': 'dec'}, - 'bin': {'base': 'bin'}, - 'closed': {'closed': True} - } - - traces = [ - 'clk', - ('state machines', 'closed', [ - 'fetch_pc_i_valid', 'fetch_pc_o_ready', - 'fetch_fsm_state', - 'fetch_insn_o_valid', 'fetch_insn_i_ready', - 'pred_insn_i_valid', 'pred_insn_o_ready', - 'fetch_predicate_state', - 'pred_mask_o_valid', 'pred_mask_i_ready', - 'issue_fsm_state', - 'exec_insn_i_valid', 'exec_insn_o_ready', - 'exec_fsm_state', - 'exec_pc_o_valid', 'exec_pc_i_ready', - 'insn_done', 'core_stop_o', 'pc_i_ok', 'pc_changed', - 'is_last', 'dec2.no_out_vec']), - {'comment': 'fetch and decode'}, - (None, 'dec', [ - 'cia[63:0]', 'nia[63:0]', 'pc[63:0]', - 'cur_pc[63:0]', 'core_core_cia[63:0]']), - 'raw_insn_i[31:0]', - 'raw_opcode_in[31:0]', 'insn_type', 'dec2.dec2_exc_happened', - ('svp64 decoding', 'closed', [ - 'svp64_rm[23:0]', ('dec2.extra[8:0]', 'bin'), - 'dec2.sv_rm_dec.mode', 'dec2.sv_rm_dec.predmode', - 'dec2.sv_rm_dec.ptype_in', - 'dec2.sv_rm_dec.dstpred[2:0]', 'dec2.sv_rm_dec.srcpred[2:0]', - 'dstmask[63:0]', 'srcmask[63:0]', - 'dregread[4:0]', 'dinvert', - 'sregread[4:0]', 'sinvert', - 'core.int.pred__addr[4:0]', 'core.int.pred__data_o[63:0]', - 'core.int.pred__ren']), - ('register augmentation', 'dec', 'closed', [ - {'comment': 'v3.0b registers'}, - 'dec2.dec_o.RT[4:0]', - 'dec2.dec_a.RA[4:0]', - 'dec2.dec_b.RB[4:0]', - ('Rdest', [ - 'dec2.o_svdec.reg_in[4:0]', - ('dec2.o_svdec.spec[2:0]', 'bin'), - 'dec2.o_svdec.reg_out[6:0]']), - ('Rsrc1', [ - 'dec2.in1_svdec.reg_in[4:0]', - ('dec2.in1_svdec.spec[2:0]', 'bin'), - 'dec2.in1_svdec.reg_out[6:0]']), - ('Rsrc1', [ - 'dec2.in2_svdec.reg_in[4:0]', - ('dec2.in2_svdec.spec[2:0]', 'bin'), - 'dec2.in2_svdec.reg_out[6:0]']), - {'comment': 'SVP64 registers'}, - 'dec2.rego[6:0]', 'dec2.reg1[6:0]', 'dec2.reg2[6:0]' - ]), - {'comment': 'svp64 context'}, - 'core_core_vl[6:0]', 'core_core_maxvl[6:0]', - 'core_core_srcstep[6:0]', 'next_srcstep[6:0]', - 'core_core_dststep[6:0]', - {'comment': 'issue and execute'}, - 'core.core_core_insn_type', - (None, 'dec', [ - 'core_rego[6:0]', 'core_reg1[6:0]', 'core_reg2[6:0]']), - 'issue_i', 'busy_o', - {'comment': 'dmi'}, - 'dbg.dmi_req_i', 'dbg.dmi_ack_o', - {'comment': 'instruction memory'}, - 'imem.sram.rdport.memory(0)[63:0]', - {'comment': 'registers'}, - # match with soc.regfile.regfiles.IntRegs port names - 'core.int.rp_src1.memory(0)[63:0]', - 'core.int.rp_src1.memory(1)[63:0]', - 'core.int.rp_src1.memory(2)[63:0]', - 'core.int.rp_src1.memory(3)[63:0]', - 'core.int.rp_src1.memory(4)[63:0]', - 'core.int.rp_src1.memory(5)[63:0]', - 'core.int.rp_src1.memory(6)[63:0]', - 'core.int.rp_src1.memory(7)[63:0]', - 'core.int.rp_src1.memory(9)[63:0]', - 'core.int.rp_src1.memory(10)[63:0]', - 'core.int.rp_src1.memory(13)[63:0]' - ] - - # PortInterface module path varies depending on MMU option - if self.microwatt_mmu: - pi_module = 'core.ldst0' - else: - pi_module = 'core.fus.ldst0' - - traces += [('ld/st port interface', {'submodule': pi_module}, [ - 'oper_r__insn_type', - 'ldst_port0_is_ld_i', - 'ldst_port0_is_st_i', - 'ldst_port0_busy_o', - 'ldst_port0_addr_i[47:0]', - 'ldst_port0_addr_i_ok', - 'ldst_port0_addr_ok_o', - 'ldst_port0_exc_happened', - 'ldst_port0_st_data_i[63:0]', - 'ldst_port0_st_data_i_ok', - 'ldst_port0_ld_data_o[63:0]', - 'ldst_port0_ld_data_o_ok', - 'exc_o_happened', - 'cancel' - ])] - - if self.microwatt_mmu: - traces += [ - {'comment': 'microwatt_mmu'}, - 'core.fus.mmu0.alu_mmu0.illegal', - 'core.fus.mmu0.alu_mmu0.debug0[3:0]', - 'core.fus.mmu0.alu_mmu0.mmu.state', - 'core.fus.mmu0.alu_mmu0.mmu.pid[31:0]', - 'core.fus.mmu0.alu_mmu0.mmu.prtbl[63:0]', - {'comment': 'wishbone_memory'}, - 'core.fus.mmu0.alu_mmu0.dcache.stb', - 'core.fus.mmu0.alu_mmu0.dcache.cyc', - 'core.fus.mmu0.alu_mmu0.dcache.we', - 'core.fus.mmu0.alu_mmu0.dcache.ack', - 'core.fus.mmu0.alu_mmu0.dcache.stall,' - ] - - write_gtkw("issuer_simulator.gtkw", - "issuer_simulator.vcd", - traces, styles, module='top.issuer') - - # add run of instructions - sim.add_sync_process(process) - - # optionally, if a wishbone-based ROM is passed in, run that as an - # extra emulated process - if self.rom is not None: - dcache = core.fus.fus["mmu0"].alu.dcache - default_mem = self.rom - sim.add_sync_process(wrap(wb_get(dcache, default_mem, "DCACHE"))) - - with sim.write_vcd("issuer_simulator.vcd"): - sim.run() + if run_hdl: + run_hdl = HDLRunner + super().__init__(tst_data, microwatt_mmu=microwatt_mmu, + rom=rom, + svp64=svp64, run_hdl=run_hdl, run_sim=run_sim) +