From b579665d7a144c8774a3aafb9f08e417284121ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Nguyen?= Date: Mon, 18 Jul 2022 15:11:38 +0200 Subject: [PATCH] Add checks for Trap instructions. --- power_fv/check/insn/all.py | 1 + power_fv/check/insn/trap.py | 10 ++++++ power_fv/insn/const.py | 5 +++ power_fv/insn/field.py | 1 + power_fv/insn/spec/trap.py | 68 +++++++++++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+) create mode 100644 power_fv/check/insn/trap.py create mode 100644 power_fv/insn/spec/trap.py diff --git a/power_fv/check/insn/all.py b/power_fv/check/insn/all.py index c0f63fc..27a5408 100644 --- a/power_fv/check/insn/all.py +++ b/power_fv/check/insn/all.py @@ -4,6 +4,7 @@ from .syscall import * from .loadstore import * from .cr import * from .compare import * +from .trap import * from .logical import * from .rotate import * from .bcd import * diff --git a/power_fv/check/insn/trap.py b/power_fv/check/insn/trap.py new file mode 100644 index 0000000..54dad63 --- /dev/null +++ b/power_fv/check/insn/trap.py @@ -0,0 +1,10 @@ +from power_fv.insn import const +from power_fv.insn.spec.trap import TrapSpec +from power_fv.check.insn import InsnCheck + + +__all__ = ["TWI", "TW"] + + +class TWI(InsnCheck, spec_cls=TrapSpec, insn_cls=const.TWI): pass +class TW (InsnCheck, spec_cls=TrapSpec, insn_cls=const.TW ): pass diff --git a/power_fv/insn/const.py b/power_fv/insn/const.py index 971b37e..9db681c 100644 --- a/power_fv/insn/const.py +++ b/power_fv/insn/const.py @@ -140,6 +140,11 @@ class CMPL (WordInsn): _fields = (f.PO(31), f.BF(), f.L_X10(), f.RA(), f.RB() class CMPRB (WordInsn): _fields = (f.PO(31), f.BF(), f.L_X10(), f.RA(), f.RB(), f.XO_X(192)) class CMPEQB (WordInsn): _fields = (f.PO(31), f.BF(), f.L_X10(), f.RA(), f.RB(), f.XO_X(224)) +# Trap + +class TWI (WordInsn): _fields = (f.PO( 3), f.TO(), f.RA(), f.SI()) +class TW (WordInsn): _fields = (f.PO(31), f.TO(), f.RA(), f.RB(), f.XO_X(4)) + # Logical class ANDI_ (WordInsn): _fields = (f.PO(28), f.RS(), f.RA(), f.UI()) diff --git a/power_fv/insn/field.py b/power_fv/insn/field.py index 3be6c0a..376e57f 100644 --- a/power_fv/insn/field.py +++ b/power_fv/insn/field.py @@ -37,6 +37,7 @@ class SC_30 (InsnField): _shape = unsigned( 1); _offset = 30; _name = "_30" class SC_31 (InsnField): _shape = unsigned( 1); _offset = 31; _name = "_31" class SI (InsnField): _shape = signed(16); _offset = 16; _name = "SI" class SH (InsnField): _shape = unsigned( 5); _offset = 16; _name = "SH" +class TO (InsnField): _shape = unsigned( 5); _offset = 6; _name = "TO" class UI (InsnField): _shape = unsigned(16); _offset = 16; _name = "UI" class XO (InsnField): _shape = unsigned( 9); _offset = 22; _name = "XO" class XO_DX (InsnField): _shape = unsigned( 5); _offset = 26; _name = "XO" diff --git a/power_fv/insn/spec/trap.py b/power_fv/insn/spec/trap.py new file mode 100644 index 0000000..b243d4d --- /dev/null +++ b/power_fv/insn/spec/trap.py @@ -0,0 +1,68 @@ +from amaranth import * + +from power_fv import pfv +from power_fv.insn.const import * + +from . import InsnSpec +from .utils import iea + + +__all__ = ["TrapSpec"] + + +class TrapSpec(InsnSpec, Elaboratable): + def __init__(self, insn): + self.pfv = pfv.Interface() + self.insn = insn + + def elaborate(self, platform): + m = Module() + + m.d.comb += [ + self.pfv.stb .eq(1), + self.pfv.insn.eq(Cat(Const(0, 32), self.insn.as_value())), + self.pfv.nia .eq(iea(self.pfv.cia + 4, self.pfv.msr.r_data.sf)), + self.pfv.msr.r_mask.sf.eq(1), + ] + + src_a = Signal(signed(64)) + src_b = Signal(signed(64)) + cond = Record([("gtu", 1), ("ltu", 1), ("eq_", 1), ("gts", 1), ("lts", 1)]) + trap = Record.like(cond) + + # Operand A : EXTS((RA)(32:63)) + + m.d.comb += [ + self.pfv.ra.index.eq(self.insn.RA), + self.pfv.ra.r_stb.eq(1), + src_a.eq(self.pfv.ra.r_data[:32].as_signed()), + ] + + # Operand B : EXTS(SI) or EXTS((RB)(32:63)) + + if isinstance(self.insn, TWI): + m.d.comb += src_b.eq(self.insn.SI) + elif isinstance(self.insn, TW): + m.d.comb += [ + self.pfv.rb.index.eq(self.insn.RB), + self.pfv.rb.r_stb.eq(1), + src_b.eq(self.pfv.rb.r_data[:32].as_signed()), + ] + else: + assert False + + # Compare operands, then trap if a condition is met. + + m.d.comb += [ + cond.eq(self.insn.TO), + + trap.lts.eq(cond.lts & (src_a < src_b)), + trap.gts.eq(cond.gts & (src_a > src_b)), + trap.eq_.eq(cond.eq_ & (src_a == src_b)), + trap.ltu.eq(cond.ltu & (src_a.as_unsigned() < src_b.as_unsigned())), + trap.gtu.eq(cond.gtu & (src_a.as_unsigned() > src_b.as_unsigned())), + + self.pfv.intr.eq(trap.any()), + ] + + return m