from nmigen import Module, Signal
from nmigen.back.pysim import Simulator, Delay
-from nmigen.test.utils import FHDLTestCase
+from nmutil.formaltest import FHDLTestCase
import unittest
from soc.decoder.power_decoder import (create_pdecode)
-from soc.decoder.power_enums import (Function, InternalOp,
+from soc.decoder.power_enums import (Function, MicrOp,
In1Sel, In2Sel, In3Sel,
OutSel, RC, LdstLen, CryIn,
- single_bit_flags, Form,
+ single_bit_flags, Form, SPR,
get_signal_name, get_csv)
from soc.decoder.power_decoder2 import (PowerDecode2)
-import tempfile
-import subprocess
-import struct
+from soc.simulator.gas import get_assembled_instruction
import random
-import pdb
-
class Register:
def __init__(self, num):
self.num = num
+
+class Checker:
+ def __init__(self):
+ self.imm = 0
+
+ def get_imm(self, in2_sel):
+ if in2_sel == In2Sel.CONST_UI.value:
+ return self.imm & 0xffff
+ if in2_sel == In2Sel.CONST_UI_HI.value:
+ return (self.imm & 0xffff) << 16
+ if in2_sel == In2Sel.CONST_SI.value:
+ sign_bit = 1 << 15
+ return (self.imm & (sign_bit-1)) - (self.imm & sign_bit)
+ if in2_sel == In2Sel.CONST_SI_HI.value:
+ imm = self.imm << 16
+ sign_bit = 1 << 31
+ return (imm & (sign_bit-1)) - (imm & sign_bit)
+
+
class RegRegOp:
def __init__(self):
self.ops = {
- "add": InternalOp.OP_ADD,
- "and": InternalOp.OP_AND,
- "or": InternalOp.OP_OR,
- "add.": InternalOp.OP_ADD,
- "lwzx": InternalOp.OP_LOAD,
- "stwx": InternalOp.OP_STORE,
+ "add": MicrOp.OP_ADD,
+ "and": MicrOp.OP_AND,
+ "or": MicrOp.OP_OR,
+ "add.": MicrOp.OP_ADD,
+ "lwzx": MicrOp.OP_LOAD,
+ "stwx": MicrOp.OP_STORE,
}
self.opcodestr = random.choice(list(self.ops.keys()))
self.opcode = self.ops[self.opcodestr]
return string
def check_results(self, pdecode2):
- if self.opcode == InternalOp.OP_STORE:
+ if self.opcode == MicrOp.OP_STORE:
r1sel = yield pdecode2.e.read_reg3.data
else:
r1sel = yield pdecode2.e.write_reg.data
assert(rc == 1)
else:
assert(rc == 0)
-
-class RegImmOp:
+class RegImmOp(Checker):
def __init__(self):
+ super().__init__()
self.ops = {
- "addi": InternalOp.OP_ADD,
- "addis": InternalOp.OP_ADD,
- "andi.": InternalOp.OP_AND,
- "ori": InternalOp.OP_OR,
+ "addi": MicrOp.OP_ADD,
+ "addis": MicrOp.OP_ADD,
+ "andi.": MicrOp.OP_AND,
+ "ori": MicrOp.OP_OR,
}
self.opcodestr = random.choice(list(self.ops.keys()))
self.opcode = self.ops[self.opcodestr]
imm = yield pdecode2.e.imm_data.data
in2_sel = yield pdecode2.dec.op.in2_sel
- if in2_sel in [In2Sel.CONST_SI_HI.value, In2Sel.CONST_UI_HI.value]:
- assert(imm == (self.imm << 16))
- else:
- assert(imm == self.imm)
+ imm_expected = self.get_imm(in2_sel)
+ msg = "imm: got {:x}, expected {:x}".format(imm, imm_expected)
+ assert imm == imm_expected, msg
rc = yield pdecode2.e.rc.data
if '.' in self.opcodestr:
else:
assert(rc == 0)
-class LdStOp:
+
+class LdStOp(Checker):
def __init__(self):
+ super().__init__()
self.ops = {
- "lwz": InternalOp.OP_LOAD,
- "stw": InternalOp.OP_STORE,
- "lwzu": InternalOp.OP_LOAD,
- "stwu": InternalOp.OP_STORE,
- "lbz": InternalOp.OP_LOAD,
- "lhz": InternalOp.OP_LOAD,
- "stb": InternalOp.OP_STORE,
- "sth": InternalOp.OP_STORE,
+ "lwz": MicrOp.OP_LOAD,
+ "stw": MicrOp.OP_STORE,
+ "lwzu": MicrOp.OP_LOAD,
+ "stwu": MicrOp.OP_STORE,
+ "lbz": MicrOp.OP_LOAD,
+ "lhz": MicrOp.OP_LOAD,
+ "stb": MicrOp.OP_STORE,
+ "sth": MicrOp.OP_STORE,
}
self.opcodestr = random.choice(list(self.ops.keys()))
self.opcode = self.ops[self.opcodestr]
self.r1 = Register(random.randrange(32))
- self.r2 = Register(random.randrange(1,32))
+ self.r2 = Register(random.randrange(1, 32))
+ while self.r2.num == self.r1.num:
+ self.r2 = Register(random.randrange(1, 32))
self.imm = random.randrange(32767)
def generate_instruction(self):
def check_results(self, pdecode2):
print("Check")
r2sel = yield pdecode2.e.read_reg1.data
- if self.opcode == InternalOp.OP_STORE:
+ if self.opcode == MicrOp.OP_STORE:
r1sel = yield pdecode2.e.read_reg3.data
else:
r1sel = yield pdecode2.e.write_reg.data
imm = yield pdecode2.e.imm_data.data
in2_sel = yield pdecode2.dec.op.in2_sel
- assert(imm == self.imm)
+ assert(imm == self.get_imm(in2_sel))
update = yield pdecode2.e.update
if "u" in self.opcodestr:
else:
assert(False)
-class DecoderTestCase(FHDLTestCase):
- def get_assembled_instruction(self, instruction):
- with tempfile.NamedTemporaryFile(suffix=".o") as outfile:
- args = ["powerpc64-linux-gnu-as",
- "-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",
- "-O", "binary",
- outfile.name,
- binfile.name]
- subprocess.check_output(args)
- binary = struct.unpack('>i', binfile.read(4))[0]
- return binary
+class CmpRegOp:
+ def __init__(self):
+ self.ops = {
+ "cmp": MicrOp.OP_CMP,
+ }
+ self.opcodestr = random.choice(list(self.ops.keys()))
+ self.opcode = self.ops[self.opcodestr]
+ self.r1 = Register(random.randrange(32))
+ self.r2 = Register(random.randrange(32))
+ self.cr = Register(random.randrange(8))
+
+ def generate_instruction(self):
+ string = "{} {}, 0, {}, {}\n".format(self.opcodestr,
+ self.cr.num,
+ self.r1.num,
+ self.r2.num)
+ return string
+
+ def check_results(self, pdecode2):
+ r1sel = yield pdecode2.e.read_reg1.data
+ r2sel = yield pdecode2.e.read_reg2.data
+ crsel = yield pdecode2.dec.BF
+
+ assert(r1sel == self.r1.num)
+ assert(r2sel == self.r2.num)
+ assert(crsel == self.cr.num)
+
+
+class RotateOp:
+ def __init__(self):
+ self.ops = {
+ "rlwinm": MicrOp.OP_CMP,
+ "rlwnm": MicrOp.OP_CMP,
+ "rlwimi": MicrOp.OP_CMP,
+ "rlwinm.": MicrOp.OP_CMP,
+ "rlwnm.": MicrOp.OP_CMP,
+ "rlwimi.": MicrOp.OP_CMP,
+ }
+ self.opcodestr = random.choice(list(self.ops.keys()))
+ self.opcode = self.ops[self.opcodestr]
+ self.r1 = Register(random.randrange(32))
+ self.r2 = Register(random.randrange(32))
+ self.shift = random.randrange(32)
+ self.mb = random.randrange(32)
+ self.me = random.randrange(32)
+
+ def generate_instruction(self):
+ string = "{} {},{},{},{},{}\n".format(self.opcodestr,
+ self.r1.num,
+ self.r2.num,
+ self.shift,
+ self.mb,
+ self.me)
+ return string
+
+ def check_results(self, pdecode2):
+ r1sel = yield pdecode2.e.write_reg.data
+ r2sel = yield pdecode2.e.read_reg3.data
+ dec = pdecode2.dec
+
+ if "i" in self.opcodestr:
+ shift = yield dec.SH
+ else:
+ shift = yield pdecode2.e.read_reg2.data
+ mb = yield dec.MB
+ me = yield dec.ME
+
+ assert(r1sel == self.r1.num)
+ assert(r2sel == self.r2.num)
+ assert(shift == self.shift)
+ assert(mb == self.mb)
+ assert(me == self.me)
+
+ rc = yield pdecode2.e.rc.data
+ if '.' in self.opcodestr:
+ assert(rc == 1)
+ else:
+ assert(rc == 0)
+
+
+class Branch:
+ def __init__(self):
+ self.ops = {
+ "b": MicrOp.OP_B,
+ "bl": MicrOp.OP_B,
+ "ba": MicrOp.OP_B,
+ "bla": MicrOp.OP_B,
+ }
+ self.opcodestr = random.choice(list(self.ops.keys()))
+ self.opcode = self.ops[self.opcodestr]
+ self.addr = random.randrange(2**23) * 4
+
+ def generate_instruction(self):
+ string = "{} {}\n".format(self.opcodestr,
+ self.addr)
+ return string
+
+ def check_results(self, pdecode2):
+ imm = yield pdecode2.e.imm_data.data
+
+ assert(imm == self.addr)
+ lk = yield pdecode2.e.lk
+ if "l" in self.opcodestr:
+ assert(lk == 1)
+ else:
+ assert(lk == 0)
+ aa = yield pdecode2.dec.AA
+ if "a" in self.opcodestr:
+ assert(aa == 1)
+ else:
+ assert(aa == 0)
+
+
+class BranchCond:
+ def __init__(self):
+ self.ops = {
+ "bc": MicrOp.OP_B,
+ "bcl": MicrOp.OP_B,
+ "bca": MicrOp.OP_B,
+ "bcla": MicrOp.OP_B,
+ }
+ # Given in Figure 40 "BO field encodings" in section 2.4, page
+ # 33 of the Power ISA v3.0B manual
+ self.branchops = [0b00000, 0b00010, 0b00100, 0b01000, 0b01010,
+ 0b01100, 0b10000, 0b10100]
+ self.opcodestr = random.choice(list(self.ops.keys()))
+ self.opcode = self.ops[self.opcodestr]
+ self.addr = random.randrange(2**13) * 4
+ self.bo = random.choice(self.branchops)
+ self.bi = random.randrange(32)
+
+ def generate_instruction(self):
+ string = "{} {},{},{}\n".format(self.opcodestr,
+ self.bo,
+ self.bi,
+ self.addr)
+ return string
+
+ def check_results(self, pdecode2):
+ imm = yield pdecode2.e.imm_data.data
+ bo = yield pdecode2.dec.BO
+ bi = yield pdecode2.dec.BI
+
+ assert(imm == self.addr)
+ assert(bo == self.bo)
+ assert(bi == self.bi)
+ lk = yield pdecode2.e.lk
+ if "l" in self.opcodestr:
+ assert(lk == 1)
+ else:
+ assert(lk == 0)
+ aa = yield pdecode2.dec.AA
+ if "a" in self.opcodestr:
+ assert(aa == 1)
+ else:
+ assert(aa == 0)
+
+ cr_sel = yield pdecode2.e.read_cr1.data
+ assert cr_sel == (self.bi//8), f"{cr_sel} {self.bi}"
+
+
+
+class BranchRel:
+ def __init__(self):
+ self.ops = {
+ "bclr": MicrOp.OP_B,
+ "bcctr": MicrOp.OP_B,
+ "bclrl": MicrOp.OP_B,
+ "bcctrl": MicrOp.OP_B,
+ }
+ # Given in Figure 40 "BO field encodings" in section 2.4, page
+ # 33 of the Power ISA v3.0B manual
+ self.branchops = [0b00100, 0b01100, 0b10100]
+ self.opcodestr = random.choice(list(self.ops.keys()))
+ self.opcode = self.ops[self.opcodestr]
+ self.bh = random.randrange(4)
+ self.bo = random.choice(self.branchops)
+ self.bi = random.randrange(32)
+
+ def generate_instruction(self):
+ string = "{} {},{},{}\n".format(self.opcodestr,
+ self.bo,
+ self.bi,
+ self.bh)
+ return string
+
+ def check_results(self, pdecode2):
+ bo = yield pdecode2.dec.BO
+ bi = yield pdecode2.dec.BI
+
+ assert(bo == self.bo)
+ assert(bi == self.bi)
+
+ spr = yield pdecode2.e.read_spr2.data
+ if "lr" in self.opcodestr:
+ assert(spr == SPR.LR.value)
+ else:
+ assert(spr == SPR.CTR.value)
+
+ lk = yield pdecode2.e.lk
+ if self.opcodestr[-1] == 'l':
+ assert(lk == 1)
+ else:
+ assert(lk == 0)
+
+class CROp:
+ def __init__(self):
+ self.ops = {
+ "crand": MicrOp.OP_CROP,
+ }
+ # Given in Figure 40 "BO field encodings" in section 2.4, page
+ # 33 of the Power ISA v3.0B manual
+ self.opcodestr = random.choice(list(self.ops.keys()))
+ self.opcode = self.ops[self.opcodestr]
+ self.ba = random.randrange(32)
+ self.bb = random.randrange(32)
+ self.bt = random.randrange(32)
+
+ def generate_instruction(self):
+ string = "{} {},{},{}\n".format(self.opcodestr,
+ self.bt,
+ self.ba,
+ self.bb)
+ return string
+
+ def check_results(self, pdecode2):
+ cr1 = yield pdecode2.e.read_cr1.data
+ assert cr1 == self.ba//4
+
+ cr2 = yield pdecode2.e.read_cr2.data
+ assert cr2 == self.bb//4
+
+ cr_out = yield pdecode2.e.write_cr.data
+ cr3 = yield pdecode2.e.read_cr3.data
+ assert cr_out == self.bt//4
+ assert cr3 == self.bt//4
+
+
+
+class DecoderTestCase(FHDLTestCase):
def run_tst(self, kls, name):
m = Module()
pdecode = create_pdecode()
m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
- comb += pdecode2.dec.opcode_in.eq(instruction)
-
+ comb += pdecode2.dec.raw_opcode_in.eq(instruction)
sim = Simulator(m)
def process():
for i in range(20):
checker = kls()
+ ins = checker.generate_instruction()
+ print("instr", ins.strip())
+ for mode in [0, 1]:
- instruction_str = checker.generate_instruction()
- print("instr", instruction_str.strip())
- instruction_bin = self.get_assembled_instruction(
- instruction_str)
- print("code", hex(instruction_bin), bin(instruction_bin))
-
- yield instruction.eq(instruction_bin)
- yield Delay(1e-6)
+ # turn the instruction into binary data (endian'd)
+ ibin = get_assembled_instruction(ins, mode)
+ print("code", mode, hex(ibin), bin(ibin))
- yield from checker.check_results(pdecode2)
+ # ask the decoder to decode this binary data (endian'd)
+ yield pdecode2.dec.bigendian.eq(mode) # little / big?
+ yield instruction.eq(ibin) # raw binary instr.
+ yield Delay(1e-6)
+ yield from checker.check_results(pdecode2)
sim.add_process(process)
+ ports = pdecode2.ports()
+ print(ports)
with sim.write_vcd("%s.vcd" % name, "%s.gtkw" % name,
- traces=[pdecode2.ports()]):
+ traces=ports):
sim.run()
+
def test_reg_reg(self):
self.run_tst(RegRegOp, "reg_reg")
def test_ldst_imm(self):
self.run_tst(LdStOp, "ldst_imm")
+ def test_cmp_reg(self):
+ self.run_tst(CmpRegOp, "cmp_reg")
+
+ def test_rot(self):
+ self.run_tst(RotateOp, "rot")
+
+ def test_branch(self):
+ self.run_tst(Branch, "branch")
+
+ def test_branch_cond(self):
+ self.run_tst(BranchCond, "branch_cond")
+
+ def test_branch_rel(self):
+ self.run_tst(BranchRel, "branch_rel")
+
+ def test_cr_op(self):
+ self.run_tst(CROp, "cr_op")
+
if __name__ == "__main__":
unittest.main()