- ccache
- .cache/pip
- apt-cache
+ when: 'always'
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
- pip install dist/sfpy*.whl
- popd
- - cargo install maturin
+ - python3 -m pip install 'maturin>=0.11,<0.12'
- git clone --depth 1 https://git.libre-soc.org/git/power-instruction-analyzer.git pia
- pushd pia
- maturin build --cargo-extra-args=--features=python-extension
and (as long as there was no exception) the data comes out (at any
time from the PortInterface), and is captured by the LDCompSTUnit.
+TODO: dcbz, yes, that's going to be complicated, has to be done
+ with great care, to detect the case when dcbz is set
+ and *not* expect to read any data, just the address.
+ so, wait for RA but not RB.
+
Both LD and ST may request that the address be computed from summing
operand1 (src[0]) with operand2 (src[1]) *or* by summing operand1 with
the immediate (from the opcode).
# opcode decode
op_is_ld = Signal(reset_less=True)
op_is_st = Signal(reset_less=True)
+ op_is_dcbz = Signal(reset_less=True)
# ALU/LD data output control
alu_valid = Signal(reset_less=True) # ALU operands are valid
# decode bits of operand (latched)
oper_r = CompLDSTOpSubset(name="oper_r") # Dest register
- comb += op_is_st.eq(oper_r.insn_type == MicrOp.OP_STORE) # ST
- comb += op_is_ld.eq(oper_r.insn_type == MicrOp.OP_LOAD) # LD
- comb += Display("compldst_multi: op_is_dcbz = %i",
- (oper_r.insn_type == MicrOp.OP_DCBZ))
+ comb += op_is_st.eq(oper_r.insn_type == MicrOp.OP_STORE) # ST
+ comb += op_is_ld.eq(oper_r.insn_type == MicrOp.OP_LOAD) # LD
+ comb += op_is_dcbz.eq(oper_r.insn_type == MicrOp.OP_DCBZ) # DCBZ
+ #uncomment if needed
+ #comb += Display("compldst_multi: op_is_dcbz = %i",
+ # (oper_r.insn_type == MicrOp.OP_DCBZ))
op_is_update = oper_r.ldst_mode == LDSTMode.update # UPDATE
op_is_cix = oper_r.ldst_mode == LDSTMode.cix # cache-inhibit
comb += self.load_mem_o.eq(op_is_ld & self.go_ad_i)
--- /dev/null
+# test case for LOAD / STORE Computation Unit using MMU
+
+from nmigen.compat.sim import run_simulation
+from nmigen.cli import verilog, rtlil
+from nmigen import Module, Signal, Mux, Cat, Elaboratable, Array, Repl
+from nmigen.hdl.rec import Record, Layout
+
+from nmutil.latch import SRLatch, latchregister
+from nmutil.byterev import byte_reverse
+from nmutil.extend import exts
+from soc.fu.regspec import RegSpecAPI
+
+from openpower.decoder.power_enums import MicrOp, Function, LDSTMode
+from soc.fu.ldst.ldst_input_record import CompLDSTOpSubset
+from openpower.decoder.power_decoder2 import Data
+from openpower.consts import MSR
+
+from soc.experiment.compalu_multi import go_record, CompUnitRecord
+from soc.experiment.l0_cache import PortInterface
+from soc.experiment.pimem import LDSTException
+from soc.experiment.compldst_multi import LDSTCompUnit
+from soc.config.test.test_loadstore import TestMemPspec
+
+from soc.experiment.mmu import MMU
+
+########################################
+
+def dcbz(dut, src1, src2, src3, imm, imm_ok=True, update=False,
+ byterev=True):
+ print("DCBZ", src1, src2, src3, imm, imm_ok, update)
+ yield dut.oper_i.insn_type.eq(MicrOp.OP_DCBZ)
+ yield dut.oper_i.data_len.eq(2) # half-word
+ yield dut.oper_i.byte_reverse.eq(byterev)
+ yield dut.src1_i.eq(src1)
+ yield dut.src2_i.eq(src2)
+ yield dut.src3_i.eq(src3)
+ yield dut.oper_i.imm_data.data.eq(imm)
+ yield dut.oper_i.imm_data.ok.eq(imm_ok)
+ #FIXME: -- yield dut.oper_i.update.eq(update)
+ yield dut.issue_i.eq(1)
+ yield
+ yield dut.issue_i.eq(0)
+
+ if imm_ok:
+ active_rel = 0b101
+ else:
+ active_rel = 0b111
+ # wait for all active rel signals to come up
+ # guess: bug is here
+ #while True:
+ # rel = yield dut.rd.rel_o
+ # if rel == active_rel:
+ # break
+ # yield
+ #yield dut.rd.go_i.eq(active_rel)
+ #yield
+ #yield dut.rd.go_i.eq(0)
+
+ #yield from wait_for(dut.adr_rel_o, False, test1st=True)
+ # yield from wait_for(dut.adr_rel_o)
+ # yield dut.ad.go.eq(1)
+ # yield
+ # yield dut.ad.go.eq(0)
+
+ #if update:
+ # yield from wait_for(dut.wr.rel_o[1])
+ # yield dut.wr.go.eq(0b10)
+ # yield
+ # addr = yield dut.addr_o
+ # print("addr", addr)
+ # yield dut.wr.go.eq(0)
+ #else:
+ # addr = None
+
+ # commented out for debugging
+ #yield from wait_for(dut.sto_rel_o)
+ #yield dut.go_st_i.eq(1)
+ #yield
+ #yield dut.go_st_i.eq(0)
+ #yield from wait_for(dut.busy_o, False)
+ # wait_for(dut.stwd_mem_o)
+ #yield
+ #return addr
+
+
+def ldst_sim(dut):
+ yield from dcbz(dut, 4, 0, 3, 2) # FIXME
+ yield
+
+########################################
+
+
+class TestLDSTCompUnitMMU(LDSTCompUnit):
+
+ def __init__(self, rwid, pspec):
+ from soc.experiment.l0_cache import TstL0CacheBuffer
+ self.l0 = l0 = TstL0CacheBuffer(pspec)
+ pi = l0.l0.dports[0]
+ LDSTCompUnit.__init__(self, pi, rwid, 4)
+
+ def elaborate(self, platform):
+ m = LDSTCompUnit.elaborate(self, platform)
+ m.submodules.l0 = self.l0
+ # link addr-go direct to rel
+ m.d.comb += self.ad.go_i.eq(self.ad.rel_o)
+ return m
+
+
+def test_scoreboard_mmu():
+
+ units = {}
+ pspec = TestMemPspec(ldst_ifacetype='mmu_cache_wb',
+ imem_ifacetype='bare_wb',
+ addr_wid=48,
+ mask_wid=8,
+ reg_wid=64,
+ units=units)
+
+ dut = TestLDSTCompUnitMMU(16,pspec)
+ vl = rtlil.convert(dut, ports=dut.ports())
+ with open("test_ldst_comp_mmu1.il", "w") as f:
+ f.write(vl)
+
+ run_simulation(dut, ldst_sim(dut), vcd_name='test_ldst_comp.vcd')
+
+########################################
+class TestLDSTCompUnitRegSpecMMU(LDSTCompUnit):
+
+ def __init__(self, pspec):
+ from soc.experiment.l0_cache import TstL0CacheBuffer
+ from soc.fu.ldst.pipe_data import LDSTPipeSpec
+ regspec = LDSTPipeSpec.regspec
+ self.l0 = l0 = TstL0CacheBuffer(pspec)
+ self.mmu = MMU()
+ pi = l0.l0.dports[0]
+ LDSTCompUnit.__init__(self, pi, regspec, 4)
+
+ def elaborate(self, platform):
+ m = LDSTCompUnit.elaborate(self, platform)
+ m.submodules.l0 = self.l0
+ m.submodules.mmu = self.mmu
+ # link addr-go direct to rel
+ m.d.comb += self.ad.go_i.eq(self.ad.rel_o)
+
+ # link mmu and dcache together
+ dcache = self.l0.pimem.dcache
+ mmu = self.mmu
+ m.d.comb += dcache.m_in.eq(mmu.d_out) # MMUToDCacheType
+ m.d.comb += mmu.d_in.eq(dcache.m_out) # DCacheToMMUType
+
+
+ return m
+
+
+def test_scoreboard_regspec_mmu():
+
+ units = {}
+ pspec = TestMemPspec(ldst_ifacetype='mmu_cache_wb',
+ imem_ifacetype='bare_wb',
+ addr_wid=48,
+ mask_wid=8,
+ reg_wid=64,
+ units=units)
+
+ dut = TestLDSTCompUnitRegSpecMMU(pspec)
+
+ # TODO: setup pagetables for MMU
+
+ vl = rtlil.convert(dut, ports=dut.ports())
+ with open("test_ldst_comp_mmu2.il", "w") as f:
+ f.write(vl)
+
+ run_simulation(dut, ldst_sim(dut), vcd_name='test_ldst_regspec.vcd')
+
+
+if __name__ == '__main__':
+ test_scoreboard_regspec_mmu()
+ #only one test for now -- test_scoreboard_mmu()
self.excs[name] = alu.exc_o
def get_exc(self, name):
- return self.excs.get(name, default=None)
+ return self.excs.get(name)
def get_fu(self, name):
return self.fus.get(name)
yield
while True:
yield
- rd_rel = yield dut.rd.rel
+ rd_rel = yield dut.rd.rel_o
if rd_rel != 0:
break
- yield dut.rd.go.eq(0xfff)
+ yield dut.rd.go_i.eq(0xfff)
yield
- yield dut.rd.go.eq(0)
+ yield dut.rd.go_i.eq(0)
for i in range(10):
yield
from openpower.decoder.power_decoder2 import PowerDecode2, get_rdflags
from openpower.decoder.power_enums import Function
from openpower.decoder.isa.all import ISA
+from openpower.decoder.isa.mem import Mem
from soc.experiment.compalu_multi import find_ok # hack
from soc.config.test.test_loadstore import TestMemPspec
return mem.mem
-def setup_tst_memory(l0, sim):
+def setup_tst_memory(l0, test_mem):
+ # create independent Sim Mem from test values
+ sim_mem = Mem(initial_mem=test_mem)
mem = get_l0_mem(l0)
print("before, init mem", mem.depth, mem.width, mem)
for i in range(mem.depth):
- data = sim.mem.ld(i*8, 8, False)
+ data = sim_mem.ld(i*8, 8, False)
print("init ", i, hex(data))
yield mem._array[i].eq(data)
yield Settle()
- for k, v in sim.mem.mem.items():
+ for k, v in sim_mem.mem.items():
print(" %6x %016x" % (k, v))
print("before, nmigen mem dump")
for i in range(mem.depth):
# initialise memory
if self.funit == Function.LDST:
- yield from setup_tst_memory(l0, sim)
+ yield from setup_tst_memory(l0, test.mem)
pc = sim.pc.CIA.value
index = pc//4
import unittest
from openpower.decoder.power_enums import (XER_bits, Function)
-from soc.fu.div.test.test_pipe_caller import get_cu_inputs
+from soc.fu.div.test.helper import get_cu_inputs
from soc.fu.div.test.test_pipe_caller import DivTestCases # creates the tests
from openpower.test.common import ALUHelpers
overflow = pia.OverflowFlags(so=bool(so),
ov=False,
ov32=False)
+ immediate_ok = yield dec2.e.do.imm_data.ok
+ if immediate_ok:
+ immediate = yield dec2.e.do.imm_data.data
+ else:
+ immediate = None
rc = inp["rc"] if has_third_input else None
return pia.InstructionInput(ra=inp.get("ra"), rb=inp.get("rb"),
+ immediate=immediate,
rc=rc, overflow=overflow)
opname = code.split(' ')[0]
fnname = opname.replace(".", "_")
print(f"{fnname}({pia_inputs})")
- pia_res = None
- try:
- pia_res = getattr(pia, fnname)(pia_inputs)
- except AttributeError:
- EXPECTED_FAILURES = ["mulli"]
- if fnname not in EXPECTED_FAILURES:
- raise
- else:
- print("not implemented, as expected.")
+ pia_res = getattr(pia, fnname)(pia_inputs)
print(f"-> {pia_res}")
yield from isa_sim.call(opname)
# and svp64 bit-rev'd ldst mode
ldst_dec = pdecode2.use_svp64_ldst_dec
sync += core.use_svp64_ldst_dec.eq(ldst_dec)
+ # after decoding, reset any previous exception condition,
+ # allowing it to be set again during the next execution
+ sync += pdecode2.ldst_exc.eq(0)
m.next = "INSN_EXECUTE" # move to "execute"
with m.If(~dbg.core_stop_o & ~core_rst):
comb += exec_pc_i_ready.eq(1)
# see https://bugs.libre-soc.org/show_bug.cgi?id=636
- #with m.If(exec_pc_o_valid & exc_happened):
- # probably something like this:
- # sync += pdecode2.ldst_exc.eq(core.fus.get_exc("ldst0")
- # TODO: the exception info needs to be blatted
- # into pdecode.ldst_exc, and the instruction "re-run".
+ # the exception info needs to be blatted into
+ # pdecode.ldst_exc, and the instruction "re-run".
# when ldst_exc.happened is set, the PowerDecoder2
# reacts very differently: it re-writes the instruction
# with a "trap" (calls PowerDecoder2.trap()) which
# PC to the exception address, as well as alter MSR.
# nothing else needs to be done other than to note
# the change of PC and MSR (and, later, SVSTATE)
- #with m.Elif(exec_pc_o_valid):
- with m.If(exec_pc_o_valid): # replace with Elif (above)
+ with m.If(exc_happened):
+ sync += pdecode2.ldst_exc.eq(core.fus.get_exc("ldst0"))
+
+ with m.If(exec_pc_o_valid):
# was this the last loop iteration?
is_last = Signal()
cur_vl = cur_state.svstate.vl
comb += is_last.eq(next_srcstep == cur_vl)
+ # return directly to Decode if Execute generated an
+ # exception.
+ with m.If(pdecode2.ldst_exc.happened):
+ m.next = "DECODE_SV"
+
# if either PC or SVSTATE were changed by the previous
# instruction, go directly back to Fetch, without
# updating either PC or SVSTATE
- with m.If(pc_changed | sv_changed):
+ with m.Elif(pc_changed | sv_changed):
m.next = "ISSUE_START"
# also return to Fetch, when no output was a vector
with m.If(~core_busy_o): # instruction done!
comb += exec_pc_o_valid.eq(1)
with m.If(exec_pc_i_ready):
- comb += self.insn_done.eq(1)
+ # when finished, indicate "done".
+ # however, if there was an exception, the instruction
+ # is *not* yet done. this is an implementation
+ # detail: we choose to implement exceptions by
+ # taking the exception information from the LDST
+ # unit, putting that *back* into the PowerDecoder2,
+ # and *re-running the entire instruction*.
+ # if we erroneously indicate "done" here, it is as if
+ # there were *TWO* instructions:
+ # 1) the failed LDST 2) a TRAP.
+ with m.If(~pdecode2.ldst_exc.happened):
+ comb += self.insn_done.eq(1)
m.next = "INSN_START" # back to fetch
def setup_peripherals(self, m):
related bugs:
* https://bugs.libre-soc.org/show_bug.cgi?id=363
+ * https://bugs.libre-soc.org/show_bug.cgi?id=686
"""
+
from nmigen import Module, Signal, Cat
from nmigen.back.pysim import Simulator, Delay, Settle
from nmutil.formaltest import FHDLTestCase
from nmigen.cli import rtlil
import unittest
+from openpower.test.state import (SimState, teststate_check_regs,
+ teststate_check_mem)
+from soc.simple.test.teststate import HDLState
from openpower.decoder.isa.caller import special_sprs
from openpower.decoder.power_decoder import create_pdecode
from openpower.decoder.power_decoder2 import PowerDecode2
# list of SPRs that are controlled and managed by the MMU
mmu_sprs = ["PRTBL", "DSISR", "DAR", "PIDR"]
-def set_mmu_spr(name, i, val, core): #important keep pep8 formatting
- fsm = core.fus.get_fu("mmu0").alu
- yield fsm.mmu.l_in.mtspr.eq(1)
- yield fsm.mmu.l_in.sprn.eq(i)
- yield fsm.mmu.l_in.rs.eq(val)
- yield
- yield fsm.mmu.l_in.mtspr.eq(0)
- print("mmu_spr was updated")
+
+def set_mmu_spr(name, i, val, core): # important keep pep8 formatting
+ fsm = core.fus.get_fu("mmu0").alu
+ yield fsm.mmu.l_in.mtspr.eq(1)
+ yield fsm.mmu.l_in.sprn.eq(i)
+ yield fsm.mmu.l_in.rs.eq(val)
+ yield
+ yield fsm.mmu.l_in.mtspr.eq(0)
+ print("mmu_spr was updated")
+
def setup_regs(pdecode2, core, test):
print("setup cr reg", hex(cr))
for i in range(8):
#j = 7-i
- cri = (cr >> (i*4)) & 0xf
+ cri = (cr >> (i * 4)) & 0xf
#cri = int('{:04b}'.format(cri)[::-1], 2)
print("setup cr reg", hex(cri), i,
crregs.regs[i].reg.shape())
if sprname == x.name:
print("setting slow SPR %d (%s) to %x" %
(i, sprname, val))
- if not sprname in mmu_sprs:
+ if sprname not in mmu_sprs:
yield sregs.memory._array[i].eq(val)
else:
yield from set_mmu_spr(sprname, i, val, core)
def check_regs(dut, sim, core, test, code):
- # int regs
- intregs = []
- for i in range(32):
- if core.regs.int.unary:
- rval = yield core.regs.int.regs[i].reg
- else:
- rval = yield core.regs.int.memory._array[i]
- intregs.append(rval)
- print("int regs", list(map(hex, intregs)))
- for i in range(32):
- simregval = sim.gpr[i].asint()
- dut.assertEqual(simregval, intregs[i],
- "int reg %d not equal %s. got %x expected %x" % \
- (i, repr(code), simregval, intregs[i]))
-
- # CRs
- crregs = []
- for i in range(8):
- rval = yield core.regs.cr.regs[i].reg
- crregs.append(rval)
- print("cr regs", list(map(hex, crregs)))
- for i in range(8):
- rval = crregs[i]
- cri = sim.crl[7-i].get_range().value
- print("cr reg", i, hex(cri), i, hex(rval))
- # XXX https://bugs.libre-soc.org/show_bug.cgi?id=363
- dut.assertEqual(cri, rval,
- "cr reg %d not equal %s" % (i, repr(code)))
-
- # XER
- xregs = core.regs.xer
- so = yield xregs.regs[xregs.SO].reg
- ov = yield xregs.regs[xregs.OV].reg
- ca = yield xregs.regs[xregs.CA].reg
-
- print("sim SO", sim.spr['XER'][XER_bits['SO']])
- e_so = sim.spr['XER'][XER_bits['SO']].value
- e_ov = sim.spr['XER'][XER_bits['OV']].value
- e_ov32 = sim.spr['XER'][XER_bits['OV32']].value
- e_ca = sim.spr['XER'][XER_bits['CA']].value
- e_ca32 = sim.spr['XER'][XER_bits['CA32']].value
-
- e_ov = e_ov | (e_ov32 << 1)
- e_ca = e_ca | (e_ca32 << 1)
+ # create the two states and compare
+ testdic = {'sim': sim, 'hdl': core}
+ yield from teststate_check_regs(dut, testdic, test, code)
- print("after: so/ov-32/ca-32", so, bin(ov), bin(ca))
- dut.assertEqual(e_so, so, "so mismatch %s" % (repr(code)))
- dut.assertEqual(e_ov, ov, "ov mismatch %s" % (repr(code)))
- dut.assertEqual(e_ca, ca, "ca mismatch %s" % (repr(code)))
- # Check the PC as well
- state = core.regs.state
- pc = yield state.r_ports['cia'].o_data
- e_pc = sim.pc.CIA.value
- dut.assertEqual(e_pc, pc)
+def check_mem(dut, sim, core, test, code):
+ # create the two states and compare mem
+ testdic = {'sim': sim, 'hdl': core}
+ yield from teststate_check_mem(dut, testdic, test, code)
def wait_for_busy_hi(cu):
for test in self.test_data:
print(test.name)
program = test.program
- self.subTest(test.name)
- sim = ISA(pdecode2, test.regs, test.sprs, test.cr, test.mem,
- test.msr,
- bigendian=bigendian)
- gen = program.generate_instructions()
- instructions = list(zip(gen, program.assembly.splitlines()))
-
- yield from setup_tst_memory(l0, sim)
- yield from setup_regs(core, test)
-
- index = sim.pc.CIA.value//4
- while index < len(instructions):
- ins, code = instructions[index]
-
- print("instruction: 0x{:X}".format(ins & 0xffffffff))
- print(code)
-
- # ask the decoder to decode this binary data (endian'd)
- yield core.bigendian_i.eq(bigendian) # little / big?
- yield instruction.eq(ins) # raw binary instr.
- yield ivalid_i.eq(1)
- yield Settle()
- # fn_unit = yield pdecode2.e.fn_unit
- #fuval = self.funit.value
- #self.assertEqual(fn_unit & fuval, fuval)
-
- # set operand and get inputs
- yield from set_issue(core, pdecode2, sim)
- yield Settle()
-
- yield from wait_for_busy_clear(core)
- yield ivalid_i.eq(0)
- yield
-
- print("sim", code)
- # call simulated operation
- opname = code.split(' ')[0]
- yield from sim.call(opname)
- index = sim.pc.CIA.value//4
-
- # register check
- yield from check_regs(self, sim, core, test, code)
-
- # Memory check
- yield from check_sim_memory(self, l0, sim, code)
+ with self.subTest(test.name):
+ sim = ISA(pdecode2, test.regs, test.sprs, test.cr,
+ test.mem,
+ test.msr,
+ bigendian=bigendian)
+ gen = program.generate_instructions()
+ instructions = list(zip(gen, program.assembly.splitlines()))
+
+ yield from setup_tst_memory(l0, test.mem)
+ yield from setup_regs(core, test)
+
+ index = sim.pc.CIA.value // 4
+ while index < len(instructions):
+ ins, code = instructions[index]
+
+ print("instruction: 0x{:X}".format(ins & 0xffffffff))
+ print(code)
+
+ # ask the decoder to decode this binary data (endian'd)
+ yield core.bigendian_i.eq(bigendian) # little / big?
+ yield instruction.eq(ins) # raw binary instr.
+ yield ivalid_i.eq(1)
+ yield Settle()
+ # fn_unit = yield pdecode2.e.fn_unit
+ #fuval = self.funit.value
+ #self.assertEqual(fn_unit & fuval, fuval)
+
+ # set operand and get inputs
+ yield from set_issue(core, pdecode2, sim)
+ yield Settle()
+
+ yield from wait_for_busy_clear(core)
+ yield ivalid_i.eq(0)
+ yield
+
+ print("sim", code)
+ # call simulated operation
+ opname = code.split(' ')[0]
+ yield from sim.call(opname)
+ index = sim.pc.CIA.value // 4
+
+ # register check
+ yield from check_regs(self, sim, core, test, code)
+
+ # Memory check
+ yield from check_mem(self, sim, core, test, code)
sim.add_sync_process(process)
with sim.write_vcd("core_simulator.vcd", "core_simulator.gtkw",
from openpower.test.div.div_cases import DivTestCases
from openpower.test.logical.logical_cases import LogicalTestCase
from openpower.test.shift_rot.shift_rot_cases import ShiftRotTestCase
+from openpower.test.shift_rot.shift_rot_cases2 import ShiftRotTestCase2
from openpower.test.cr.cr_cases import CRTestCase
from openpower.test.branch.branch_cases import BranchTestCase
-# from soc.fu.spr.test.test_pipe_caller import SPRTestCase
+from soc.fu.spr.test.test_pipe_caller import SPRTestCase
from openpower.test.ldst.ldst_cases import LDSTTestCase
from openpower.simulator.test_sim import (GeneralTestCases, AttnTestCase)
-# from openpower.simulator.test_helloworld_sim import HelloTestCases
+from openpower.simulator.test_helloworld_sim import HelloTestCases
if __name__ == "__main__":
svp64 = False
sys.argv.pop()
- print ("SVP64 test mode enabled", svp64)
+ # allow list of testing to be selected by command-line
+ testing = sys.argv[1:]
+ sys.argv = sys.argv[:1]
+
+ if not testing:
+ testing = ['general', 'ldst', 'cr', 'shiftrot', 'shiftrot2',
+ 'logical', 'alu',
+ 'branch', 'div']
+
+ print ("SVP64 test mode enabled", svp64, testing)
unittest.main(exit=False)
suite = unittest.TestSuite()
- # suite.addTest(TestRunner(HelloTestCases.test_data, svp64=svp64))
- suite.addTest(TestRunner(DivTestCases().test_data, svp64=svp64))
- # suite.addTest(TestRunner(AttnTestCase.test_data, svp64=svp64))
- suite.addTest(TestRunner(GeneralTestCases.test_data, svp64=svp64))
- suite.addTest(TestRunner(LDSTTestCase().test_data, svp64=svp64))
- suite.addTest(TestRunner(CRTestCase().test_data, svp64=svp64))
- suite.addTest(TestRunner(ShiftRotTestCase().test_data, svp64=svp64))
- suite.addTest(TestRunner(LogicalTestCase().test_data, svp64=svp64))
- suite.addTest(TestRunner(ALUTestCase().test_data, svp64=svp64))
- suite.addTest(TestRunner(BranchTestCase().test_data, svp64=svp64))
- # suite.addTest(TestRunner(SPRTestCase.test_data, svp64=svp64))
+
+ # dictionary of data for tests
+ tests = {'hello': HelloTestCases.test_data,
+ 'div': DivTestCases().test_data,
+ 'attn': AttnTestCase.test_data,
+ 'general': GeneralTestCases.test_data,
+ 'ldst': LDSTTestCase().test_data,
+ 'cr': CRTestCase().test_data,
+ 'shiftrot': ShiftRotTestCase().test_data,
+ 'shiftrot2': ShiftRotTestCase2().test_data,
+ 'logical': LogicalTestCase().test_data,
+ 'alu': ALUTestCase().test_data,
+ 'branch': BranchTestCase().test_data,
+ 'spr': SPRTestCase().test_data
+ }
+
+ # walk through all tests, those requested get added
+ for tname, data in tests.items():
+ if tname in testing:
+ suite.addTest(TestRunner(data, svp64=svp64))
runner = unittest.TextTestRunner()
runner.run(suite)
microwatt_mmu=True))
# LD/ST exception cases
- # TODO: Depends on TestIssuer passing the exception condition to
- # PowerDecoder2
suite.addTest(TestRunner(LDSTExceptionTestCase().test_data, svp64=svp64,
microwatt_mmu=True))
from soc.simple.test.test_core import (setup_regs, check_regs,
wait_for_busy_clear,
wait_for_busy_hi)
-from soc.fu.compunits.test.test_compunit import (setup_tst_memory,
- check_sim_memory,
+from soc.fu.compunits.test.test_compunit import (check_sim_memory,
get_l0_mem)
from soc.simple.test.test_runner import setup_i_memory
# blech! put the same listing into the data memory
data_mem = get_l0_mem(l0)
yield from setup_i_memory(data_mem, pc, instructions)
- # yield from setup_tst_memory(l0, sim)
yield from setup_regs(core, test)
yield pc_i.eq(pc)
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.hdl.xfrm import ResetInserter
+from copy import copy
# NOTE: to use cxxsim, export NMIGEN_SIM_MODE=cxxsim from the shell
# Also, check out the cxxsim nmigen branch, and latest yosys from git
from soc.simple.issuer import TestIssuerInternal
from soc.config.test.test_loadstore import TestMemPspec
-from soc.simple.test.test_core import (setup_regs, check_regs,
+from soc.simple.test.test_core import (setup_regs, check_regs, check_mem,
wait_for_busy_clear,
wait_for_busy_hi)
from soc.fu.compunits.test.test_compunit import (setup_tst_memory,
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
def setup_i_memory(imem, startaddr, instructions):
return data
+def run_hdl_state(dut, test, issuer, pc_i, svstate_i, instructions):
+ """run_hdl_state - runs a TestIssuer nmigen HDL simulation
+ """
+
+ imem = issuer.imem._get_memory()
+ core = issuer.core
+ dmi = issuer.dbg.dmi
+ pdecode2 = issuer.pdecode2
+ l0 = core.l0
+ hdl_states = []
+
+ # establish the TestIssuer context (mem, regs etc)
+
+ pc = 0 # start address
+ counter = 0 # test to pause/start
+
+ yield from setup_i_memory(imem, pc, instructions)
+ yield from setup_tst_memory(l0, test.mem)
+ yield from setup_regs(pdecode2, core, test)
+
+ # set PC and SVSTATE
+ yield pc_i.eq(pc)
+ yield issuer.pc_i.ok.eq(1)
+
+ # copy initial SVSTATE
+ initial_svstate = copy(test.svstate)
+ if isinstance(initial_svstate, int):
+ initial_svstate = SVP64State(initial_svstate)
+ yield svstate_i.eq(initial_svstate.value)
+ yield issuer.svstate_i.ok.eq(1)
+ yield
+
+ print("instructions", instructions)
+
+ # run the loop of the instructions on the current test
+ index = (yield issuer.cur_state.pc) // 4
+ while index < len(instructions):
+ ins, code = instructions[index]
+
+ print("hdl instr: 0x{:X}".format(ins & 0xffffffff))
+ print(index, code)
+
+ if counter == 0:
+ # start the core
+ yield
+ yield from set_dmi(dmi, DBGCore.CTRL,
+ 1<<DBGCtrl.START)
+ yield issuer.pc_i.ok.eq(0) # no change PC after this
+ yield issuer.svstate_i.ok.eq(0) # ditto
+ yield
+ yield
+
+ counter = counter + 1
+
+ # wait until executed
+ while not (yield issuer.insn_done):
+ yield
+
+ yield Settle()
+
+ index = (yield issuer.cur_state.pc) // 4
+
+ terminated = yield issuer.dbg.terminated_o
+ print("terminated", terminated)
+
+ if index < len(instructions):
+ # Get HDL mem and state
+ state = yield from TestState("hdl", core, dut,
+ code)
+ hdl_states.append(state)
+
+ if index >= len(instructions):
+ print ("index over, send dmi stop")
+ # stop at end
+ yield from set_dmi(dmi, DBGCore.CTRL,
+ 1<<DBGCtrl.STOP)
+ yield
+ yield
+
+ terminated = yield issuer.dbg.terminated_o
+ print("terminated(2)", terminated)
+ if terminated:
+ break
+
+ return hdl_states
+
+
+def run_sim_state(dut, test, simdec2, instructions, gen, insncode):
+ """run_sim_state - runs an ISACaller simulation
+ """
+
+ 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 SimRunner(StateRunner):
+ def __init__(self, dut, m, pspec):
+ 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
+
+
+class HDLRunner(StateRunner):
+ def __init__(self, dut, m, pspec):
+ self.dut = dut
+ #hard_reset = Signal(reset_less=True)
+ self.issuer = TestIssuerInternal(pspec)
+ # use DMI RESET command instead, this does actually work though
+ #issuer = ResetInserter({'coresync': hard_reset,
+ # 'sync': hard_reset})(issuer)
+ m.submodules.issuer = self.issuer
+ self.dmi = self.issuer.dbg.dmi
+
+
class TestRunner(FHDLTestCase):
def __init__(self, tst_data, microwatt_mmu=False, rom=None,
- svp64=True):
+ 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
- pc_i = Signal(32)
- svstate_i = Signal(64)
-
if self.microwatt_mmu:
ldst_ifacetype = 'test_mmu_cache_wb'
else:
svp64=self.svp64,
mmu=self.microwatt_mmu,
reg_wid=64)
- #hard_reset = Signal(reset_less=True)
- issuer = TestIssuerInternal(pspec)
- # use DMI RESET command instead, this does actually work though
- #issuer = ResetInserter({'coresync': hard_reset,
- # 'sync': hard_reset})(issuer)
- m.submodules.issuer = issuer
- imem = issuer.imem._get_memory()
- core = issuer.core
- dmi = issuer.dbg.dmi
- pdecode2 = issuer.pdecode2
- l0 = core.l0
- regreduce_en = pspec.regreduce_en == True
- #simdec = create_pdecode()
- simdec2 = PowerDecode2(None, regreduce_en=regreduce_en)
- m.submodules.simdec2 = simdec2 # pain in the neck
+ ###### SETUP PHASE #######
+ # StateRunner.setup_for_test()
+
+ if self.run_hdl:
+ hdlrun = HDLRunner(self, m, pspec)
+
+ if self.run_sim:
+ simrun = SimRunner(self, m, pspec)
# run core clock at same rate as test clock
intclk = ClockSignal("coresync")
comb += intclk.eq(ClockSignal())
- comb += issuer.pc_i.data.eq(pc_i)
- comb += issuer.svstate_i.data.eq(svstate_i)
+ if self.run_hdl:
- # nmigen Simulation
+ pc_i = Signal(32)
+ svstate_i = Signal(64)
+
+ comb += hdlrun.issuer.pc_i.data.eq(pc_i)
+ comb += hdlrun.issuer.svstate_i.data.eq(svstate_i)
+
+ # nmigen Simulation - everything runs around this, so it
+ # still has to be created.
sim = Simulator(m)
sim.add_clock(1e-6)
def process():
- # start in stopped
- yield from set_dmi(dmi, DBGCore.CTRL, 1<<DBGCtrl.STOP)
- yield
+ ###### PREPARATION PHASE AT START OF RUNNING #######
+ # StateRunner.setup_during_test()
+
+ if self.run_hdl:
+ # start in stopped
+ yield from set_dmi(hdlrun.dmi, DBGCore.CTRL, 1<<DBGCtrl.STOP)
+ yield
# get each test, completely reset the core, and run it
for test in self.test_data:
- # set up bigendian (TODO: don't do this, use MSR)
- yield issuer.core_bigendian_i.eq(bigendian)
- yield Settle()
+ with self.subTest(test.name):
- yield
- yield
- yield
- yield
+ ###### PREPARATION PHASE AT START OF TEST #######
+ # StateRunner.prepare_for_test()
- print(test.name)
- program = test.program
- with self.subTest(test.name):
+ if self.run_hdl:
+ # set up bigendian (TODO: don't do this, use MSR)
+ yield hdlrun.issuer.core_bigendian_i.eq(bigendian)
+ yield Settle()
+
+ yield
+ yield
+ yield
+ yield
+
+ print(test.name)
+ program = test.program
print("regs", test.regs)
print("sprs", test.sprs)
print("cr", test.cr)
insncode = program.assembly.splitlines()
instructions = list(zip(gen, insncode))
- # 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)
-
- # establish the TestIssuer context (mem, regs etc)
-
- pc = 0 # start address
- counter = 0 # test to pause/start
-
- yield from setup_i_memory(imem, pc, instructions)
- yield from setup_tst_memory(l0, sim)
- yield from setup_regs(pdecode2, core, test)
-
- # set PC and SVSTATE
- yield pc_i.eq(pc)
- yield issuer.pc_i.ok.eq(1)
-
- initial_svstate = test.svstate
- if isinstance(initial_svstate, int):
- initial_svstate = SVP64State(initial_svstate)
- yield svstate_i.eq(initial_svstate.value)
- yield issuer.svstate_i.ok.eq(1)
+ ###### 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
+
+ ##########
+ # 1. HDL
+ ##########
+ if self.run_hdl:
+ hdl_states = yield from run_hdl_state(self, test,
+ hdlrun.issuer,
+ pc_i, svstate_i,
+ instructions)
+
+ ##########
+ # 2. Simulator
+ ##########
+
+ if self.run_sim:
+ sim_states = yield from run_sim_state(self, test,
+ simrun.simdec2,
+ instructions, gen,
+ insncode)
+
+ ###### COMPARING THE TESTS #######
+
+ ###############
+ # 3. Compare
+ ###############
+
+ 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 and self.run_sim:
+ for simstate, hdlstate in zip(sim_states, hdl_states):
+ simstate.compare(hdlstate) # register check
+ simstate.compare_mem(hdlstate) # memory check
+
+ 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)
+
+ # 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()
+
+ if self.run_hdl:
+ # stop at end
+ yield from set_dmi(hdlrun.dmi, DBGCore.CTRL, 1<<DBGCtrl.STOP)
+ yield
yield
- print("instructions", instructions)
-
- # 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("instruction: 0x{:X}".format(ins & 0xffffffff))
- print(index, code)
-
- if counter == 0:
- # start the core
- yield
- yield from set_dmi(dmi, DBGCore.CTRL,
- 1<<DBGCtrl.START)
- yield issuer.pc_i.ok.eq(0) # no change PC after this
- yield issuer.svstate_i.ok.eq(0) # ditto
- yield
- yield
-
- counter = counter + 1
-
- # wait until executed
- while not (yield issuer.insn_done):
- yield
-
- # 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
-
- terminated = yield issuer.dbg.terminated_o
- print("terminated", terminated)
-
- if index >= len(instructions):
- print ("index over, send dmi stop")
- # stop at end
- yield from set_dmi(dmi, DBGCore.CTRL,
- 1<<DBGCtrl.STOP)
- yield
- yield
-
- # register check
- yield from check_regs(self, sim, core, test, code)
-
- # Memory check
- yield from check_sim_memory(self, l0, sim, code)
-
- terminated = yield issuer.dbg.terminated_o
- print("terminated(2)", terminated)
- if terminated:
- break
+ # TODO, here is where the static (expected) results
+ # can be checked: register check (TODO, memory check)
+ # see https://bugs.libre-soc.org/show_bug.cgi?id=686#c51
+ # yield from check_regs(self, sim, core, test, code,
+ # >>>expected_data<<<)
- # stop at end
- yield from set_dmi(dmi, DBGCore.CTRL, 1<<DBGCtrl.STOP)
- yield
- yield
+ # get CR
+ cr = yield from get_dmi(hdlrun.dmi, DBGCore.CR)
+ print("after test %s cr value %x" % (test.name, cr))
- # get CR
- cr = yield from get_dmi(dmi, DBGCore.CR)
- print("after test %s cr value %x" % (test.name, cr))
+ # get XER
+ xer = yield from get_dmi(hdlrun.dmi, DBGCore.XER)
+ print("after test %s XER value %x" % (test.name, xer))
- # get XER
- xer = yield from get_dmi(dmi, DBGCore.XER)
- print("after test %s XER value %x" % (test.name, xer))
+ # test of dmi reg get
+ for int_reg in range(32):
+ yield from set_dmi(hdlrun.dmi, DBGCore.GSPR_IDX, int_reg)
+ value = yield from get_dmi(hdlrun.dmi, DBGCore.GSPR_DATA)
- # test of dmi reg get
- for int_reg in range(32):
- yield from set_dmi(dmi, DBGCore.GSPR_IDX, int_reg)
- value = yield from get_dmi(dmi, DBGCore.GSPR_DATA)
+ print("after test %s reg %2d value %x" %
+ (test.name, int_reg, value))
- print("after test %s reg %2d value %x" %
- (test.name, int_reg, value))
+ # pull a reset
+ yield from set_dmi(hdlrun.dmi, DBGCore.CTRL, 1<<DBGCtrl.RESET)
+ yield
- # pull a reset
- yield from set_dmi(dmi, DBGCore.CTRL, 1<<DBGCtrl.RESET)
- yield
+ ###### END OF EVERYTHING (but none needs doing, still call fn) #######
+ # StateRunner.cleanup()
styles = {
'dec': {'base': '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',
+ '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',
--- /dev/null
+""" Power ISA test API
+
+This module implements the creation, inspection and comparison
+of test states for TestIssuer HDL
+
+"""
+
+from openpower.decoder.power_enums import XER_bits
+from openpower.util import log
+from openpower.test.state import (State, state_add, state_factory,
+ TestState,)
+from soc.fu.compunits.test.test_compunit import get_l0_mem
+
+class HDLState(State):
+ def __init__(self, core):
+ super().__init__()
+ self.core = core
+
+ def get_intregs(self):
+ self.intregs = []
+ for i in range(32):
+ if self.core.regs.int.unary:
+ rval = yield self.core.regs.int.regs[i].reg
+ else:
+ rval = yield self.core.regs.int.memory._array[i]
+ self.intregs.append(rval)
+ log("class hdl int regs", list(map(hex, self.intregs)))
+
+ def get_crregs(self):
+ self.crregs = []
+ for i in range(8):
+ rval = yield self.core.regs.cr.regs[i].reg
+ self.crregs.append(rval)
+ log("class hdl cr regs", list(map(hex, self.crregs)))
+
+ def get_xregs(self):
+ self.xregs = []
+ self.xr = self.core.regs.xer
+ self.so = yield self.xr.regs[self.xr.SO].reg
+ self.ov = yield self.xr.regs[self.xr.OV].reg
+ self.ca = yield self.xr.regs[self.xr.CA].reg
+ self.xregs.extend((self.so, self.ov, self.ca))
+ log("class hdl xregs", list(map(hex, self.xregs)))
+
+ def get_pc(self):
+ self.pcl = []
+ self.state = self.core.regs.state
+ self.pc = yield self.state.r_ports['cia'].o_data
+ self.pcl.append(self.pc)
+ log("class hdl pc", hex(self.pc))
+
+ def get_mem(self):
+ # get the underlying HDL-simulated memory from the L0CacheBuffer
+ hdlmem = get_l0_mem(self.core.l0)
+ self.mem = {}
+ for i in range(hdlmem.depth):
+ value = yield hdlmem._array[i] # should not really do this
+ self.mem[i*8] = value
+
+
+# add to State Factory
+state_add('hdl', HDLState)