diff --git a/power_fv/check/insn/all.py b/power_fv/check/insn/all.py index 989eb13..452f080 100644 --- a/power_fv/check/insn/all.py +++ b/power_fv/check/insn/all.py @@ -5,5 +5,6 @@ from .cr import * from .compare import * from .logical import * from .rotate import * +from .bcd import * from .msr import * from .spr import * diff --git a/power_fv/check/insn/bcd.py b/power_fv/check/insn/bcd.py new file mode 100644 index 0000000..36f0f60 --- /dev/null +++ b/power_fv/check/insn/bcd.py @@ -0,0 +1,11 @@ +from power_fv.insn import const +from power_fv.insn.spec.bcd import BCDAssistSpec +from power_fv.check.insn import InsnCheck + + +__all__ = ["CDTBCD", "CBCDTD", "ADDG6S"] + + +class CDTBCD (InsnCheck, spec_cls=BCDAssistSpec, insn_cls=const.CDTBCD): pass +class CBCDTD (InsnCheck, spec_cls=BCDAssistSpec, insn_cls=const.CBCDTD): pass +class ADDG6S (InsnCheck, spec_cls=BCDAssistSpec, insn_cls=const.ADDG6S): pass diff --git a/power_fv/insn/const.py b/power_fv/insn/const.py index eccd9f8..27299e5 100644 --- a/power_fv/insn/const.py +++ b/power_fv/insn/const.py @@ -191,6 +191,12 @@ class SRAWI_ (WordInsn): _fields = (f.PO(31), f.RS(), f.RA(), f.SH(), f.XO_X(82 class SRAW (WordInsn): _fields = (f.PO(31), f.RS(), f.RA(), f.RB(), f.XO_X(792), f.Rc(0)) class SRAW_ (WordInsn): _fields = (f.PO(31), f.RS(), f.RA(), f.RB(), f.XO_X(792), f.Rc(1)) +# BCD Assist + +class CDTBCD (WordInsn): _fields = (f.PO(31), f.RS(), f.RA(), f.XO_X(282)) +class CBCDTD (WordInsn): _fields = (f.PO(31), f.RS(), f.RA(), f.XO_X(314)) +class ADDG6S (WordInsn): _fields = (f.PO(31), f.RT(), f.RA(), f.RB(), f.XO(74)) + # Move To/From System Register class MTMSR (WordInsn): _fields = (f.PO(31), f.RS(), f.L_X15(), f.XO_X(146)) diff --git a/power_fv/insn/spec/bcd.py b/power_fv/insn/spec/bcd.py new file mode 100644 index 0000000..3b261ca --- /dev/null +++ b/power_fv/insn/spec/bcd.py @@ -0,0 +1,150 @@ +from amaranth import * + +from power_fv import pfv +from power_fv.insn.const import * + +from . import InsnSpec +from .utils import iea + + +__all__ = ["BCDAssistSpec"] + + +class BCDAssistSpec(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.intr.eq(0), + self.pfv.nia .eq(iea(self.pfv.cia + 4, self.pfv.msr.r_data.sf)), + self.pfv.msr.r_mask.sf.eq(1), + ] + + bcd_layout = [(f, 1) for f in reversed("abcdefghijkm")] + dpd_layout = [(f, 1) for f in reversed("pqrstuvwxy")] + + def _bcd_to_dpd(bcd, dpd): + # (see PowerISA v3.1, Book I, Appendix B.1) + stmts = [ + dpd.p.eq((bcd.f & bcd.a & bcd.i & ~bcd.e) | (bcd.j & bcd.a & ~bcd.i) | (bcd.b & ~bcd.a)), + dpd.q.eq((bcd.g & bcd.a & bcd.i & ~bcd.e) | (bcd.k & bcd.a & ~bcd.i) | (bcd.c & ~bcd.a)), + dpd.r.eq(bcd.d), + + dpd.s.eq((bcd.j & ~bcd.a & bcd.e & ~bcd.i) | (bcd.f & ~bcd.i & ~bcd.e) | (bcd.f & ~bcd.a & ~bcd.e) | (bcd.e & bcd.i)), + dpd.t.eq((bcd.k & ~bcd.a & bcd.e & ~bcd.i) | (bcd.g & ~bcd.i & ~bcd.e) | (bcd.g & ~bcd.a & ~bcd.e) | (bcd.a & bcd.i)), + dpd.u.eq(bcd.h), + + dpd.v.eq(bcd.a | bcd.e | bcd.i), + + dpd.w.eq((~bcd.e & bcd.j & ~bcd.i) | (bcd.e & bcd.i) | bcd.a), + dpd.x.eq((~bcd.a & bcd.k & ~bcd.i) | (bcd.a & bcd.i) | bcd.e), + dpd.y.eq(bcd.m), + ] + return stmts + + def _dpd_to_bcd(dpd, bcd): + # (see PowerISA v3.1, Book I, Appendix B.2) + stmts = [ + bcd.a.eq((~dpd.s & dpd.v & dpd.w) | (dpd.t & dpd.v & dpd.w & dpd.s) | (dpd.v & dpd.w & ~dpd.x)), + bcd.b.eq((dpd.p & dpd.s & dpd.x & ~dpd.t) | (dpd.p & ~dpd.w) | (dpd.p & ~dpd.v)), + bcd.c.eq((dpd.q & dpd.s & dpd.x & ~dpd.t) | (dpd.q & ~dpd.w) | (dpd.q & ~dpd.v)), + bcd.d.eq(dpd.r), + + bcd.e.eq((dpd.v & ~dpd.w & dpd.x) | (dpd.s & dpd.v & dpd.w & dpd.x) | (~dpd.t & dpd.v & dpd.x & dpd.w)), + bcd.f.eq((dpd.p & dpd.t & dpd.v & dpd.w & dpd.x & ~dpd.s) | (dpd.s & ~dpd.x & dpd.v) | (dpd.s & ~dpd.v)), + bcd.g.eq((dpd.q & dpd.t & dpd.w & dpd.v & dpd.x & ~dpd.s) | (dpd.t & ~dpd.x & dpd.v) | (dpd.t & ~dpd.v)), + bcd.h.eq(dpd.u), + + bcd.i.eq((dpd.t & dpd.v & dpd.w & dpd.x) | (dpd.s & dpd.v & dpd.w & dpd.x) | (dpd.v & ~dpd.w & ~dpd.x)), + bcd.j.eq((dpd.p & ~dpd.s & ~dpd.t & dpd.w & dpd.v) | (dpd.s & dpd.v & ~dpd.w & dpd.x) | (dpd.p & dpd.w & ~dpd.x & dpd.v) | (dpd.w & ~dpd.v)), + bcd.k.eq((dpd.q & ~dpd.s & ~dpd.t & dpd.v & dpd.w) | (dpd.t & dpd.v & ~dpd.w & dpd.x) | (dpd.q & dpd.v & dpd.w & ~dpd.x) | (dpd.x & ~dpd.v)), + bcd.m.eq(dpd.y), + ] + return stmts + + if isinstance(self.insn, CDTBCD): + dpd_0 = Record([("lo", dpd_layout), ("hi", dpd_layout)]) + bcd_0 = Record([("lo", bcd_layout), ("hi", bcd_layout)]) + dpd_1 = Record([("lo", dpd_layout), ("hi", dpd_layout)]) + bcd_1 = Record([("lo", bcd_layout), ("hi", bcd_layout)]) + + m.d.comb += [ + self.pfv.rs.index.eq(self.insn.RS), + self.pfv.rs.r_stb.eq(1), + dpd_0.eq(self.pfv.rs.r_data[63-31:64-12]), + dpd_1.eq(self.pfv.rs.r_data[63-63:64-44]), + + _dpd_to_bcd(dpd_0.lo, bcd_0.lo), + _dpd_to_bcd(dpd_0.hi, bcd_0.hi), + _dpd_to_bcd(dpd_1.lo, bcd_1.lo), + _dpd_to_bcd(dpd_1.hi, bcd_1.hi), + + self.pfv.ra.index .eq(self.insn.RA), + self.pfv.ra.w_stb .eq(1), + self.pfv.ra.w_data[63-31:64- 8].eq(bcd_0), + self.pfv.ra.w_data[63-63:64-40].eq(bcd_1), + ] + + elif isinstance(self.insn, CBCDTD): + bcd_0 = Record([("lo", bcd_layout), ("hi", bcd_layout)]) + dpd_0 = Record([("lo", dpd_layout), ("hi", dpd_layout)]) + bcd_1 = Record([("lo", bcd_layout), ("hi", bcd_layout)]) + dpd_1 = Record([("lo", dpd_layout), ("hi", dpd_layout)]) + + m.d.comb += [ + self.pfv.rs.index.eq(self.insn.RS), + self.pfv.rs.r_stb.eq(1), + bcd_0.eq(self.pfv.rs.r_data[63-31:64- 8]), + bcd_1.eq(self.pfv.rs.r_data[63-63:64-40]), + + _bcd_to_dpd(bcd_0.lo, dpd_0.lo), + _bcd_to_dpd(bcd_0.hi, dpd_0.hi), + _bcd_to_dpd(bcd_1.lo, dpd_1.lo), + _bcd_to_dpd(bcd_1.hi, dpd_1.hi), + + self.pfv.ra.index.eq(self.insn.RA), + self.pfv.ra.w_stb.eq(1), + self.pfv.ra.w_data[63-31:64-12].eq(dpd_0), + self.pfv.ra.w_data[63-63:64-44].eq(dpd_1), + ] + + elif isinstance(self.insn, ADDG6S): + src_a = Signal(unsigned(65)) + src_b = Signal(unsigned(65)) + result = Signal(unsigned(65)) + cout_6s = Signal(unsigned(64)) + + m.d.comb += [ + self.pfv.ra.index.eq(self.insn.RA), + self.pfv.ra.r_stb.eq(1), + self.pfv.rb.index.eq(self.insn.RB), + self.pfv.rb.r_stb.eq(1), + + src_a .eq(self.pfv.ra.r_data), + src_b .eq(self.pfv.rb.r_data), + result.eq(src_a + src_b), + ] + + for i in range(64//4): + a_bit = src_a [i*4 + 4] + b_bit = src_b [i*4 + 4] + r_bit = result[i*4 + 4] + c_nib = cout_6s.word_select(i, width=4) + m.d.comb += c_nib.eq(Mux(a_bit ^ b_bit ^ r_bit, 0x0, 0x6)) + + m.d.comb += [ + self.pfv.rt.index .eq(self.insn.RT), + self.pfv.rt.w_stb .eq(1), + self.pfv.rt.w_data.eq(cout_6s), + ] + + else: + assert False + + return m