--- /dev/null
+import os
+
+# set up environment variable overrides, can use for different versions
+# as well as native (TALOS-II POWER9) builds.
+cmds = {}
+for cmd in ['objcopy', 'as', 'ld', 'gcc', 'ar', 'gdb']:
+ cmds[cmd] = os.environ.get(cmd.upper(), "powerpc64-linux-gnu-%s" % cmd)
+
+
--- /dev/null
+# License: LPGLv3
+# Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
+# Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+
+import tempfile
+import subprocess
+import struct
+
+
+def get_assembled_instruction(instruction, bigendian=False):
+ if bigendian:
+ endian_fmt = "elf64-big"
+ obj_fmt = "-be"
+ else:
+ endian_fmt = "elf64-little"
+ obj_fmt = "-le"
+ with tempfile.NamedTemporaryFile(suffix=".o") as outfile:
+ args = ["powerpc64-linux-gnu-as",
+ obj_fmt,
+ "-o",
+ outfile.name]
+ p = subprocess.Popen(args, stdin=subprocess.PIPE)
+ p.communicate(instruction.encode('utf-8'))
+ assert(p.wait() == 0)
+
+ with tempfile.NamedTemporaryFile(suffix=".bin") as binfile:
+ args = ["powerpc64-linux-gnu-objcopy",
+ "-I", endian_fmt,
+ "-O", "binary",
+ outfile.name,
+ binfile.name]
+ subprocess.check_output(args)
+ binary = struct.unpack('>i', binfile.read(4))[0]
+ return binary
--- /dev/null
+# License: LGPLv3+
+# Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
+# Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+
+"""POWER Program
+
+takes powerpc assembly instructions and turns them into LE/BE binary
+data. calls powerpc64-linux-gnu-as, ld and objcopy to do so.
+"""
+
+import tempfile
+import subprocess
+import struct
+import os
+import sys
+from io import BytesIO
+
+from soc.simulator.envcmds import cmds
+
+filedir = os.path.dirname(os.path.realpath(__file__))
+memmap = os.path.join(filedir, "memmap")
+
+
+class Program:
+ def __init__(self, instructions, bigendian):
+ self.bigendian = bigendian
+ if self.bigendian:
+ self.endian_fmt = "elf64-big"
+ self.obj_fmt = "-be"
+ self.ld_fmt = "-EB"
+ else:
+ self.ld_fmt = "-EL"
+ self.endian_fmt = "elf64-little"
+ self.obj_fmt = "-le"
+
+ if isinstance(instructions, bytes): # actual bytes
+ self.binfile = BytesIO(instructions)
+ self.binfile.name = "assembly"
+ self.assembly = '' # noo disassemble number fiiive
+ elif isinstance(instructions, str): # filename
+ # read instructions into a BytesIO to avoid "too many open files"
+ with open(instructions, "rb") as f:
+ b = f.read()
+ self.binfile = BytesIO(b)
+ self.assembly = '' # noo disassemble number fiiive
+ print("program", self.binfile)
+ else:
+ if isinstance(instructions, list):
+ instructions = '\n'.join(instructions)
+ self.assembly = instructions + '\n' # plus final newline
+ self._assemble()
+ self._instructions = list(self._get_instructions())
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, traceback):
+ self.close()
+
+ def _get_binary(self, elffile):
+ self.binfile = tempfile.NamedTemporaryFile(suffix=".bin")
+ args = [cmds['objcopy'],
+ "-O", "binary",
+ "-I", self.endian_fmt,
+ elffile.name,
+ self.binfile.name]
+ subprocess.check_output(args)
+
+ def _link(self, ofile):
+ with tempfile.NamedTemporaryFile(suffix=".elf") as elffile:
+ args = [cmds['ld'],
+ self.ld_fmt,
+ "-o", elffile.name,
+ "-T", memmap,
+ ofile.name]
+ subprocess.check_output(args)
+ self._get_binary(elffile)
+
+ def _assemble(self):
+ with tempfile.NamedTemporaryFile(suffix=".o") as outfile:
+ args = [cmds['as'],
+ '-mpower9',
+ '-mregnames',
+ self.obj_fmt,
+ "-o",
+ outfile.name]
+ p = subprocess.Popen(args, stdin=subprocess.PIPE)
+ p.communicate(self.assembly.encode('utf-8'))
+ if p.wait() != 0:
+ print("Error in program:")
+ print(self.assembly)
+ sys.exit(1)
+ self._link(outfile)
+
+ def _get_instructions(self):
+ while True:
+ data = self.binfile.read(4)
+ if not data:
+ break
+ yield struct.unpack('<I', data)[0] # unsigned int
+
+ def generate_instructions(self):
+ yield from self._instructions
+
+ def reset(self):
+ self.binfile.seek(0)
+
+ def size(self):
+ curpos = self.binfile.tell()
+ self.binfile.seek(0, 2) # Seek to end of file
+ size = self.binfile.tell()
+ self.binfile.seek(curpos, 0)
+ return size
+
+ def write_bin(self, fname):
+ self.reset()
+ data = self.binfile.read()
+ with open(fname, "wb") as f:
+ f.write(data)
+
+ def close(self):
+ self.binfile.close()
+
+if __name__ == '__main__':
+ lst = ['addi 5, 0, 4660/2',
+ 'mtcrf 255, 5+3',
+ 'mfocrf 2, 1',
+ 'addi r2, 3, 1',
+ 'attn',
+ ]
+ lst = ["addi 9, 0, 0x10", # i = 16
+ "addi 9,9,-1", # i = i - 1
+ "cmpi 2,1,9,12", # compare 9 to value 12, store in CR2
+ "bc 4,10,-8", # branch if CR2 "test was != 12"
+ 'attn',
+ ]
+
+ with Program(lst, False) as p:
+ for instruction in p.generate_instructions():
+ print (hex(instruction))
+ p.write_bin("/tmp/test.bin")
--- /dev/null
+from pygdbmi.gdbcontroller import GdbController
+import subprocess
+
+launch_args_be = ['qemu-system-ppc64',
+ '-machine', 'powernv9',
+ '-nographic',
+ '-s', '-S']
+
+launch_args_le = ['qemu-system-ppc64le',
+ '-machine', 'powernv9',
+ '-nographic',
+ '-s', '-S']
+
+
+def swap_order(x, nbytes):
+ x = x.to_bytes(nbytes, byteorder='little')
+ x = int.from_bytes(x, byteorder='big', signed=False)
+ return x
+
+
+class QemuController:
+ def __init__(self, kernel, bigendian):
+ if bigendian:
+ args = launch_args_be + ['-kernel', kernel]
+ else:
+ args = launch_args_le + ['-kernel', kernel]
+ self.qemu_popen = subprocess.Popen(args,
+ stdout=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+ self.gdb = GdbController(gdb_path='powerpc64-linux-gnu-gdb')
+ self.bigendian = bigendian
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, traceback):
+ self.exit()
+
+ def connect(self):
+ return self.gdb.write('-target-select remote localhost:1234')
+
+ def set_endian(self, bigendian):
+ if bigendian:
+ cmd = '-gdb-set endian big'
+ else:
+ cmd = '-gdb-set endian little'
+ return self.gdb.write(cmd)
+
+ def break_address(self, addr):
+ cmd = '-break-insert *0x{:x}'.format(addr)
+ return self.gdb.write(cmd)
+
+ def delete_breakpoint(self, breakpoint=None):
+ breakstring = ''
+ if breakpoint:
+ breakstring = f' {breakpoint}'
+ return self.gdb.write('-break-delete' + breakstring)
+
+ def set_byte(self, addr, v):
+ print("qemu set byte", hex(addr), hex(v))
+ faddr = '&{int}0x%x' % addr
+ res = self.gdb.write('-data-write-memory-bytes %s "%02x"' % (faddr, v))
+ print("confirm", self.get_mem(addr, 1))
+
+ def get_mem(self, addr, nbytes):
+ res = self.gdb.write("-data-read-memory %d u 1 1 %d" %
+ (addr, 8*nbytes))
+ #print ("get_mem", res)
+ for x in res:
+ if(x["type"] == "result"):
+ l = list(map(int, x['payload']['memory'][0]['data']))
+ res = []
+ for j in range(0, len(l), 8):
+ b = 0
+ for i, v in enumerate(l[j:j+8]):
+ b += v << (i*8)
+ res.append(b)
+ return res
+ return None
+
+ def get_registers(self):
+ return self.gdb.write('-data-list-register-values x')
+
+ def _get_register(self, fmt):
+ res = self.gdb.write('-data-list-register-values '+fmt,
+ timeout_sec=1.0) # increase this timeout if needed
+ for x in res:
+ if(x["type"] == "result"):
+ assert 'register-values' in x['payload']
+ res = int(x['payload']['register-values'][0]['value'], 0)
+ return res
+ # return swap_order(res, 8)
+ return None
+
+ # TODO: use -data-list-register-names instead of hardcoding the values
+ def get_pc(self): return self._get_register('x 64')
+ def get_msr(self): return self._get_register('x 65')
+ def get_cr(self): return self._get_register('x 66')
+ def get_lr(self): return self._get_register('x 67')
+ def get_ctr(self): return self._get_register('x 68') # probably
+ def get_xer(self): return self._get_register('x 69')
+ def get_fpscr(self): return self._get_register('x 70')
+ def get_mq(self): return self._get_register('x 71')
+
+ def get_register(self, num):
+ return self._get_register('x {}'.format(num))
+
+ def step(self):
+ return self.gdb.write('-exec-next-instruction')
+
+ def gdb_continue(self):
+ return self.gdb.write('-exec-continue')
+
+ def gdb_eval(self, expr):
+ return self.gdb.write(f'-data-evaluate-expression {expr}')
+
+ def exit(self):
+ self.gdb.exit()
+ self.qemu_popen.kill()
+ outs, errs = self.qemu_popen.communicate()
+ self.qemu_popen.stdout.close()
+ self.qemu_popen.stdin.close()
+
+
+def run_program(program, initial_mem=None, extra_break_addr=None,
+ bigendian=False):
+ q = QemuController(program.binfile.name, bigendian)
+ q.connect()
+ q.set_endian(True) # easier to set variables this way
+
+ # Run to the start of the program
+ if initial_mem:
+ for addr, (v, wid) in initial_mem.items():
+ for i in range(wid):
+ q.set_byte(addr+i, (v >> i*8) & 0xff)
+
+ # set breakpoint at start
+ q.break_address(0x20000000)
+ q.gdb_continue()
+ # set the MSR bit 63, to set bigendian/littleendian mode
+ msr = q.get_msr()
+ print("msr", bigendian, hex(msr))
+ if bigendian:
+ msr &= ~(1 << 0)
+ msr = msr & ((1 << 64)-1)
+ else:
+ msr |= (1 << 0)
+ q.gdb_eval('$msr=%d' % msr)
+ print("msr set to", hex(msr))
+ # set the CR to 0, matching the simulator
+ q.gdb_eval('$cr=0')
+ # delete the previous breakpoint so loops don't screw things up
+ q.delete_breakpoint()
+ # run to completion
+ q.break_address(0x20000000 + program.size())
+ # or to trap
+ q.break_address(0x700)
+ # or to alternative (absolute) address)
+ if extra_break_addr:
+ q.break_address(extra_break_addr)
+ q.gdb_continue()
+ q.set_endian(bigendian)
+
+ return q
+
+
+if __name__ == '__main__':
+ q = QemuController("simulator/qemu_test/kernel.bin", bigendian=True)
+ q.connect()
+ q.break_address(0x20000000)
+ q.gdb_continue()
+ print(q.get_register(1))
+ print(q.step())
+ print(q.get_register(1))
+ q.exit()
--- /dev/null
+TOOLCHAIN=powerpc64-linux-gnu
+CC=$(TOOLCHAIN)-gcc
+AS=$(TOOLCHAIN)-as
+AFLAGS=-mpwr9
+
+all: kernel.bin
+
+clean:
+ rm *.o *.elf *.bin
+
+kernel.elf: test.o
+ $(TOOLCHAIN)-ld $^ -o $@ -T memmap
+
+kernel.bin: kernel.elf
+ $(TOOLCHAIN)-objcopy $< -O binary $@
+
+%.o: %.s
+ $(AS) $(AFLAGS) -c $< -o $@
--- /dev/null
+# Qemu test directory
+
+To launch and debug qemu, run the following:
+```
+make
+./launch.sh
+powerpc64-linux-gnu-gdb -x gdbscript
+```
--- /dev/null
+target remote localhost:1234
+layout asm
+b *0x20000000
+c
--- /dev/null
+qemu-system-ppc64 -machine powernv9 -nographic -s -S -kernel kernel.bin
--- /dev/null
+ lis 1, 0xdead
+ ori 1, 1, 0xbeef
+ lis 2, 0x2000
+ ori 2, 2, 0x0100
+ std 1, 0(2)
+ lhz 1, 4(2)
--- /dev/null
+from nmigen import Module, Signal
+from nmigen.back.pysim import Simulator, Delay, Settle
+from nmutil.formaltest import FHDLTestCase
+import unittest
+from soc.decoder.power_decoder import (create_pdecode)
+from soc.decoder.power_enums import (Function, MicrOp,
+ In1Sel, In2Sel, In3Sel,
+ OutSel, RC, LdstLen, CryIn,
+ single_bit_flags, Form, SPR,
+ get_signal_name, get_csv)
+from soc.decoder.power_decoder2 import (PowerDecode2)
+from soc.simulator.program import Program
+from soc.simulator.qemu import run_program
+from soc.decoder.isa.all import ISA
+from soc.fu.test.common import TestCase
+from soc.simulator.test_sim import DecoderBase
+
+
+
+class DivTestCases(FHDLTestCase):
+ test_data = []
+
+ def __init__(self, name="div"):
+ super().__init__(name)
+ self.test_name = name
+
+ def test_0_divw(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x1234",
+ "divw 3, 1, 2",
+ ]
+ with Program(lst) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ def test_1_divw_(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x1234",
+ "divw. 3, 1, 2",
+ ]
+ with Program(lst) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ def test_2_divw_(self):
+ lst = ["addi 1, 0, 0x1234",
+ "addi 2, 0, 0x5678",
+ "divw. 3, 1, 2",
+ ]
+ with Program(lst) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ def test_1_divwe(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x1234",
+ "divwe 3, 1, 2",
+ ]
+ with Program(lst) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ def test_2_divweu(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x1234",
+ "divweu 3, 1, 2",
+ ]
+ with Program(lst) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ def test_4_moduw(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x1234",
+ "moduw 3, 1, 2",
+ ]
+ with Program(lst) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ def test_5_div_regression(self):
+ lst = ["addi 1, 0, 0x4",
+ "addi 2, 0, 0x2",
+ "neg 2, 2",
+ "neg 1, 1",
+ "divwo 3, 1, 2",
+ ]
+ with Program(lst) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ def run_tst_program(self, prog, initial_regs=None, initial_sprs=None,
+ initial_mem=None):
+ initial_regs = [0] * 32
+ tc = TestCase(prog, self.test_name, initial_regs, initial_sprs, 0,
+ initial_mem, 0)
+ self.test_data.append(tc)
+
+
+class DivZeroTestCases(FHDLTestCase):
+ test_data = []
+
+ def __init__(self, name="divbyzero"):
+ super().__init__(name)
+ self.test_name = name
+
+ def test_0_divw(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x0",
+ "divw 3, 1, 2",
+ ]
+ with Program(lst) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ def test_1_divwe(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x0",
+ "divwe 3, 1, 2",
+ ]
+ with Program(lst) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ def test_2_divweu(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x0",
+ "divweu 3, 1, 2",
+ ]
+ with Program(lst) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ def test_4_moduw(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x0",
+ "moduw 3, 1, 2",
+ ]
+ with Program(lst) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ def run_tst_program(self, prog, initial_regs=None, initial_sprs=None,
+ initial_mem=None):
+ initial_regs = [0] * 32
+ tc = TestCase(prog, self.test_name, initial_regs, initial_sprs, 0,
+ initial_mem, 0)
+ self.test_data.append(tc)
+
+
+
+class DivDecoderTestCase(DecoderBase, DivTestCases):
+ pass
+
+class DivZeroDecoderTestCase(DecoderBase, DivZeroTestCases):
+ pass
+
+if __name__ == "__main__":
+ unittest.main()
--- /dev/null
+from nmigen import Module, Signal
+from nmigen.back.pysim import Simulator, Delay, Settle
+from nmutil.formaltest import FHDLTestCase
+import unittest
+from soc.decoder.power_decoder import (create_pdecode)
+from soc.decoder.power_enums import (Function, MicrOp,
+ In1Sel, In2Sel, In3Sel,
+ OutSel, RC, LdstLen, CryIn,
+ single_bit_flags, Form, SPR,
+ get_signal_name, get_csv)
+from soc.decoder.power_decoder2 import (PowerDecode2)
+from soc.simulator.program import Program
+from soc.simulator.qemu import run_program
+from soc.decoder.isa.all import ISA
+from soc.fu.test.common import TestCase
+from soc.simulator.test_sim import DecoderBase
+from soc.config.endian import bigendian
+
+
+class HelloTestCases(FHDLTestCase):
+ test_data = []
+
+ def __init__(self, name="div"):
+ super().__init__(name)
+ self.test_name = name
+
+ def test_microwatt_helloworld(self):
+ lst = ["addis 1,0,0",
+ "ori 1,1,0",
+ "rldicr 1,1,32,31",
+ "oris 1,1,0",
+ "ori 1,1,7936",
+ "addis 12,0,0",
+ "ori 12,12,0",
+ "rldicr 12,12,32,31",
+ "oris 12,12,0",
+ "ori 12,12,4116",
+ "mtspr 9, 12", # mtctr r12
+ "bcctrl 20,0,0", # bctrl
+ ]
+ self.run_tst_program(Program(lst, bigendian),
+ [1,12], extra_break_addr=0x1014)
+
+ def run_tst_program(self, prog, initial_regs=None, initial_sprs=None,
+ initial_mem=None, extra_break_addr=None):
+ initial_regs = [0] * 32
+ tc = TestCase(prog, self.test_name, initial_regs, initial_sprs, 0,
+ initial_mem, 0,
+ extra_break_addr=extra_break_addr)
+ self.test_data.append(tc)
+
+
+class HelloDecoderTestCase(DecoderBase, HelloTestCases):
+ pass
+
+
+if __name__ == "__main__":
+ unittest.main()
--- /dev/null
+from nmigen import Module, Signal
+from nmigen.back.pysim import Simulator, Delay, Settle
+from nmutil.formaltest import FHDLTestCase
+import unittest
+from soc.decoder.power_decoder import (create_pdecode)
+from soc.decoder.power_enums import (Function, MicrOp,
+ In1Sel, In2Sel, In3Sel,
+ OutSel, RC, LdstLen, CryIn,
+ single_bit_flags, Form, SPR,
+ get_signal_name, get_csv)
+from soc.decoder.power_decoder2 import (PowerDecode2)
+from soc.simulator.program import Program
+from soc.simulator.qemu import run_program
+from soc.decoder.isa.all import ISA
+from soc.fu.test.common import TestCase
+from soc.simulator.test_sim import DecoderBase
+from soc.config.endian import bigendian
+
+
+
+class MulTestCases(FHDLTestCase):
+ test_data = []
+
+ def __init__(self, name="div"):
+ super().__init__(name)
+ self.test_name = name
+
+ def tst_mullw(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x1234",
+ "mullw 3, 1, 2"]
+ self.run_tst_program(Program(lst, bigendian), [3])
+
+ def test_mullwo(self):
+ lst = ["addi 1, 0, 0x5678",
+ "neg 1, 1",
+ "addi 2, 0, 0x1234",
+ "neg 2, 2",
+ "mullwo 3, 1, 2"]
+ self.run_tst_program(Program(lst, bigendian), [3])
+
+ def run_tst_program(self, prog, initial_regs=None, initial_sprs=None,
+ initial_mem=None):
+ initial_regs = [0] * 32
+ tc = TestCase(prog, self.test_name, initial_regs, initial_sprs, 0,
+ initial_mem, 0)
+ self.test_data.append(tc)
+
+
+class MulDecoderTestCase(DecoderBase, MulTestCases):
+ pass
+
+
+if __name__ == "__main__":
+ unittest.main()
--- /dev/null
+from nmigen import Module, Signal
+from nmigen.back.pysim import Simulator, Delay, Settle
+from nmutil.formaltest import FHDLTestCase
+import unittest
+from soc.decoder.power_decoder import (create_pdecode)
+from soc.decoder.power_enums import (Function, MicrOp,
+ In1Sel, In2Sel, In3Sel,
+ OutSel, RC, LdstLen, CryIn,
+ single_bit_flags, Form, SPR,
+ get_signal_name, get_csv)
+from soc.decoder.power_decoder2 import (PowerDecode2)
+from soc.simulator.program import Program
+from soc.simulator.qemu import run_program
+from soc.decoder.isa.all import ISA
+from soc.fu.test.common import TestCase
+from soc.simulator.test_sim import DecoderBase
+from soc.config.endian import bigendian
+
+
+
+class MulTestCases(FHDLTestCase):
+ test_data = []
+
+ def __init__(self, name="div"):
+ super().__init__(name)
+ self.test_name = name
+
+ def test_1_extswsli(self):
+ lst = ["addi 1, 0, 0x5678",
+ "extswsli 3, 1, 34"]
+ self.run_tst_program(Program(lst, bigendian), [3])
+
+ def run_tst_program(self, prog, initial_regs=None, initial_sprs=None,
+ initial_mem=None):
+ initial_regs = [0] * 32
+ tc = TestCase(prog, self.test_name, initial_regs, initial_sprs, 0,
+ initial_mem, 0)
+ self.test_data.append(tc)
+
+
+class MulDecoderTestCase(DecoderBase, MulTestCases):
+ pass
+
+
+if __name__ == "__main__":
+ unittest.main()
--- /dev/null
+from nmigen import Module, Signal
+from nmigen.back.pysim import Simulator, Delay, Settle
+from nmutil.formaltest import FHDLTestCase
+import unittest
+from soc.decoder.power_decoder import (create_pdecode)
+from soc.decoder.power_enums import (Function, MicrOp,
+ In1Sel, In2Sel, In3Sel,
+ OutSel, RC, LdstLen, CryIn,
+ single_bit_flags, Form,
+ get_signal_name, get_csv)
+from soc.decoder.power_decoder2 import (PowerDecode2)
+from soc.simulator.program import Program
+from soc.simulator.qemu import run_program
+from soc.decoder.isa.all import ISA
+from soc.fu.test.common import TestCase
+from soc.config.endian import bigendian
+
+
+class AttnTestCase(FHDLTestCase):
+ test_data = []
+
+ def __init__(self, name="general"):
+ super().__init__(name)
+ self.test_name = name
+
+ def test_0_attn(self):
+ """simple test of attn. program is 4 long: should halt at 2nd op
+ """
+ lst = ["addi 6, 0, 0x10",
+ "attn",
+ "subf. 1, 6, 7",
+ "cmp cr2, 1, 6, 7",
+ ]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1])
+
+ def run_tst_program(self, prog, initial_regs=None, initial_sprs=None,
+ initial_mem=None):
+ initial_regs = [0] * 32
+ tc = TestCase(prog, self.test_name, initial_regs, initial_sprs, 0,
+ initial_mem, 0)
+ self.test_data.append(tc)
+
+
+class GeneralTestCases(FHDLTestCase):
+ test_data = []
+
+ def __init__(self, name="general"):
+ super().__init__(name)
+ self.test_name = name
+
+ @unittest.skip("disable")
+ def test_0_litex_bios_ctr_loop(self):
+ """
+ 32a4: ff ff 63 38 addi r3,r3,-1
+ 32a8: 20 00 63 78 clrldi r3,r3,32
+ 32ac: 01 00 23 39 addi r9,r3,1
+ 32b0: a6 03 29 7d mtctr r9
+ 32b4: 00 00 00 60 nop
+ 32b8: fc ff 00 42 bdnz 32b4 <cdelay+0x10>
+ 32bc: 20 00 80 4e blr
+
+ notes on converting pseudo-assembler to actual:
+
+ * bdnz target (equivalent to: bc 16,0,target)
+ * Clear left immediate clrldi ra,rs,n (n < 64) rldicl ra,rs,0,n
+ * CTR mtctr Rx mtspr 9,Rx
+ """
+ pass
+
+ @unittest.skip("disable")
+ def test_0_litex_bios_cmp(self):
+ """litex bios cmp test
+ """
+ lst = [ "addis 26, 0, 21845",
+ "ori 26, 26, 21845",
+ "addi 5, 26, 0",
+ "rldicr 5,5,32,31",
+ "addi 5, 26, 0",
+ "cmp 0, 0, 5, 26",
+ "bc 12, 2, 28",
+ "addis 6, 0, 1",
+ "addis 7, 0, 1",
+ ]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [5,6,7,26], initial_mem={})
+
+ @unittest.skip("disable")
+ def test_0_litex_bios_r1(self):
+ """litex bios IMM64 macro test
+ """
+ lst = [ "addis 1,0,0",
+ "ori 1,1,0",
+ "rldicr 1,1,32,31",
+ "oris 1,1,256",
+ "ori 1,1,3832",
+ ]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1], initial_mem={})
+
+ @unittest.skip("disable")
+ def test_0_litex_trampoline(self):
+ lst = ["tdi 0,0,0x48",
+ "b 0x28",
+ "mfmsr r11",
+ "bcl 20,31,4",
+ "mflr r10",
+ "addi r10,r10,20",
+ "mthsrr0 r10",
+ "mthsrr1 r11",
+ "hrfid",
+ ]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [], initial_mem={})
+
+ @unittest.skip("disable")
+ def test_0_cmp(self):
+ lst = ["addi 6, 0, 0x10",
+ "addi 7, 0, 0x05",
+ "subf. 1, 6, 7",
+ "cmp cr2, 1, 6, 7",
+ ]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1])
+
+ @unittest.skip("disable")
+ def test_example(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x1234",
+ "add 3, 1, 2",
+ "and 4, 1, 2"]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1, 2, 3, 4])
+
+ @unittest.skip("disable")
+ def test_ldst(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x1234",
+ "stw 1, 0(2)",
+ "lwz 3, 0(2)"
+ ]
+ initial_mem = {0x1230: (0x5432123412345678, 8),
+ 0x1238: (0xabcdef0187654321, 8),
+ }
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program,
+ [1, 2, 3],
+ initial_mem)
+
+ @unittest.skip("disable")
+ def test_ldst_update(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x1234",
+ "stwu 1, 0(2)",
+ "lwz 3, 0(2)"
+ ]
+ initial_mem = {0x1230: (0x5432123412345678, 8),
+ 0x1238: (0xabcdef0187654321, 8),
+ }
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program,
+ [1, 2, 3],
+ initial_mem)
+
+ @unittest.skip("disable")
+ def test_ld_rev_ext(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x1234",
+ "addi 4, 0, 0x40",
+ "stw 1, 0x40(2)",
+ "lwbrx 3, 4, 2"]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ @unittest.skip("disable")
+ def test_st_rev_ext(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x1234",
+ "addi 4, 0, 0x40",
+ "stwbrx 1, 4, 2",
+ "lwzx 3, 4, 2"]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ @unittest.skip("disable")
+ def test_ldst_extended(self):
+ lst = ["addi 1, 0, 0x5678",
+ "addi 2, 0, 0x1234",
+ "addi 4, 0, 0x40",
+ "stw 1, 0x40(2)",
+ "lwzx 3, 4, 2"]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ @unittest.skip("disable")
+ def test_0_ldst_widths(self):
+ lst = ["addis 1, 0, 0xdead",
+ "ori 1, 1, 0xbeef",
+ "addi 2, 0, 0x1000",
+ "std 1, 0(2)",
+ "lbz 1, 5(2)",
+ "lhz 3, 4(2)",
+ "lwz 4, 4(2)",
+ "addi 5, 0, 0x12",
+ "stb 5, 5(2)",
+ "ld 5, 0(2)"]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1, 2, 3, 4, 5])
+
+ @unittest.skip("disable")
+ def test_sub(self):
+ lst = ["addi 1, 0, 0x1234",
+ "addi 2, 0, 0x5678",
+ "subf 3, 1, 2",
+ "subfic 4, 1, 0x1337",
+ "neg 5, 1"]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1, 2, 3, 4, 5])
+
+ @unittest.skip("disable")
+ def test_add_with_carry(self):
+ lst = ["addi 1, 0, 5",
+ "neg 1, 1",
+ "addi 2, 0, 7",
+ "neg 2, 2",
+ "addc 3, 2, 1",
+ "addi 3, 3, 1"
+ ]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1, 2, 3])
+
+ @unittest.skip("disable")
+ def test_addis(self):
+ lst = ["addi 1, 0, 0x0FFF",
+ "addis 1, 1, 0x0F"
+ ]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1])
+
+ @unittest.skip("broken")
+ def test_mulli(self):
+ lst = ["addi 1, 0, 3",
+ "mulli 1, 1, 2"
+ ]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1])
+
+ #@unittest.skip("disable")
+ def test_crxor(self):
+ lst = ["addi 1, 0, 0x1004",
+ "addi 2, 0, 0x1008",
+ "addi 3, 0, 0x01ee",
+ "mtcrf 0b1111111, 3",
+ "crxor 3, 30, 4",
+ "mfcr 3",
+ ]
+ initial_regs = [0] * 32
+ initial_regs[1] = 0x1004
+ initial_regs[2] = 0x1008
+ initial_regs[3] = 0x01ee
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [3, 4])
+
+ #@unittest.skip("disable")
+ def test_crxor_2(self):
+ lst = ["addi 1, 0, 0x1004",
+ "addi 2, 0, 0x1008",
+ "addi 3, 0, 0x01ee",
+ "mtcrf 0b1111111, 3",
+ "crxor 29, 30, 29",
+ "mfcr 3",
+ ]
+ initial_regs = [0] * 32
+ initial_regs[1] = 0x1004
+ initial_regs[2] = 0x1008
+ initial_regs[3] = 0x01ee
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [3, 4])
+
+ #@unittest.skip("disable")
+ def test_crnand(self):
+ lst = ["addi 1, 0, 0x1004",
+ "addi 2, 0, 0x1008",
+ "addi 3, 0, 0x01ee",
+ "mtcrf 0b1111111, 3",
+ "crnand 3, 30, 4",
+ "mfcr 3",
+ ]
+ initial_regs = [0] * 32
+ initial_regs[1] = 0x1004
+ initial_regs[2] = 0x1008
+ initial_regs[3] = 0x01ee
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [3, 4])
+
+ #@unittest.skip("disable")
+ def test_crnand_2(self):
+ lst = ["addi 1, 0, 0x1004",
+ "addi 2, 0, 0x1008",
+ "addi 3, 0, 0x01ee",
+ "mtcrf 0b1111111, 3",
+ "crnand 28, 30, 29",
+ "mfcr 3",
+ ]
+ initial_regs = [0] * 32
+ initial_regs[1] = 0x1004
+ initial_regs[2] = 0x1008
+ initial_regs[3] = 0x01ee
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [3, 4])
+
+ @unittest.skip("disable")
+ def test_isel_1(self):
+ lst = ["addi 1, 0, 0x1004",
+ "addi 2, 0, 0x1008",
+ "addi 3, 0, 0x01ee",
+ "mtcrf 0b1111111, 3",
+ "isel 4, 1, 2, 2"
+ ]
+ initial_regs = [0] * 32
+ initial_regs[1] = 0x1004
+ initial_regs[2] = 0x1008
+ initial_regs[3] = 0x00ee
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [3, 4])
+
+ #@unittest.skip("disable")
+ def test_isel_2(self):
+ lst = ["addi 1, 0, 0x1004",
+ "addi 2, 0, 0x1008",
+ "addi 3, 0, 0x01ee",
+ "mtcrf 0b1111111, 3",
+ "isel 4, 1, 2, 30"
+ ]
+ initial_regs = [0] * 32
+ initial_regs[1] = 0x1004
+ initial_regs[2] = 0x1008
+ initial_regs[3] = 0x00ee
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [3, 4])
+
+ @unittest.skip("disable")
+ def test_isel_3(self):
+ lst = ["addi 1, 0, 0x1004",
+ "addi 2, 0, 0x1008",
+ "addi 3, 0, 0x01ee",
+ "mtcrf 0b1111111, 3",
+ "isel 4, 1, 2, 31"
+ ]
+ initial_regs = [0] * 32
+ initial_regs[1] = 0x1004
+ initial_regs[2] = 0x1008
+ initial_regs[3] = 0x00ee
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [3, 4])
+
+ @unittest.skip("disable")
+ def test_2_load_store(self):
+ lst = ["addi 1, 0, 0x1004",
+ "addi 2, 0, 0x1008",
+ "addi 3, 0, 0x00ee",
+ "stb 3, 1(2)",
+ "lbz 4, 1(2)",
+ ]
+ initial_regs = [0] * 32
+ initial_regs[1] = 0x1004
+ initial_regs[2] = 0x1008
+ initial_regs[3] = 0x00ee
+ initial_mem = {0x1000: (0x5432123412345678, 8),
+ 0x1008: (0xabcdef0187654321, 8),
+ 0x1020: (0x1828384822324252, 8),
+ }
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [3, 4], initial_mem)
+
+ @unittest.skip("disable")
+ def test_3_load_store(self):
+ lst = ["addi 1, 0, 0x1004",
+ "addi 2, 0, 0x1002",
+ "addi 3, 0, 0x15eb",
+ "sth 4, 0(2)",
+ "lhz 4, 0(2)"]
+ initial_regs = [0] * 32
+ initial_regs[1] = 0x1004
+ initial_regs[2] = 0x1002
+ initial_regs[3] = 0x15eb
+ initial_mem = {0x1000: (0x5432123412345678, 8),
+ 0x1008: (0xabcdef0187654321, 8),
+ 0x1020: (0x1828384822324252, 8),
+ }
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1, 2, 3, 4], initial_mem)
+
+ @unittest.skip("disable")
+ def test_nop(self):
+ lst = ["addi 1, 0, 0x1004",
+ "ori 0,0,0", # "preferred" form of nop
+ "addi 3, 0, 0x15eb",
+ ]
+ initial_regs = [0] * 32
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1, 3])
+
+ @unittest.skip("disable")
+ def test_zero_illegal(self):
+ lst = bytes([0x10,0x00,0x20,0x39,
+ 0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0 ])
+ disassembly = ["addi 9, 0, 0x10",
+ "nop", # not quite
+ "nop"] # not quite
+ initial_regs = [0] * 32
+ with Program(lst, bigendian) as program:
+ program.assembly = '\n'.join(disassembly) + '\n' # XXX HACK!
+ self.run_tst_program(program, [1, 3])
+
+ def test_loop(self):
+ """
+ in godbolt.org:
+ register unsigned long i asm ("r9");
+ void square(void) {
+ i = 16;
+ do {
+ i = i - 1;
+ } while (i != 12);
+ }
+ """
+ lst = ["addi 9, 0, 0x10", # i = 16
+ "addi 9,9,-1", # i = i - 1
+ "cmpi 2,1,9,12", # compare 9 to value 12, store in CR2
+ "bc 4,10,-8" # branch if CR2 "test was != 12"
+ ]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [9], initial_mem={})
+
+ @unittest.skip("disable")
+ def test_30_addis(self):
+ lst = [ # "addi 0, 0, 5",
+ "addis 12, 0, 0",
+ ]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [12])
+
+ @unittest.skip("disable")
+ def test_31_addis(self):
+ """tests for zero not in register zero
+ """
+ lst = [ "rldicr 0, 0, 32, 31",
+ "oris 0, 0, 32767",
+ "ori 0, 0, 65535",
+ "addis 1, 0, 1",
+ "ori 1, 1, 515",
+ "rldicr 1, 1, 32, 31",
+ "oris 1, 1, 1029",
+ "ori 1, 1, 1543",
+ "addis 2, 0, -1",
+ ]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [0, 1, 2])
+
+ def run_tst_program(self, prog, initial_regs=None, initial_sprs=None,
+ initial_mem=None):
+ initial_regs = [0] * 32
+ tc = TestCase(prog, self.test_name, initial_regs, initial_sprs, 0,
+ initial_mem, 0)
+ self.test_data.append(tc)
+
+
+class DecoderBase:
+
+ def run_tst(self, generator, initial_mem=None, initial_pc=0):
+ m = Module()
+ comb = m.d.comb
+
+ gen = list(generator.generate_instructions())
+ insn_code = generator.assembly.splitlines()
+ instructions = list(zip(gen, insn_code))
+
+ pdecode = create_pdecode()
+ m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
+
+ # place program at requested address
+ gen = (initial_pc, gen)
+
+ simulator = ISA(pdecode2, [0] * 32, {}, 0, initial_mem, 0,
+ initial_insns=gen, respect_pc=True,
+ disassembly=insn_code,
+ initial_pc=initial_pc,
+ bigendian=bigendian)
+
+ sim = Simulator(m)
+
+ def process():
+ # yield pdecode2.dec.bigendian.eq(bigendian)
+ yield Settle()
+
+ while True:
+ try:
+ yield from simulator.setup_one()
+ except KeyError: # indicates instruction not in imem: stop
+ break
+ yield Settle()
+ yield from simulator.execute_one()
+ yield Settle()
+
+ sim.add_process(process)
+ with sim.write_vcd("pdecode_simulator.vcd"):
+ sim.run()
+
+ return simulator
+
+ def run_tst_program(self, prog, reglist, initial_mem=None,
+ extra_break_addr=None):
+ import sys
+ simulator = self.run_tst(prog, initial_mem=initial_mem,
+ initial_pc=0x20000000)
+ prog.reset()
+ with run_program(prog, initial_mem, extra_break_addr,
+ bigendian=bigendian) as q:
+ self.qemu_register_compare(simulator, q, reglist)
+ self.qemu_mem_compare(simulator, q, True)
+ print(simulator.gpr.dump())
+
+ def qemu_mem_compare(self, sim, qemu, check=True):
+ if False: # disable convenient large interesting debugging memory dump
+ addr = 0x0
+ qmemdump = qemu.get_mem(addr, 2048)
+ for i in range(len(qmemdump)):
+ s = hex(int(qmemdump[i]))
+ print("qemu mem %06x %s" % (addr+i*8, s))
+ for k, v in sim.mem.mem.items():
+ qmemdump = qemu.get_mem(k*8, 8)
+ s = hex(int(qmemdump[0]))[2:]
+ print("qemu mem %06x %16s" % (k*8, s))
+ for k, v in sim.mem.mem.items():
+ print("sim mem %06x %016x" % (k*8, v))
+ if not check:
+ return
+ for k, v in sim.mem.mem.items():
+ qmemdump = qemu.get_mem(k*8, 1)
+ self.assertEqual(int(qmemdump[0]), v)
+
+ def qemu_register_compare(self, sim, qemu, regs):
+ qpc, qxer, qcr = qemu.get_pc(), qemu.get_xer(), qemu.get_cr()
+ sim_cr = sim.cr.value
+ sim_pc = sim.pc.CIA.value
+ sim_xer = sim.spr['XER'].value
+ print("qemu pc", hex(qpc))
+ print("qemu cr", hex(qcr))
+ print("qemu xer", bin(qxer))
+ print("sim nia", hex(sim.pc.NIA.value))
+ print("sim pc", hex(sim.pc.CIA.value))
+ print("sim cr", hex(sim_cr))
+ print("sim xer", hex(sim_xer))
+ self.assertEqual(qpc, sim_pc)
+ for reg in regs:
+ qemu_val = qemu.get_register(reg)
+ sim_val = sim.gpr(reg).value
+ self.assertEqual(qemu_val, sim_val,
+ "expect %x got %x" % (qemu_val, sim_val))
+ self.assertEqual(qcr, sim_cr)
+
+
+class DecoderTestCase(DecoderBase, GeneralTestCases):
+ pass
+
+
+if __name__ == "__main__":
+ unittest.main()
--- /dev/null
+from nmigen import Module, Signal
+from nmigen.back.pysim import Simulator, Delay, Settle
+from nmutil.formaltest import FHDLTestCase
+import unittest
+from soc.decoder.power_decoder import (create_pdecode)
+from soc.decoder.power_enums import (Function, MicrOp,
+ In1Sel, In2Sel, In3Sel,
+ OutSel, RC, LdstLen, CryIn,
+ single_bit_flags, Form, SPR,
+ get_signal_name, get_csv)
+from soc.decoder.power_decoder2 import (PowerDecode2)
+from soc.simulator.program import Program
+from soc.simulator.qemu import run_program
+from soc.decoder.isa.all import ISA
+from soc.fu.test.common import TestCase
+from soc.simulator.test_sim import DecoderBase
+from soc.config.endian import bigendian
+
+
+class TrapSimTestCases(FHDLTestCase):
+ test_data = []
+
+ def __init__(self, name="div"):
+ super().__init__(name)
+ self.test_name = name
+
+ def test_0_not_twi(self):
+ lst = ["addi 1, 0, 0x5678",
+ "twi 4, 1, 0x5677",
+ ]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1])
+
+ def test_1_twi_eq(self):
+ lst = ["addi 1, 0, 0x5678",
+ "twi 4, 1, 0x5678",
+ ]
+ with Program(lst, bigendian) as program:
+ self.run_tst_program(program, [1])
+
+ def run_tst_program(self, prog, initial_regs=None, initial_sprs=None,
+ initial_mem=None):
+ initial_regs = [0] * 32
+ tc = TestCase(prog, self.test_name, initial_regs, initial_sprs, 0,
+ initial_mem, 0)
+ self.test_data.append(tc)
+
+
+class TrapDecoderTestCase(DecoderBase, TrapSimTestCases):
+ pass
+
+
+if __name__ == "__main__":
+ unittest.main()