insn.spec: implement some interrupts (program,alignment,system call).

main
Jean-François Nguyen 2 years ago
parent 2e29794b7d
commit d3546e4362

@ -133,8 +133,7 @@ class MicrowattWrapper(Elaboratable):
end architecture behave; end architecture behave;
""") """)


def __init__(self, **kwargs): self.pfv = pfv.Interface(mem_aligned=False, illegal_insn_heai=False)
self.pfv = pfv.Interface(mem_aligned=False)
self.wb_insn = wishbone.Interface(addr_width=29, data_width=64, granularity=8, self.wb_insn = wishbone.Interface(addr_width=29, data_width=64, granularity=8,
features=("stall",)) features=("stall",))
self.wb_data = wishbone.Interface(addr_width=29, data_width=64, granularity=8, self.wb_data = wishbone.Interface(addr_width=29, data_width=64, granularity=8,
@ -256,6 +255,14 @@ class MicrowattWrapper(Elaboratable):
Assume(~dmi.req), Assume(~dmi.req),
Assume(~terminated), Assume(~terminated),
] ]
with m.If(self.pfv.stb):
m.d.comb += [
# no decrementer interrupts
Assume(self.pfv.msr.w_mask.ee.implies(~self.pfv.msr.w_data.ee)),
# no trace interrupts
Assume(self.pfv.msr.w_mask.te[0].implies(~self.pfv.msr.w_data.te[0])),
Assume(self.pfv.msr.w_mask.te[1].implies(~self.pfv.msr.w_data.te[1])),
]


return m return m



@ -62,10 +62,8 @@ class InsnTestbench(Elaboratable):
Assert(dut.pfv.intr == spec.pfv.intr), Assert(dut.pfv.intr == spec.pfv.intr),
] ]


with m.If(t_post.zero & ~spec.pfv.intr): with m.If(t_post.zero):
m.d.comb += [ m.d.comb += Assert(dut.pfv.nia == spec.pfv.nia)
Assert(dut.pfv.nia == spec.pfv.nia),
]


m.submodules.ra = ra = _GPRFileTest(self.check, port="ra") m.submodules.ra = ra = _GPRFileTest(self.check, port="ra")
m.submodules.rb = rb = _GPRFileTest(self.check, port="rb") m.submodules.rb = rb = _GPRFileTest(self.check, port="rb")
@ -79,7 +77,7 @@ class InsnTestbench(Elaboratable):
spec.pfv.rt.r_data.eq(dut.pfv.rt.r_data), spec.pfv.rt.r_data.eq(dut.pfv.rt.r_data),
] ]


with m.If(t_post.zero & ~spec.pfv.intr): with m.If(t_post.zero):
m.d.comb += [ m.d.comb += [
Assert(ra.valid.all()), Assert(ra.valid.all()),
Assert(rb.valid.all()), Assert(rb.valid.all()),
@ -91,7 +89,7 @@ class InsnTestbench(Elaboratable):


m.d.comb += spec.pfv.mem.r_data.eq(dut.pfv.mem.r_data) m.d.comb += spec.pfv.mem.r_data.eq(dut.pfv.mem.r_data)


with m.If(t_post.zero & ~spec.pfv.intr): with m.If(t_post.zero):
m.d.comb += Assert(mem.valid.all()) m.d.comb += Assert(mem.valid.all())


m.submodules.cr = cr = _SysRegTest(self.check, reg="cr" ) m.submodules.cr = cr = _SysRegTest(self.check, reg="cr" )
@ -114,7 +112,7 @@ class InsnTestbench(Elaboratable):
spec.pfv.srr1.r_data.eq(dut.pfv.srr1.r_data), spec.pfv.srr1.r_data.eq(dut.pfv.srr1.r_data),
] ]


with m.If(t_post.zero & ~spec.pfv.intr): with m.If(t_post.zero):
m.d.comb += [ m.d.comb += [
Assert(cr .valid.all()), Assert(cr .valid.all()),
Assert(msr .valid.all()), Assert(msr .valid.all()),

@ -2,9 +2,10 @@ from amaranth import *


from power_fv import pfv from power_fv import pfv
from power_fv.insn.const import * from power_fv.insn.const import *
from power_fv.intr import *


from . import InsnSpec from . import InsnSpec
from .utils import iea from .utils import iea, msr_to_srr1




__all__ = ["BranchSpec"] __all__ = ["BranchSpec"]
@ -20,7 +21,9 @@ class BranchSpec(InsnSpec, Elaboratable):
self.pfv.msr.r_mask.sf.eq(1), self.pfv.msr.r_mask.sf.eq(1),
] ]


# Raise an interrupt if the BO field is invalid. # Raise an interrupt if BO is invalid

illegal_insn = Record([("bo", 1)])


if isinstance(self.insn, ( if isinstance(self.insn, (
BC , BCA , BCL , BCLA , BC , BCA , BCL , BCLA ,
@ -42,122 +45,145 @@ class BranchSpec(InsnSpec, Elaboratable):
"1-00-", "1-00-",
"1-01-", "1-01-",
] ]
m.d.comb += self.pfv.intr.eq(~self.insn.BO.matches(*bo_valid_patterns)) m.d.comb += illegal_insn.bo.eq(~self.insn.BO.matches(*bo_valid_patterns))

else:
m.d.comb += self.pfv.intr.eq(0)

# Is this branch taken ?


taken = Signal() with m.If(illegal_insn.any()):
if self.pfv.illegal_insn_heai:
raise NotImplementedError


cond_bit = Signal() m.d.comb += [
cond_ok = Signal() self.pfv.intr.eq(1),
ctr_any = Signal() self.pfv.nia .eq(INTR_PROGRAM.vector_addr),
ctr_ok = Signal() INTR_PROGRAM.write_msr(self.pfv.msr),

self.pfv.srr0.w_mask.eq(Repl(1, 64)),
self.pfv.srr0.w_data.eq(iea(self.pfv.cia, self.pfv.msr.r_data.sf)),

self.pfv.srr1.w_mask[63-36:64-33].eq(Repl(1, 4)),
self.pfv.srr1.w_data[63-36:64-33].eq(0),
self.pfv.srr1.w_mask[63-42].eq(1),
self.pfv.srr1.w_data[63-42].eq(0),
self.pfv.srr1.w_mask[63-46:64-43].eq(Repl(1, 4)),
self.pfv.srr1.w_data[63-46:64-43].eq(0b0100), # Illegal Instruction type (deprecated)
self.pfv.srr1.w_mask[63-47].eq(1),
self.pfv.srr1.w_data[63-47].eq(0),

msr_to_srr1(self.pfv.msr, self.pfv.srr1, 0, 32),
msr_to_srr1(self.pfv.msr, self.pfv.srr1, 37, 41),
msr_to_srr1(self.pfv.msr, self.pfv.srr1, 48, 63),
]


if isinstance(self.insn, (B, BA, BL, BLA)): with m.Else():
m.d.comb += taken.eq(1) taken = Signal()
cond_bit = Signal()
cond_ok = Signal()
ctr_any = Signal()
ctr_ok = Signal()


elif isinstance(self.insn, ( # Is this branch taken ?
BC , BCA , BCL , BCLA ,
BCLR , BCLRL , BCTAR, BCTARL,
BCCTR, BCCTRL,
)):


# If BO(0) = 0, test CR(BI) if isinstance(self.insn, (B, BA, BL, BLA)):
with m.If(self.insn.BO[4 - 0]): m.d.comb += taken.eq(1)
m.d.comb += cond_ok.eq(1)
with m.Else():
m.d.comb += [
self.pfv.cr.r_mask[::-1].bit_select(self.insn.BI, width=1).eq(1),


cond_bit.eq(self.pfv.cr.r_data[::-1].bit_select(self.insn.BI, width=1)), elif isinstance(self.insn, (
cond_ok .eq(cond_bit == self.insn.BO[4 - 1]), BC , BCA , BCL , BCLA ,
] BCLR , BCLRL , BCTAR, BCTARL,
BCCTR, BCCTRL,
)):


if isinstance(self.insn, (BCCTR, BCCTRL)): with m.If(self.insn.BO[4 - 0]):
m.d.comb += taken.eq(cond_ok) m.d.comb += cond_ok.eq(1)
else:
# If BO(2) = 0, decrement CTR then test its value.
with m.If(self.insn.BO[4 - 2]):
m.d.comb += ctr_ok.eq(1)
with m.Else(): with m.Else():
# BO(0) = 0, test CR(BI)
m.d.comb += self.pfv.cr.r_mask.bit_select(31-self.insn.BI, width=1).eq(1)
m.d.comb += [ m.d.comb += [
self.pfv.ctr.r_mask.eq(Repl(1, 64)), cond_bit.eq(self.pfv.cr.r_data.bit_select(31-self.insn.BI, width=1)),
self.pfv.ctr.w_mask.eq(Repl(1, 64)), cond_ok .eq(cond_bit == self.insn.BO[4 - 1]),
self.pfv.ctr.w_data.eq(self.pfv.ctr.r_data - 1),

ctr_any.eq(iea(self.pfv.ctr.w_data, self.pfv.msr.r_data.sf).any()),
ctr_ok .eq(ctr_any ^ self.insn.BO[4 - 3]),
] ]
m.d.comb += taken.eq(cond_ok & ctr_ok)


else: if isinstance(self.insn, (BCCTR, BCCTRL)):
assert False m.d.comb += taken.eq(cond_ok)
else:
with m.If(self.insn.BO[4 - 2]):
m.d.comb += ctr_ok.eq(1)
with m.Else():
# BO(2) = 0, decrement CTR then test its value.
m.d.comb += [
self.pfv.ctr.r_mask.eq(Repl(1, 64)),
self.pfv.ctr.w_mask.eq(Repl(1, 64)),
self.pfv.ctr.w_data.eq(self.pfv.ctr.r_data - 1),
]
m.d.comb += [
ctr_any.eq(iea(self.pfv.ctr.w_data, self.pfv.msr.r_data.sf).any()),
ctr_ok .eq(ctr_any ^ self.insn.BO[4 - 3]),
]
m.d.comb += taken.eq(cond_ok & ctr_ok)


# Compute the target address else:
assert False


target = Signal(unsigned(64)) # Compute the target address
base = Signal(unsigned(64))
offset = Signal( signed(62))


# base : CIA if AA=0, 0 otherwise target = Signal(unsigned(64))
base = Signal(unsigned(64))
offset = Signal( signed(62))


if isinstance(self.insn, (B, BL, BC, BCL)): # base : CIA if AA=0, 0 otherwise
m.d.comb += base.eq(self.pfv.cia)
elif isinstance(self.insn, (
BA , BLA , BCA , BCLA ,
BCLR, BCLRL, BCCTR, BCCTRL, BCTAR, BCTARL,
)):
m.d.comb += base.eq(0)
else:
assert False


# offset : LI or BD or LR>>2 or CTR>>2 or TAR>>2 if isinstance(self.insn, (B, BL, BC, BCL)):
m.d.comb += base.eq(self.pfv.cia)
elif isinstance(self.insn, (
BA , BLA , BCA , BCLA ,
BCLR, BCLRL, BCCTR, BCCTRL, BCTAR, BCTARL,
)):
m.d.comb += base.eq(0)
else:
assert False


if isinstance(self.insn, (B, BA, BL, BLA)): # offset : LI or BD or LR>>2 or CTR>>2 or TAR>>2
m.d.comb += offset.eq(self.insn.LI)
elif isinstance(self.insn, (BC, BCA, BCL, BCLA)): if isinstance(self.insn, (B, BA, BL, BLA)):
m.d.comb += offset.eq(self.insn.BD) m.d.comb += offset.eq(self.insn.LI)
elif isinstance(self.insn, (BCLR, BCLRL)): elif isinstance(self.insn, (BC, BCA, BCL, BCLA)):
m.d.comb += [ m.d.comb += offset.eq(self.insn.BD)
self.pfv.lr.r_mask[2:].eq(Repl(1, 62)), elif isinstance(self.insn, (BCLR, BCLRL)):
offset.eq(self.pfv.lr.r_data[2:]), m.d.comb += [
] self.pfv.lr.r_mask[2:].eq(Repl(1, 62)),
elif isinstance(self.insn, (BCCTR, BCCTRL)): offset.eq(self.pfv.lr.r_data[2:]),
m.d.comb += [ ]
self.pfv.ctr.r_mask[2:].eq(Repl(1, 62)), elif isinstance(self.insn, (BCCTR, BCCTRL)):
offset.eq(self.pfv.ctr.r_data[2:]), m.d.comb += [
] self.pfv.ctr.r_mask[2:].eq(Repl(1, 62)),
elif isinstance(self.insn, (BCTAR, BCTARL)): offset.eq(self.pfv.ctr.r_data[2:]),
m.d.comb += [ ]
self.pfv.tar.r_mask[2:].eq(Repl(1, 62)), elif isinstance(self.insn, (BCTAR, BCTARL)):
offset.eq(self.pfv.tar.r_data[2:]), m.d.comb += [
] self.pfv.tar.r_mask[2:].eq(Repl(1, 62)),
else: offset.eq(self.pfv.tar.r_data[2:]),
assert False ]
else:
assert False


# target : base + offset<<2 # target : base + offset<<2


m.d.comb += target.eq(base + Cat(Const(0, 2), offset)) m.d.comb += target.eq(base + Cat(Const(0, 2), offset))


# Update NIA # Update NIA


with m.If(taken): with m.If(taken):
m.d.comb += self.pfv.nia.eq(iea(target, self.pfv.msr.r_data.sf)) m.d.comb += self.pfv.nia.eq(iea(target, self.pfv.msr.r_data.sf))
with m.Else(): with m.Else():
m.d.comb += self.pfv.nia.eq(iea(self.pfv.cia + 4, self.pfv.msr.r_data.sf)) m.d.comb += self.pfv.nia.eq(iea(self.pfv.cia + 4, self.pfv.msr.r_data.sf))


# Write the return address to LR if LK=1 # Write the return address to LR if LK=1


if isinstance(self.insn, ( if isinstance(self.insn, (
BL , BLA , BCL , BCLA, BL , BLA , BCL , BCLA,
BCLRL, BCCTRL, BCTARL, BCLRL, BCCTRL, BCTARL,
)): )):
m.d.comb += [ m.d.comb += [
self.pfv.lr.w_mask.eq(Repl(1, 64)), self.pfv.lr.w_mask.eq(Repl(1, 64)),
self.pfv.lr.w_data.eq(iea(self.pfv.cia + 4, self.pfv.msr.r_data.sf)), self.pfv.lr.w_data.eq(iea(self.pfv.cia + 4, self.pfv.msr.r_data.sf)),
] ]


return m return m

@ -3,9 +3,10 @@ from amaranth.utils import log2_int


from power_fv import pfv from power_fv import pfv
from power_fv.insn.const import * from power_fv.insn.const import *
from power_fv.intr import *


from . import InsnSpec from . import InsnSpec
from .utils import iea, byte_reversed from .utils import iea, byte_reversed, msr_to_srr1




__all__ = ["LoadStoreSpec"] __all__ = ["LoadStoreSpec"]
@ -18,250 +19,296 @@ class LoadStoreSpec(InsnSpec, Elaboratable):
m.d.comb += [ m.d.comb += [
self.pfv.stb .eq(1), self.pfv.stb .eq(1),
self.pfv.insn.eq(Cat(Const(0, 32), self.insn.as_value())), 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), self.pfv.msr.r_mask.sf.eq(1),
] ]


# EA (effective address) = ea_base + ea_offset # Raise an interrupt if RA is invalid


ea = Signal(64) illegal_insn = Record([
ea_base = Signal(64) ("ra_zero", 1),
ea_offset = Signal(64) ("ra_rt" , 1),

])
# ea_base : (RA|0) or (RA)

m.d.comb += self.pfv.ra.index.eq(self.insn.RA)


if isinstance(self.insn, ( if isinstance(self.insn, (
LBZ, LBZX, LHZ, LHZX, LHA, LHAX, LWZ, LWZX,
STB, STBX, STH, STHX, STW, STWX,
LWBRX, STHBRX, STWBRX
)):
m.d.comb += [
self.pfv.ra.r_stb.eq(self.insn.RA != 0),
ea_base.eq(Mux(self.insn.RA != 0, self.pfv.ra.r_data, 0)),
]
elif isinstance(self.insn, (
LBZU, LBZUX, LHZU, LHZUX, LHAU, LHAUX, LWZU, LWZUX, LBZU, LBZUX, LHZU, LHZUX, LHAU, LHAUX, LWZU, LWZUX,
STBU, STBUX, STHU, STHUX, STWU, STWUX STBU, STBUX, STHU, STHUX, STWU, STWUX,
)): )):
m.d.comb += [ m.d.comb += illegal_insn.ra_zero.eq(self.insn.RA == 0)
self.pfv.ra.r_stb.eq(1),
ea_base.eq(self.pfv.ra.r_data),
]
else:
assert False

# ea_offset : EXTS(D) or (RB)

if isinstance(self.insn, ( if isinstance(self.insn, (
LBZ, LBZU, LHZ, LHZU, LHA, LHAU, LWZ, LWZU, LBZU, LBZUX, LHZU, LHZUX, LHAU, LHAUX, LWZU, LWZUX,
STB, STBU, STH, STHU, STW, STWU,
)):
m.d.comb += ea_offset.eq(self.insn.D.as_signed())
elif isinstance(self.insn, (
LBZX, LBZUX, LHZX, LHZUX, LHAX, LHAUX, LWZX, LWZUX,
STBX, STBUX, STHX, STHUX, STWX, STWUX,
LWBRX, STHBRX, STWBRX,
)): )):
m.d.comb += [ m.d.comb += illegal_insn.ra_rt.eq(self.insn.RA == self.insn.RT)
self.pfv.rb.index.eq(self.insn.RB),
self.pfv.rb.r_stb.eq(1),
ea_offset.eq(self.pfv.rb.r_data)
]
else:
assert False

m.d.comb += ea.eq(iea(ea_base + ea_offset, self.pfv.msr.r_data.sf))

# If `pfv.mem_aligned` is set, `pfv.mem.addr` points to the dword containing EA.
# If `pfv.mem_aligned` is unset, `pfv.mem.addr` is equal to EA.

byte_offset = Signal(3)
half_offset = Signal(2)
word_offset = Signal(1)


m.d.comb += self.pfv.mem.addr[3:].eq(ea[3:]) with m.If(illegal_insn.any()):
if self.pfv.illegal_insn_heai:
raise NotImplementedError


if self.pfv.mem_aligned:
m.d.comb += [ m.d.comb += [
self.pfv.mem.addr[:3].eq(0), self.pfv.intr.eq(1),
byte_offset.eq(ea[:3]), self.pfv.nia .eq(INTR_PROGRAM.vector_addr),
] INTR_PROGRAM.write_msr(self.pfv.msr),
else:
m.d.comb += [ self.pfv.srr0.w_mask.eq(Repl(1, 64)),
self.pfv.mem.addr[:3].eq(ea[:3]), self.pfv.srr0.w_data.eq(iea(self.pfv.cia, self.pfv.msr.r_data.sf)),
byte_offset.eq(0),
self.pfv.srr1.w_mask[63-36:64-33].eq(Repl(1, 4)),
self.pfv.srr1.w_data[63-36:64-33].eq(0),
self.pfv.srr1.w_mask[63-42].eq(1),
self.pfv.srr1.w_data[63-42].eq(0),
self.pfv.srr1.w_mask[63-46:64-43].eq(Repl(1, 4)),
self.pfv.srr1.w_data[63-46:64-43].eq(0b0100), # Illegal Instruction type (deprecated)
self.pfv.srr1.w_mask[63-47].eq(1),
self.pfv.srr1.w_data[63-47].eq(0),

msr_to_srr1(self.pfv.msr, self.pfv.srr1, 0, 32),
msr_to_srr1(self.pfv.msr, self.pfv.srr1, 37, 41),
msr_to_srr1(self.pfv.msr, self.pfv.srr1, 48, 63),
] ]


m.d.comb += [ with m.Else():
half_offset.eq(byte_offset[1:]), # EA (effective address) = ea_base + ea_offset
word_offset.eq(byte_offset[2:]),
]


msr_le = self.pfv.msr.r_data.le ea = Signal(64)
m.d.comb += self.pfv.msr.r_mask.le.eq(1) ea_base = Signal(64)
ea_offset = Signal(64)


# Load: read from memory, then write the result to RT. # ea_base : (RA|0) or (RA)


if isinstance(self.insn, ( m.d.comb += self.pfv.ra.index.eq(self.insn.RA)
LBZ, LBZX, LBZU, LBZUX,
LHZ, LHZX, LHZU, LHZUX,
LHA, LHAX, LHAU, LHAUX,
LWZ, LWZX, LWZU, LWZUX,
LWBRX,
)):
load_byte = Signal( 8)
load_half = Signal(16)
load_word = Signal(32)
load_result = Signal(64)

m.d.comb += [
load_byte.eq(self.pfv.mem.r_data.word_select(byte_offset, width= 8)),
load_half.eq(self.pfv.mem.r_data.word_select(half_offset, width=16)),
load_word.eq(self.pfv.mem.r_data.word_select(word_offset, width=32)),
]


if isinstance(self.insn, (LBZ, LBZX, LBZU, LBZUX)): if isinstance(self.insn, (
LBZ, LBZX, LHZ, LHZX, LHA, LHAX, LWZ, LWZX,
STB, STBX, STH, STHX, STW, STWX,
LWBRX, STHBRX, STWBRX
)):
m.d.comb += [ m.d.comb += [
self.pfv.mem.r_mask.word_select(byte_offset, width=1).eq(0x1), self.pfv.ra.r_stb.eq(self.insn.RA != 0),
load_result.eq(load_byte.as_unsigned()), ea_base.eq(Mux(self.insn.RA != 0, self.pfv.ra.r_data, 0)),
] ]
elif isinstance(self.insn, (LHZ, LHZX, LHZU, LHZUX)): elif isinstance(self.insn, (
LBZU, LBZUX, LHZU, LHZUX, LHAU, LHAUX, LWZU, LWZUX,
STBU, STBUX, STHU, STHUX, STWU, STWUX
)):
m.d.comb += [ m.d.comb += [
self.pfv.mem.r_mask.word_select(half_offset, width=2).eq(0x3), self.pfv.ra.r_stb.eq(1),
load_result.eq(byte_reversed(load_half, ~msr_le).as_unsigned()), ea_base.eq(self.pfv.ra.r_data),
] ]
elif isinstance(self.insn, (LHA, LHAX, LHAU, LHAUX)): else:
m.d.comb += [ assert False
self.pfv.mem.r_mask.word_select(half_offset, width=2).eq(0x3),
load_result.eq(byte_reversed(load_half, ~msr_le).as_signed()) # ea_offset : EXTS(D) or (RB)
]
elif isinstance(self.insn, (LWZ, LWZX, LWZU, LWZUX)): if isinstance(self.insn, (
m.d.comb += [ LBZ, LBZU, LHZ, LHZU, LHA, LHAU, LWZ, LWZU,
self.pfv.mem.r_mask.word_select(word_offset, width=4).eq(0xf), STB, STBU, STH, STHU, STW, STWU,
load_result.eq(byte_reversed(load_word, ~msr_le).as_unsigned()), )):
] m.d.comb += ea_offset.eq(self.insn.D.as_signed())
elif isinstance(self.insn, LWBRX): elif isinstance(self.insn, (
LBZX, LBZUX, LHZX, LHZUX, LHAX, LHAUX, LWZX, LWZUX,
STBX, STBUX, STHX, STHUX, STWX, STWUX,
LWBRX, STHBRX, STWBRX,
)):
m.d.comb += [ m.d.comb += [
self.pfv.mem.r_mask.word_select(word_offset, width=4).eq(0xf), self.pfv.rb.index.eq(self.insn.RB),
load_result.eq(byte_reversed(load_word, msr_le).as_unsigned()), self.pfv.rb.r_stb.eq(1),
ea_offset.eq(self.pfv.rb.r_data)
] ]
else: else:
assert False assert False


m.d.comb += [ m.d.comb += ea.eq(iea(ea_base + ea_offset, self.pfv.msr.r_data.sf))
self.pfv.rt.index .eq(self.insn.RT),
self.pfv.rt.w_stb .eq(1),
self.pfv.rt.w_data.eq(load_result),
]


# Store: read from RS, then write the result to memory. byte_offset = Signal(3)
half_offset = Signal(2)
word_offset = Signal(1)


elif isinstance(self.insn, ( # If `pfv.mem_aligned` is set, `pfv.mem.addr` points to the dword containing EA.
STB, STBX, STBU, STBUX, # If `pfv.mem_aligned` is unset, `pfv.mem.addr` is equal to EA.
STH, STHX, STHU, STHUX,
STW, STWX, STWU, STWUX,
STHBRX, STWBRX,
)):
store_byte = Signal(64)
store_half = Signal(64)
store_word = Signal(64)


m.d.comb += [ m.d.comb += self.pfv.mem.addr[3:].eq(ea[3:])
self.pfv.rs.index.eq(self.insn.RS),
self.pfv.rs.r_stb.eq(1),


store_byte.eq(Repl(self.pfv.rs.r_data[: 8], count=8)), if self.pfv.mem_aligned:
store_half.eq(Repl(self.pfv.rs.r_data[:16], count=4)),
store_word.eq(Repl(self.pfv.rs.r_data[:32], count=2)),
]

if isinstance(self.insn, (STB, STBX, STBU, STBUX)):
m.d.comb += [
self.pfv.mem.w_mask.word_select(byte_offset, width=1).eq(0x1),
self.pfv.mem.w_data.eq(store_byte),
]
elif isinstance(self.insn, (STH, STHX, STHU, STHUX)):
m.d.comb += [
self.pfv.mem.w_mask.word_select(half_offset, width=2).eq(0x3),
self.pfv.mem.w_data.eq(byte_reversed(store_half, ~msr_le)),
]
elif isinstance(self.insn, (STW, STWX, STWU, STWUX)):
m.d.comb += [
self.pfv.mem.w_mask.word_select(word_offset, width=4).eq(0xf),
self.pfv.mem.w_data.eq(byte_reversed(store_word, ~msr_le)),
]
elif isinstance(self.insn, STHBRX):
m.d.comb += [ m.d.comb += [
self.pfv.mem.w_mask.word_select(half_offset, width=2).eq(0x3), self.pfv.mem.addr[:3].eq(0),
self.pfv.mem.w_data.eq(byte_reversed(store_half, msr_le)), byte_offset.eq(ea[:3]),
] ]
elif isinstance(self.insn, STWBRX): else:
m.d.comb += [ m.d.comb += [
self.pfv.mem.w_mask.word_select(word_offset, width=4).eq(0xf), self.pfv.mem.addr[:3].eq(ea[:3]),
self.pfv.mem.w_data.eq(byte_reversed(store_word, msr_le)), byte_offset.eq(0),
] ]
else:
assert False

else:
assert False


# Load/store with update: write EA to RA.

if isinstance(self.insn, (
LBZU, LBZUX, LHZU, LHZUX, LHAU, LHAUX, LWZU, LWZUX,
STBU, STBUX, STHU, STHUX, STWU, STWUX,
)):
m.d.comb += [ m.d.comb += [
self.pfv.ra.w_stb .eq(1), half_offset.eq(byte_offset[1:]),
self.pfv.ra.w_data.eq(ea), word_offset.eq(byte_offset[2:]),
] ]


# Interrupt causes # Raise an Alignment Interrupt if EA is misaligned wrt. `pfv.mem`

ea_misaligned = Signal()

if isinstance(self.insn, (
LBZ, LBZX, LBZU, LBZUX,
STB, STBX, STBU, STBUX,
)):
m.d.comb += ea_misaligned.eq(0)
elif isinstance(self.insn, (
LHZ, LHZX, LHZU, LHZUX, LHA, LHAX, LHAU, LHAUX,
STH, STHX, STHU, STHUX,
STHBRX,
)):
m.d.comb += ea_misaligned.eq(byte_offset[0])
elif isinstance(self.insn, (
LWZ, LWZX, LWZU, LWZUX,
STW, STWX, STWU, STWUX,
LWBRX, STWBRX,
)):
m.d.comb += ea_misaligned.eq(byte_offset[:1].any())
else:
assert False


intr = Record([ with m.If(ea_misaligned):
("misaligned", 1), m.d.comb += [
("update_zero", 1), self.pfv.intr.eq(1),
("update_rt", 1), self.pfv.nia .eq(INTR_ALIGNMENT.vector_addr),
]) INTR_ALIGNMENT.write_msr(self.pfv.msr),


if isinstance(self.insn, ( self.pfv.srr0.w_mask.eq(Repl(1, 64)),
LBZ, LBZX, LBZU, LBZUX, self.pfv.srr0.w_data.eq(iea(self.pfv.cia, self.pfv.msr.r_data.sf)),
STB, STBX, STBU, STBUX,
)):
m.d.comb += intr.misaligned.eq(0)
elif isinstance(self.insn, (
LHZ, LHZX, LHZU, LHZUX, LHA, LHAX, LHAU, LHAUX,
STH, STHX, STHU, STHUX,
STHBRX,
)):
m.d.comb += intr.misaligned.eq(byte_offset[0])
elif isinstance(self.insn, (
LWZ, LWZX, LWZU, LWZUX,
STW, STWX, STWU, STWUX,
LWBRX, STWBRX,
)):
m.d.comb += intr.misaligned.eq(byte_offset[:1].any())
else:
assert False


if isinstance(self.insn, ( self.pfv.srr1.w_mask[63-36:64-33].eq(Repl(1, 4)),
LBZU, LBZUX, LHZU, LHZUX, LHAU, LHAUX, LWZU, LWZUX, self.pfv.srr1.w_mask[63-36:64-33].eq(0),
STBU, STBUX, STHU, STHUX, STWU, STWUX, self.pfv.srr1.w_mask[63-47:64-42].eq(Repl(1, 6)),
)): self.pfv.srr1.w_mask[63-47:64-42].eq(0),
m.d.comb += intr.update_zero.eq(self.insn.RA == 0)
else:
m.d.comb += intr.update_zero.eq(0)


if isinstance(self.insn, ( msr_to_srr1(self.pfv.msr, self.pfv.srr1, 0, 32),
LBZU, LBZUX, LHZU, LHZUX, LHAU, LHAUX, LWZU, LWZUX, msr_to_srr1(self.pfv.msr, self.pfv.srr1, 37, 41),
)): msr_to_srr1(self.pfv.msr, self.pfv.srr1, 48, 63),
m.d.comb += intr.update_rt.eq(self.insn.RA == self.insn.RT) ]
else:
m.d.comb += intr.update_rt.eq(0)


m.d.comb += self.pfv.intr.eq(intr.any()) with m.Else():
m.d.comb += self.pfv.msr.r_mask.le.eq(1)
msr_le = self.pfv.msr.r_data.le

# Load: read from memory, then write the result to RT.

if isinstance(self.insn, (
LBZ, LBZX, LBZU, LBZUX,
LHZ, LHZX, LHZU, LHZUX,
LHA, LHAX, LHAU, LHAUX,
LWZ, LWZX, LWZU, LWZUX,
LWBRX,
)):
load_byte = Signal( 8)
load_half = Signal(16)
load_word = Signal(32)
load_result = Signal(64)

m.d.comb += [
load_byte.eq(self.pfv.mem.r_data.word_select(byte_offset, width= 8)),
load_half.eq(self.pfv.mem.r_data.word_select(half_offset, width=16)),
load_word.eq(self.pfv.mem.r_data.word_select(word_offset, width=32)),
]

if isinstance(self.insn, (LBZ, LBZX, LBZU, LBZUX)):
m.d.comb += [
self.pfv.mem.r_mask.word_select(byte_offset, width=1).eq(0x1),
load_result.eq(load_byte.as_unsigned()),
]
elif isinstance(self.insn, (LHZ, LHZX, LHZU, LHZUX)):
m.d.comb += [
self.pfv.mem.r_mask.word_select(half_offset, width=2).eq(0x3),
load_result.eq(byte_reversed(load_half, ~msr_le).as_unsigned()),
]
elif isinstance(self.insn, (LHA, LHAX, LHAU, LHAUX)):
m.d.comb += [
self.pfv.mem.r_mask.word_select(half_offset, width=2).eq(0x3),
load_result.eq(byte_reversed(load_half, ~msr_le).as_signed())
]
elif isinstance(self.insn, (LWZ, LWZX, LWZU, LWZUX)):
m.d.comb += [
self.pfv.mem.r_mask.word_select(word_offset, width=4).eq(0xf),
load_result.eq(byte_reversed(load_word, ~msr_le).as_unsigned()),
]
elif isinstance(self.insn, LWBRX):
m.d.comb += [
self.pfv.mem.r_mask.word_select(word_offset, width=4).eq(0xf),
load_result.eq(byte_reversed(load_word, msr_le).as_unsigned()),
]
else:
assert False

m.d.comb += [
self.pfv.rt.index .eq(self.insn.RT),
self.pfv.rt.w_stb .eq(1),
self.pfv.rt.w_data.eq(load_result),
]

# Store: read from RS, then write the result to memory.

elif isinstance(self.insn, (
STB, STBX, STBU, STBUX,
STH, STHX, STHU, STHUX,
STW, STWX, STWU, STWUX,
STHBRX, STWBRX,
)):
store_byte = Signal(64)
store_half = Signal(64)
store_word = Signal(64)

m.d.comb += [
self.pfv.rs.index.eq(self.insn.RS),
self.pfv.rs.r_stb.eq(1),

store_byte.eq(Repl(self.pfv.rs.r_data[: 8], count=8)),
store_half.eq(Repl(self.pfv.rs.r_data[:16], count=4)),
store_word.eq(Repl(self.pfv.rs.r_data[:32], count=2)),
]

if isinstance(self.insn, (STB, STBX, STBU, STBUX)):
m.d.comb += [
self.pfv.mem.w_mask.word_select(byte_offset, width=1).eq(0x1),
self.pfv.mem.w_data.eq(store_byte),
]
elif isinstance(self.insn, (STH, STHX, STHU, STHUX)):
m.d.comb += [
self.pfv.mem.w_mask.word_select(half_offset, width=2).eq(0x3),
self.pfv.mem.w_data.eq(byte_reversed(store_half, ~msr_le)),
]
elif isinstance(self.insn, (STW, STWX, STWU, STWUX)):
m.d.comb += [
self.pfv.mem.w_mask.word_select(word_offset, width=4).eq(0xf),
self.pfv.mem.w_data.eq(byte_reversed(store_word, ~msr_le)),
]
elif isinstance(self.insn, STHBRX):
m.d.comb += [
self.pfv.mem.w_mask.word_select(half_offset, width=2).eq(0x3),
self.pfv.mem.w_data.eq(byte_reversed(store_half, msr_le)),
]
elif isinstance(self.insn, STWBRX):
m.d.comb += [
self.pfv.mem.w_mask.word_select(word_offset, width=4).eq(0xf),
self.pfv.mem.w_data.eq(byte_reversed(store_word, msr_le)),
]
else:
assert False

else:
assert False

# Load/store with update: write EA to RA.

if isinstance(self.insn, (
LBZU, LBZUX, LHZU, LHZUX, LHAU, LHAUX, LWZU, LWZUX,
STBU, STBUX, STHU, STHUX, STWU, STWUX,
)):
m.d.comb += [
self.pfv.ra.w_stb .eq(1),
self.pfv.ra.w_data.eq(ea),
]

# Update NIA

m.d.comb += self.pfv.nia.eq(iea(self.pfv.cia + 4, self.pfv.msr.r_data.sf))


return m return m

@ -2,10 +2,11 @@ from amaranth import *


from power_fv import pfv from power_fv import pfv
from power_fv.insn.const import * from power_fv.insn.const import *
from power_fv.intr import *
from power_fv.reg import msr_layout from power_fv.reg import msr_layout


from . import InsnSpec from . import InsnSpec
from .utils import iea from .utils import iea, msr_to_srr1




__all__ = ["MSRMoveSpec"] __all__ = ["MSRMoveSpec"]
@ -18,92 +19,118 @@ class MSRMoveSpec(InsnSpec, Elaboratable):
m.d.comb += [ m.d.comb += [
self.pfv.stb .eq(1), self.pfv.stb .eq(1),
self.pfv.insn.eq(Cat(Const(0, 32), self.insn.as_value())), 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), self.pfv.msr.r_mask.sf.eq(1),

self.pfv.msr.r_mask.pr.eq(1)
# mtmsr/mfmsr are privileged
self.pfv.intr.eq(self.pfv.msr.r_data.pr),
self.pfv.msr.r_mask.pr.eq(1),
] ]


rs_as_msr = Record(msr_layout) # Raise a Program Interrupt if executing from Problem State
ultravisor = Signal()


if isinstance(self.insn, MTMSR): with m.If(self.pfv.msr.r_data.pr):
m.d.comb += [ m.d.comb += [
self.pfv.rs.index .eq(self.insn.RS), self.pfv.intr.eq(1),
self.pfv.rs.r_stb .eq(1), self.pfv.nia .eq(INTR_PROGRAM.vector_addr),

INTR_PROGRAM.write_msr(self.pfv.msr),
self.pfv.msr.r_mask.s .eq(1),
self.pfv.msr.r_mask.hv.eq(1), self.pfv.srr0.w_mask.eq(Repl(1, 64)),

self.pfv.srr0.w_data.eq(iea(self.pfv.cia, self.pfv.msr.r_data.sf)),
rs_as_msr .eq(self.pfv.rs.r_data),
ultravisor.eq(self.pfv.msr.r_data.s & self.pfv.msr.r_data.hv & ~rs_as_msr.pr), self.pfv.srr1.w_mask[63-36:64-33].eq(Repl(1, 4)),
self.pfv.srr1.w_data[63-36:64-33].eq(0),
self.pfv.srr1.w_mask[63-42].eq(1),
self.pfv.srr1.w_data[63-42].eq(0),
self.pfv.srr1.w_mask[63-46:64-43].eq(Repl(1, 4)),
self.pfv.srr1.w_data[63-46:64-43].eq(0b0010), # Privileged Instruction type
self.pfv.srr1.w_mask[63-47].eq(1),
self.pfv.srr1.w_data[63-47].eq(0),

msr_to_srr1(self.pfv.msr, self.pfv.srr1, 0, 32),
msr_to_srr1(self.pfv.msr, self.pfv.srr1, 37, 41),
msr_to_srr1(self.pfv.msr, self.pfv.srr1, 48, 63),
] ]


with m.If(self.insn.L): with m.Else():
# Write bits 48 62 rs_as_msr = Record(msr_layout)
ultravisor = Signal()

if isinstance(self.insn, MTMSR):
m.d.comb += [ m.d.comb += [
self.pfv.msr.w_mask.ee.eq(1), self.pfv.rs.index .eq(self.insn.RS),
self.pfv.msr.w_data.ee.eq(rs_as_msr.ee), self.pfv.rs.r_stb .eq(1),
self.pfv.msr.w_mask.ri.eq(1),
self.pfv.msr.w_data.ri.eq(rs_as_msr.ri), self.pfv.msr.r_mask.s .eq(1),
self.pfv.msr.r_mask.hv.eq(1),

rs_as_msr .eq(self.pfv.rs.r_data),
ultravisor.eq(self.pfv.msr.r_data.s & self.pfv.msr.r_data.hv & ~rs_as_msr.pr),
] ]
with m.Else():
# Write bits: with m.If(self.insn.L):
# Write bits 48 62
m.d.comb += [
self.pfv.msr.w_mask.ee.eq(1),
self.pfv.msr.w_data.ee.eq(rs_as_msr.ee),
self.pfv.msr.w_mask.ri.eq(1),
self.pfv.msr.w_data.ri.eq(rs_as_msr.ri),
]
with m.Else():
# Write bits:
m.d.comb += [
# 48 58 59
self.pfv.msr.w_mask.ee .eq(1),
self.pfv.msr.w_data.ee .eq(rs_as_msr.ee | rs_as_msr.pr),
self.pfv.msr.w_mask.ir .eq(1),
self.pfv.msr.w_data.ir .eq((rs_as_msr.ir | rs_as_msr.pr) & ~ultravisor),
self.pfv.msr.w_mask.dr .eq(1),
self.pfv.msr.w_data.dr .eq((rs_as_msr.dr | rs_as_msr.pr) & ~ultravisor),
# 32:40
self.pfv.msr.w_mask._32.eq(Repl(1, 6)),
self.pfv.msr.w_data._32.eq(rs_as_msr._32),
self.pfv.msr.w_mask.vec.eq(1),
self.pfv.msr.w_data.vec.eq(rs_as_msr.vec),
self.pfv.msr.w_mask._39.eq(1),
self.pfv.msr.w_data._39.eq(rs_as_msr._39),
self.pfv.msr.w_mask.vsx.eq(1),
self.pfv.msr.w_data.vsx.eq(rs_as_msr.vsx),
# 42:47
self.pfv.msr.w_mask._42.eq(Repl(1, 6)),
self.pfv.msr.w_data._42.eq(rs_as_msr._42),
# 49:50
self.pfv.msr.w_mask.pr .eq(1),
self.pfv.msr.w_data.pr .eq(rs_as_msr.pr),
self.pfv.msr.w_mask.fp .eq(1),
self.pfv.msr.w_data.fp .eq(rs_as_msr.fp),
# 52:57
self.pfv.msr.w_mask.fe0.eq(1),
self.pfv.msr.w_data.fe0.eq(rs_as_msr.fe0),
self.pfv.msr.w_mask.te .eq(Repl(1, 2)),
self.pfv.msr.w_data.te .eq(rs_as_msr.te),
self.pfv.msr.w_mask.fe1.eq(1),
self.pfv.msr.w_data.fe1.eq(rs_as_msr.fe1),
self.pfv.msr.w_mask._56.eq(Repl(1, 2)),
self.pfv.msr.w_data._56.eq(rs_as_msr._56),
# 60:62
self.pfv.msr.w_mask._60.eq(1),
self.pfv.msr.w_data._60.eq(rs_as_msr._60),
self.pfv.msr.w_mask.pmm.eq(1),
self.pfv.msr.w_data.pmm.eq(rs_as_msr.pmm),
self.pfv.msr.w_mask.ri .eq(1),
self.pfv.msr.w_data.ri .eq(rs_as_msr.ri),
]

elif isinstance(self.insn, MFMSR):
m.d.comb += [ m.d.comb += [
# 48 58 59 self.pfv.msr.r_mask.eq(Repl(1, 64)),
self.pfv.msr.w_mask.ee .eq(1),
self.pfv.msr.w_data.ee .eq(rs_as_msr.ee | rs_as_msr.pr), self.pfv.rt.index .eq(self.insn.RT),
self.pfv.msr.w_mask.ir .eq(1), self.pfv.rt.w_stb .eq(1),
self.pfv.msr.w_data.ir .eq((rs_as_msr.ir | rs_as_msr.pr) & ~ultravisor), self.pfv.rt.w_data.eq(self.pfv.msr.r_data),
self.pfv.msr.w_mask.dr .eq(1),
self.pfv.msr.w_data.dr .eq((rs_as_msr.dr | rs_as_msr.pr) & ~ultravisor),
# 32:40
self.pfv.msr.w_mask._32.eq(Repl(1, 6)),
self.pfv.msr.w_data._32.eq(rs_as_msr._32),
self.pfv.msr.w_mask.vec.eq(1),
self.pfv.msr.w_data.vec.eq(rs_as_msr.vec),
self.pfv.msr.w_mask._39.eq(1),
self.pfv.msr.w_data._39.eq(rs_as_msr._39),
self.pfv.msr.w_mask.vsx.eq(1),
self.pfv.msr.w_data.vsx.eq(rs_as_msr.vsx),
# 42:47
self.pfv.msr.w_mask._42.eq(Repl(1, 6)),
self.pfv.msr.w_data._42.eq(rs_as_msr._42),
# 49:50
self.pfv.msr.w_mask.pr .eq(1),
self.pfv.msr.w_data.pr .eq(rs_as_msr.pr),
self.pfv.msr.w_mask.fp .eq(1),
self.pfv.msr.w_data.fp .eq(rs_as_msr.fp),
# 52:57
self.pfv.msr.w_mask.fe0.eq(1),
self.pfv.msr.w_data.fe0.eq(rs_as_msr.fe0),
self.pfv.msr.w_mask.te .eq(Repl(1, 2)),
self.pfv.msr.w_data.te .eq(rs_as_msr.te),
self.pfv.msr.w_mask.fe1.eq(1),
self.pfv.msr.w_data.fe1.eq(rs_as_msr.fe1),
self.pfv.msr.w_mask._56.eq(Repl(1, 2)),
self.pfv.msr.w_data._56.eq(rs_as_msr._56),
# 60:62
self.pfv.msr.w_mask._60.eq(1),
self.pfv.msr.w_data._60.eq(rs_as_msr._60),
self.pfv.msr.w_mask.pmm.eq(1),
self.pfv.msr.w_data.pmm.eq(rs_as_msr.pmm),
self.pfv.msr.w_mask.ri .eq(1),
self.pfv.msr.w_data.ri .eq(rs_as_msr.ri),
] ]


elif isinstance(self.insn, MFMSR): else:
m.d.comb += [ assert False
self.pfv.msr.r_mask.eq(Repl(1, 64)),


self.pfv.rt.index .eq(self.insn.RT), # Update NIA
self.pfv.rt.w_stb .eq(1),
self.pfv.rt.w_data.eq(self.pfv.msr.r_data),
]


else: m.d.comb += self.pfv.nia.eq(iea(self.pfv.cia + 4, self.pfv.msr.r_data.sf))
assert False


return m return m

@ -2,9 +2,10 @@ from amaranth import *


from power_fv import pfv from power_fv import pfv
from power_fv.insn.const import * from power_fv.insn.const import *
from power_fv.intr import *


from . import InsnSpec from . import InsnSpec
from .utils import iea from .utils import iea, msr_to_srr1




__all__ = ["RotateShiftSpec"] __all__ = ["RotateShiftSpec"]
@ -17,136 +18,161 @@ class RotateShiftSpec(InsnSpec, Elaboratable):
m.d.comb += [ m.d.comb += [
self.pfv.stb .eq(1), self.pfv.stb .eq(1),
self.pfv.insn.eq(Cat(Const(0, 32), self.insn.as_value())), 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), self.pfv.msr.r_mask.sf.eq(1),
] ]


src = Signal(unsigned(64)) # Raise an interrupt if MB or ME are invalid
shamt = Signal(unsigned( 6))
rotl = Signal(unsigned(64))
mask = Signal(unsigned(64))
result = Signal(unsigned(64))


# Source operand : (RS)(32:63)||(RS)(32:63) illegal_insn = Record([
("mask", 1),
])


m.d.comb += [ if isinstance(self.insn, (RLWINM, RLWINM_, RLWNM, RLWNM_, RLWIMI, RLWIMI_)):
self.pfv.rs.index.eq(self.insn.RS), m.d.comb += illegal_insn.mask.eq((self.insn.MB >= 32) | (self.insn.ME >= 32))
self.pfv.rs.r_stb.eq(1),
src.eq(self.pfv.rs.r_data),
]


# Shift amount : SH or (RB)(59:63) with m.If(illegal_insn.any()):
if self.pfv.illegal_insn_heai:
raise NotImplementedError


if isinstance(self.insn, (RLWINM, RLWINM_, RLWIMI, RLWIMI_, SRAWI, SRAWI_)):
m.d.comb += shamt.eq(self.insn.SH)
elif isinstance(self.insn, (RLWNM, RLWNM_, SLW, SLW_, SRW, SRW_, SRAW, SRAW_)):
m.d.comb += [ m.d.comb += [
self.pfv.rb.index.eq(self.insn.RB), self.pfv.intr.eq(1),
self.pfv.rb.r_stb.eq(1), self.pfv.nia .eq(INTR_PROGRAM.vector_addr),
shamt.eq(self.pfv.rb.r_data[:6]), INTR_PROGRAM.write_msr(self.pfv.msr),

self.pfv.srr0.w_mask.eq(Repl(1, 64)),
self.pfv.srr0.w_data.eq(iea(self.pfv.cia, self.pfv.msr.r_data.sf)),

self.pfv.srr1.w_mask[63-36:64-33].eq(Repl(1, 4)),
self.pfv.srr1.w_data[63-36:64-33].eq(0),
self.pfv.srr1.w_mask[63-42].eq(1),
self.pfv.srr1.w_data[63-42].eq(0),
self.pfv.srr1.w_mask[63-46:64-43].eq(Repl(1, 4)),
self.pfv.srr1.w_data[63-46:64-43].eq(0b0100), # Illegal Instruction type (deprecated)
self.pfv.srr1.w_mask[63-47].eq(1),
self.pfv.srr1.w_data[63-47].eq(0),

msr_to_srr1(self.pfv.msr, self.pfv.srr1, 0, 32),
msr_to_srr1(self.pfv.msr, self.pfv.srr1, 37, 41),
msr_to_srr1(self.pfv.msr, self.pfv.srr1, 48, 63),
] ]
else:
assert False


# Mask with m.Else():
src = Signal(unsigned(64))
shamt = Signal(unsigned( 6))
rotl = Signal(unsigned(64))
mask = Signal(unsigned(64))
result = Signal(unsigned(64))


def _mask(mstart, mstop): # Source operand : (RS)(32:63)||(RS)(32:63)
mask = ((1 << 64-mstart) - 1) & ~((1 << 63-mstop ) - 1)
mask_inv = ~((1 << 63-mstop ) - 1) | ((1 << 64-mstart) - 1)
return Mux(mstart <= mstop, mask, mask_inv)


if isinstance(self.insn, (RLWINM, RLWINM_, RLWNM, RLWNM_, RLWIMI, RLWIMI_)): m.d.comb += [
m.d.comb += mask.eq(_mask(self.insn.MB+32, self.insn.ME+32)) self.pfv.rs.index.eq(self.insn.RS),
elif isinstance(self.insn, (SLW, SLW_)): self.pfv.rs.r_stb.eq(1),
m.d.comb += mask.eq(Mux(shamt[5], 0, _mask(32, 63-shamt))) src.eq(self.pfv.rs.r_data),
elif isinstance(self.insn, (SRW, SRW_, SRAW, SRAW_)): ]
m.d.comb += mask.eq(Mux(shamt[5], 0, _mask(shamt+32, 63)))
elif isinstance(self.insn, (SRAWI, SRAWI_)):
m.d.comb += mask.eq(_mask(shamt+32, 63))
else:
assert False

# Rotation

def _rotl32(src, n):
v = Repl(src[:32], 2)
return ((v << n) | (v >> 64-n)) & Repl(1, 64)

if isinstance(self.insn, (
RLWINM, RLWINM_, RLWNM, RLWNM_, RLWIMI, RLWIMI_,
SLW, SLW_,
)):
m.d.comb += rotl.eq(_rotl32(src, shamt))
elif isinstance(self.insn, (SRW, SRW_, SRAWI, SRAWI_, SRAW, SRAW_)):
m.d.comb += rotl.eq(_rotl32(src, 64-shamt))
else:
assert False

# Write result to RA

m.d.comb += [
self.pfv.ra.index .eq(self.insn.RA),
self.pfv.ra.w_stb .eq(1),
self.pfv.ra.w_data.eq(result),
]


if isinstance(self.insn, (RLWINM, RLWINM_, RLWNM, RLWNM_, SLW, SLW_, SRW, SRW_)): # Shift amount : SH or (RB)(59:63)
m.d.comb += result.eq(rotl & mask)
elif isinstance(self.insn, (RLWIMI, RLWIMI_)): if isinstance(self.insn, (RLWINM, RLWINM_, RLWIMI, RLWIMI_, SRAWI, SRAWI_)):
m.d.comb += self.pfv.ra.r_stb.eq(1) m.d.comb += shamt.eq(self.insn.SH)
m.d.comb += result.eq(rotl & mask | self.pfv.ra.r_data & ~mask) elif isinstance(self.insn, (RLWNM, RLWNM_, SLW, SLW_, SRW, SRW_, SRAW, SRAW_)):
elif isinstance(self.insn, (SRAWI, SRAWI_, SRAW, SRAW_)): m.d.comb += [
m.d.comb += result.eq(rotl & mask | Repl(src[31], 64) & ~mask) self.pfv.rb.index.eq(self.insn.RB),
else: self.pfv.rb.r_stb.eq(1),
assert False shamt.eq(self.pfv.rb.r_data[:6]),
]
else:
assert False

# Mask

def _mask(mstart, mstop):
mask = ((1 << 64-mstart) - 1) & ~((1 << 63-mstop ) - 1)
mask_inv = ~((1 << 63-mstop ) - 1) | ((1 << 64-mstart) - 1)
return Mux(mstart <= mstop, mask, mask_inv)

if isinstance(self.insn, (RLWINM, RLWINM_, RLWNM, RLWNM_, RLWIMI, RLWIMI_)):
m.d.comb += mask.eq(_mask(self.insn.MB+32, self.insn.ME+32))
elif isinstance(self.insn, (SLW, SLW_)):
m.d.comb += mask.eq(Mux(shamt[5], 0, _mask(32, 63-shamt)))
elif isinstance(self.insn, (SRW, SRW_, SRAW, SRAW_)):
m.d.comb += mask.eq(Mux(shamt[5], 0, _mask(shamt+32, 63)))
elif isinstance(self.insn, (SRAWI, SRAWI_)):
m.d.comb += mask.eq(_mask(shamt+32, 63))
else:
assert False

# Rotation

def _rotl32(src, n):
v = Repl(src[:32], 2)
return ((v << n) | (v >> 64-n)) & Repl(1, 64)

if isinstance(self.insn, (
RLWINM, RLWINM_, RLWNM, RLWNM_, RLWIMI, RLWIMI_,
SLW, SLW_,
)):
m.d.comb += rotl.eq(_rotl32(src, shamt))
elif isinstance(self.insn, (SRW, SRW_, SRAWI, SRAWI_, SRAW, SRAW_)):
m.d.comb += rotl.eq(_rotl32(src, 64-shamt))
else:
assert False

# Write result to RA


# Write CR0 m.d.comb += [
self.pfv.ra.index .eq(self.insn.RA),
self.pfv.ra.w_stb .eq(1),
self.pfv.ra.w_data.eq(result),
]


if isinstance(self.insn, ( if isinstance(self.insn, (RLWINM, RLWINM_, RLWNM, RLWNM_, SLW, SLW_, SRW, SRW_)):
RLWINM_, RLWNM_, RLWIMI_, SLW_, SRW_, SRAWI_, SRAW_, m.d.comb += result.eq(rotl & mask)
)): elif isinstance(self.insn, (RLWIMI, RLWIMI_)):
cr0_w_mask = Record([("so", 1), ("eq_", 1), ("gt", 1), ("lt", 1)]) m.d.comb += self.pfv.ra.r_stb.eq(1)
cr0_w_data = Record([("so", 1), ("eq_", 1), ("gt", 1), ("lt", 1)]) m.d.comb += result.eq(rotl & mask | self.pfv.ra.r_data & ~mask)
elif isinstance(self.insn, (SRAWI, SRAWI_, SRAW, SRAW_)):
m.d.comb += result.eq(rotl & mask | Repl(src[31], 64) & ~mask)
else:
assert False


m.d.comb += [ # Write CR0
self.pfv.xer.r_mask.so.eq(1),


cr0_w_mask .eq(0b1111), if isinstance(self.insn, (
cr0_w_data.so .eq(self.pfv.xer.r_data.so), RLWINM_, RLWNM_, RLWIMI_, SLW_, SRW_, SRAWI_, SRAW_,
cr0_w_data.eq_.eq(~Mux(self.pfv.msr.r_data.sf, result[:64].any(), result[:32].any())), )):
cr0_w_data.gt .eq(~(cr0_w_data.lt | cr0_w_data.eq_)), cr0_w_mask = Record([("so", 1), ("eq_", 1), ("gt", 1), ("lt", 1)])
cr0_w_data.lt .eq(Mux(self.pfv.msr.r_data.sf, result[63], result[31])), cr0_w_data = Record([("so", 1), ("eq_", 1), ("gt", 1), ("lt", 1)])


self.pfv.cr.w_mask.cr0.eq(cr0_w_mask), m.d.comb += [
self.pfv.cr.w_data.cr0.eq(cr0_w_data), self.pfv.xer.r_mask.so.eq(1),
]


# Write XER cr0_w_mask .eq(0b1111),
cr0_w_data.so .eq(self.pfv.xer.r_data.so),
cr0_w_data.eq_.eq(~Mux(self.pfv.msr.r_data.sf, result[:64].any(), result[:32].any())),
cr0_w_data.gt .eq(~(cr0_w_data.lt | cr0_w_data.eq_)),
cr0_w_data.lt .eq(Mux(self.pfv.msr.r_data.sf, result[63], result[31])),


if isinstance(self.insn, (SRAWI, SRAWI_, SRAW, SRAW_)): self.pfv.cr.w_mask.cr0.eq(cr0_w_mask),
carry = Signal() self.pfv.cr.w_data.cr0.eq(cr0_w_data),
]


m.d.comb += [ # Write XER
carry.eq(src[31] & (rotl & ~mask)[:32].any()),


self.pfv.xer.w_mask.ca .eq(1), if isinstance(self.insn, (SRAWI, SRAWI_, SRAW, SRAW_)):
self.pfv.xer.w_data.ca .eq(carry), carry = Signal()
self.pfv.xer.w_mask.ca32.eq(1),
self.pfv.xer.w_data.ca32.eq(carry),
]


# Interrupt causes m.d.comb += [
carry.eq(src[31] & (rotl & ~mask)[:32].any()),


intr = Record([ self.pfv.xer.w_mask.ca .eq(1),
("rotl32_mask", 1), self.pfv.xer.w_data.ca .eq(carry),
]) self.pfv.xer.w_mask.ca32.eq(1),
self.pfv.xer.w_data.ca32.eq(carry),
]


if isinstance(self.insn, (RLWINM, RLWINM_, RLWNM, RLWNM_, RLWIMI, RLWIMI_)): # Update NIA
m.d.comb += intr.rotl32_mask.eq((self.insn.MB >= 32) | (self.insn.ME >= 32))
else:
m.d.comb += intr.rotl32_mask.eq(0)


m.d.comb += self.pfv.intr.eq(intr.any()) m.d.comb += self.pfv.nia.eq(iea(self.pfv.cia + 4, self.pfv.msr.r_data.sf))


return m return m

@ -2,10 +2,11 @@ from amaranth import *


from power_fv import pfv from power_fv import pfv
from power_fv.insn.const import * from power_fv.insn.const import *
from power_fv.intr import *
from power_fv.reg import xer_layout from power_fv.reg import xer_layout


from . import InsnSpec from . import InsnSpec
from .utils import iea from .utils import iea, msr_to_srr1




__all__ = ["SPRMoveSpec"] __all__ = ["SPRMoveSpec"]
@ -18,12 +19,11 @@ class SPRMoveSpec(InsnSpec, Elaboratable):
m.d.comb += [ m.d.comb += [
self.pfv.stb .eq(1), self.pfv.stb .eq(1),
self.pfv.insn.eq(Cat(Const(0, 32), self.insn.as_value())), 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), self.pfv.msr.r_mask.sf.eq(1),
self.pfv.msr.r_mask.pr.eq(1), self.pfv.msr.r_mask.pr.eq(1),
] ]


# If SPR(0) = 1, this instruction is privileged. # If SPR(0)=1, raise a Program Interrupt if executing from Problem State


spr_privileged = Signal() spr_privileged = Signal()
spr_access_err = Signal() spr_access_err = Signal()
@ -31,62 +31,89 @@ class SPRMoveSpec(InsnSpec, Elaboratable):
m.d.comb += [ m.d.comb += [
spr_privileged.eq(self.insn.SPR[9 - 0]), spr_privileged.eq(self.insn.SPR[9 - 0]),
spr_access_err.eq(spr_privileged & self.pfv.msr.r_data.pr), spr_access_err.eq(spr_privileged & self.pfv.msr.r_data.pr),
self.pfv.intr.eq(spr_access_err),
] ]


def mXspr_spec(pfv_spr, mtspr_cls, mfspr_cls, reserved_mask): with m.If(spr_access_err):
if isinstance(self.insn, mtspr_cls): m.d.comb += [
# Copy (RS) to SPR. self.pfv.intr.eq(1),
m.d.comb += [ self.pfv.nia .eq(INTR_PROGRAM.vector_addr),
self.pfv.rs.index.eq(self.insn.RS), INTR_PROGRAM.write_msr(self.pfv.msr),
self.pfv.rs.r_stb.eq(1),
pfv_spr.w_mask.eq(~reserved_mask), self.pfv.srr0.w_mask.eq(Repl(1, 64)),
pfv_spr.w_data.eq(self.pfv.rs.r_data & ~reserved_mask), self.pfv.srr0.w_data.eq(iea(self.pfv.cia, self.pfv.msr.r_data.sf)),
]
self.pfv.srr1.w_mask[63-36:64-33].eq(Repl(1, 4)),
self.pfv.srr1.w_data[63-36:64-33].eq(0),
self.pfv.srr1.w_mask[63-42].eq(1),
self.pfv.srr1.w_data[63-42].eq(0),
self.pfv.srr1.w_mask[63-46:64-43].eq(Repl(1, 4)),
self.pfv.srr1.w_data[63-46:64-43].eq(0b0010), # Privileged Instruction type
self.pfv.srr1.w_mask[63-47].eq(1),
self.pfv.srr1.w_data[63-47].eq(0),

msr_to_srr1(self.pfv.msr, self.pfv.srr1, 0, 32),
msr_to_srr1(self.pfv.msr, self.pfv.srr1, 37, 41),
msr_to_srr1(self.pfv.msr, self.pfv.srr1, 48, 63),
]


if isinstance(self.insn, mfspr_cls): with m.Else():
# Copy SPR to (RT). def mXspr_spec(pfv_spr, mtspr_cls, mfspr_cls, reserved_mask):
if isinstance(self.insn, mtspr_cls):
# Copy (RS) to SPR.
m.d.comb += [
self.pfv.rs.index.eq(self.insn.RS),
self.pfv.rs.r_stb.eq(1),
pfv_spr.w_mask.eq(~reserved_mask),
pfv_spr.w_data.eq(self.pfv.rs.r_data & ~reserved_mask),
]

if isinstance(self.insn, mfspr_cls):
# Copy SPR to (RT).
m.d.comb += [
self.pfv.rt.index.eq(self.insn.RT),
self.pfv.rt.w_stb.eq(1),
pfv_spr.r_mask.eq(~reserved_mask),
]
# In problem state, reading reserved bits returns 0.
with m.If(self.pfv.msr.r_data.pr):
m.d.comb += self.pfv.rt.w_data.eq(pfv_spr.r_data & ~reserved_mask)
with m.Else():
m.d.comb += self.pfv.rt.w_data.eq(pfv_spr.r_data)

if isinstance(self.insn, (MTXER, MFXER)):
xer_reserved_mask = Record(xer_layout)
m.d.comb += [ m.d.comb += [
self.pfv.rt.index.eq(self.insn.RT), xer_reserved_mask._56.eq(Repl(1, 1)),
self.pfv.rt.w_stb.eq(1), xer_reserved_mask._46.eq(Repl(1, 2)),
pfv_spr.r_mask.eq(~reserved_mask), xer_reserved_mask._35.eq(Repl(1, 9)),
xer_reserved_mask._0 .eq(Repl(1, 32)),
] ]
# In problem state, reading reserved bits returns 0. mXspr_spec(self.pfv.xer, MTXER, MFXER, xer_reserved_mask)
with m.If(self.pfv.msr.r_data.pr):
m.d.comb += self.pfv.rt.w_data.eq(pfv_spr.r_data & ~reserved_mask) elif isinstance(self.insn, (MTLR, MFLR)):
with m.Else(): mXspr_spec(self.pfv.lr, MTLR, MFLR, Const(0, 64))
m.d.comb += self.pfv.rt.w_data.eq(pfv_spr.r_data)

elif isinstance(self.insn, (MTCTR, MFCTR)):
if isinstance(self.insn, (MTXER, MFXER)): mXspr_spec(self.pfv.ctr, MTCTR, MFCTR, Const(0, 64))
xer_reserved_mask = Record(xer_layout)
m.d.comb += [
xer_reserved_mask._56.eq(Repl(1, 1)),
xer_reserved_mask._46.eq(Repl(1, 2)),
xer_reserved_mask._35.eq(Repl(1, 9)),
xer_reserved_mask._0 .eq(Repl(1, 32)),
]
mXspr_spec(self.pfv.xer, MTXER, MFXER, xer_reserved_mask)


elif isinstance(self.insn, (MTLR, MFLR)): elif isinstance(self.insn, (MTSRR0, MFSRR0)):
mXspr_spec(self.pfv.lr, MTLR, MFLR, Const(0, 64)) mXspr_spec(self.pfv.srr0, MTSRR0, MFSRR0, Const(0, 64))


elif isinstance(self.insn, (MTCTR, MFCTR)): elif isinstance(self.insn, (MTSRR1, MFSRR1)):
mXspr_spec(self.pfv.ctr, MTCTR, MFCTR, Const(0, 64)) # SRR1 bits should be treated as reserved if their corresponding MSR bits are also
# reserved; which is implementation-specific.
# We treat all bits as defined for now, but this may cause false positives.
srr1_reserved_mask = Const(0, 64)
mXspr_spec(self.pfv.srr1, MTSRR1, MFSRR1, srr1_reserved_mask)


elif isinstance(self.insn, (MTSRR0, MFSRR0)): elif isinstance(self.insn, (MTTAR, MFTAR)):
mXspr_spec(self.pfv.srr0, MTSRR0, MFSRR0, Const(0, 64)) mXspr_spec(self.pfv.tar, MTTAR, MFTAR, Const(0, 64))


elif isinstance(self.insn, (MTSRR1, MFSRR1)): else:
# SRR1 bits should be treated as reserved if their corresponding MSR bits are also assert False
# reserved; which is implementation-specific.
# We treat all bits as defined for now, but this may cause false positives.
srr1_reserved_mask = Const(0, 64)
mXspr_spec(self.pfv.srr1, MTSRR1, MFSRR1, srr1_reserved_mask)


elif isinstance(self.insn, (MTTAR, MFTAR)): # Update NIA
mXspr_spec(self.pfv.tar, MTTAR, MFTAR, Const(0, 64))


else: m.d.comb += self.pfv.nia.eq(iea(self.pfv.cia + 4, self.pfv.msr.r_data.sf))
assert False


return m return m

@ -2,9 +2,10 @@ from amaranth import *


from power_fv import pfv from power_fv import pfv
from power_fv.insn.const import * from power_fv.insn.const import *
from power_fv.intr import *


from . import InsnSpec from . import InsnSpec
from .utils import iea from .utils import iea, msr_to_srr1




__all__ = ["SystemCallSpec"] __all__ = ["SystemCallSpec"]
@ -17,19 +18,15 @@ class SystemCallSpec(InsnSpec, Elaboratable):
m.d.comb += [ m.d.comb += [
self.pfv.stb .eq(1), self.pfv.stb .eq(1),
self.pfv.insn.eq(Cat(Const(0, 32), self.insn.as_value())), self.pfv.insn.eq(Cat(Const(0, 32), self.insn.as_value())),
self.pfv.msr.r_mask.sf.eq(1),
] ]


if isinstance(self.insn, SC): if isinstance(self.insn, SC):
def _msr_to_srr1(start, stop):
stmts = [
self.pfv.msr .r_mask[63-stop:64-start].eq(Repl(1, stop-start+1)),
self.pfv.srr1.w_mask[63-stop:64-start].eq(Repl(1, stop-start+1)),
self.pfv.srr1.w_data[63-stop:64-start].eq(self.pfv.msr.r_data[63-stop:64-start]),
]
return stmts

m.d.comb += [ m.d.comb += [
self.pfv.intr.eq(1),
self.pfv.nia .eq(INTR_SYSTEM_CALL.vector_addr),
INTR_SYSTEM_CALL.write_msr(self.pfv.msr),

self.pfv.msr .r_mask.sf.eq(1),
self.pfv.srr0.w_mask.eq(Repl(1, 64)), self.pfv.srr0.w_mask.eq(Repl(1, 64)),
self.pfv.srr0.w_data.eq(iea(self.pfv.cia + 4, self.pfv.msr.r_data.sf)), self.pfv.srr0.w_data.eq(iea(self.pfv.cia + 4, self.pfv.msr.r_data.sf)),


@ -38,14 +35,10 @@ class SystemCallSpec(InsnSpec, Elaboratable):
self.pfv.srr1.w_mask[63-47:64-42].eq(Repl(1, 6)), self.pfv.srr1.w_mask[63-47:64-42].eq(Repl(1, 6)),
self.pfv.srr1.w_data[63-47:64-42].eq(0), self.pfv.srr1.w_data[63-47:64-42].eq(0),


_msr_to_srr1( 0, 32), msr_to_srr1(self.pfv.msr, self.pfv.srr1, 0, 32),
_msr_to_srr1(37, 41), msr_to_srr1(self.pfv.msr, self.pfv.srr1, 37, 41),
_msr_to_srr1(48, 63), msr_to_srr1(self.pfv.msr, self.pfv.srr1, 48, 63),

self.pfv.intr.eq(1),
self.pfv.nia .eq(0xc00),
] ]

else: else:
assert False assert False



@ -2,9 +2,10 @@ from amaranth import *


from power_fv import pfv from power_fv import pfv
from power_fv.insn.const import * from power_fv.insn.const import *
from power_fv.intr import *


from . import InsnSpec from . import InsnSpec
from .utils import iea from .utils import iea, msr_to_srr1




__all__ = ["TrapSpec"] __all__ = ["TrapSpec"]
@ -17,8 +18,6 @@ class TrapSpec(InsnSpec, Elaboratable):
m.d.comb += [ m.d.comb += [
self.pfv.stb .eq(1), self.pfv.stb .eq(1),
self.pfv.insn.eq(Cat(Const(0, 32), self.insn.as_value())), 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_a = Signal(signed(64))
@ -47,7 +46,7 @@ class TrapSpec(InsnSpec, Elaboratable):
else: else:
assert False assert False


# Compare operands, then trap if a condition is met. # Compare operands


m.d.comb += [ m.d.comb += [
cond.eq(self.insn.TO), cond.eq(self.insn.TO),
@ -57,8 +56,36 @@ class TrapSpec(InsnSpec, Elaboratable):
trap.eq_.eq(cond.eq_ & (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.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())), trap.gtu.eq(cond.gtu & (src_a.as_unsigned() > src_b.as_unsigned())),

self.pfv.intr.eq(trap.any()),
] ]


# Trap if a condition is met

m.d.comb += self.pfv.msr.r_mask.sf.eq(1)

with m.If(trap.any()):
m.d.comb += [
self.pfv.intr.eq(1),
self.pfv.nia .eq(INTR_PROGRAM.vector_addr),
INTR_PROGRAM.write_msr(self.pfv.msr),

self.pfv.srr0.w_mask.eq(Repl(1, 64)),
self.pfv.srr0.w_data.eq(iea(self.pfv.cia, self.pfv.msr.r_data.sf)),

self.pfv.srr1.w_mask[63-36:64-33].eq(0xf),
self.pfv.srr1.w_data[63-36:64-33].eq(0x0),

self.pfv.srr1.w_mask[63-42].eq(1),
self.pfv.srr1.w_data[63-42].eq(0),
self.pfv.srr1.w_mask[63-46:64-43].eq(Repl(1, 4)),
self.pfv.srr1.w_data[63-46:64-43].eq(0b0001), # Trap type
self.pfv.srr1.w_mask[63-47].eq(1),
self.pfv.srr1.w_data[63-47].eq(0),

msr_to_srr1(self.pfv.msr, self.pfv.srr1, 0, 32),
msr_to_srr1(self.pfv.msr, self.pfv.srr1, 37, 41),
msr_to_srr1(self.pfv.msr, self.pfv.srr1, 48, 63),
]
with m.Else():
m.d.comb += self.pfv.nia.eq(iea(self.pfv.cia + 4, self.pfv.msr.r_data.sf))

return m return m

@ -1,7 +1,7 @@
from amaranth import * from amaranth import *




__all__ = ["iea", "byte_reversed"] __all__ = ["iea", "byte_reversed", "msr_to_srr1"]




def iea(addr, msr_sf): def iea(addr, msr_sf):
@ -17,3 +17,12 @@ def byte_reversed(src, en=0):
assert len(src) in {8, 16, 32, 64} assert len(src) in {8, 16, 32, 64}
res = Cat(src.word_select(i, width=8) for i in reversed(range(len(src) // 8))) res = Cat(src.word_select(i, width=8) for i in reversed(range(len(src) // 8)))
return Mux(en, res, src) return Mux(en, res, src)


def msr_to_srr1(msr, srr1, start, stop):
stmts = [
msr .r_mask[63-stop:64-start].eq(Repl(1, stop-start+1)),
srr1.w_mask[63-stop:64-start].eq(Repl(1, stop-start+1)),
srr1.w_data[63-stop:64-start].eq(msr.r_data[63-stop:64-start]),
]
return stmts

@ -0,0 +1,60 @@
__all__ = [
"Interrupt",
"INTR_ALIGNMENT",
"INTR_PROGRAM",
"INTR_SYSTEM_CALL",
]


class Interrupt:
def __init__(self, vector_addr, ir, dr, ee, ri, me, hv, s):
self.vector_addr = vector_addr
self.ir = ir
self.dr = dr
self.ee = ee
self.ri = ri
self.me = me
self.hv = hv
self.s = s

def write_msr(self, msr):
def _write_field(field, value):
stmts = []
if value is not None:
stmts.append(getattr(msr.w_mask, field).eq(-1))
stmts.append(getattr(msr.w_data, field).eq(value))
return stmts

# See PowerISA v3.1, Book III, Section 7.5, Figure 67
stmts = [
_write_field("ir" , self.ir),
_write_field("dr" , self.dr),
_write_field("fe0", 0),
_write_field("fe1", 0),
_write_field("ee" , self.ee),
_write_field("ri" , self.ri),
_write_field("me" , self.me),
_write_field("hv" , self.hv),
_write_field("s" , self.s),

_write_field("pr" , 0),
_write_field("pmm", 0),
_write_field("te" , 0),
_write_field("fp" , 0),
_write_field("vec", 0),
_write_field("vsx", 0),
_write_field("sf" , 1),

msr.w_mask[63- 5].eq(1),
msr.w_data[63- 5].eq(0),
msr.w_mask[63-31].eq(1),
msr.w_data[63-31].eq(0),
]
return stmts


# TODO: Support MSR.{IR,DR,HV,S,LE} bits, which depend on context (e.g. LPCR)

INTR_ALIGNMENT = Interrupt(0x600, ir=None, dr=None, ee=0, ri=0, me=None, hv=None, s=None)
INTR_PROGRAM = Interrupt(0x700, ir=None, dr=None, ee=0, ri=0, me=None, hv=None, s=None)
INTR_SYSTEM_CALL = Interrupt(0xC00, ir=None, dr=None, ee=0, ri=0, me=None, hv=None, s=None)

@ -51,8 +51,10 @@ class Interface(Record):
Instruction strobe. Asserted when the processor retires an instruction. Other signals are Instruction strobe. Asserted when the processor retires an instruction. Other signals are
only valid when ``stb`` is asserted. only valid when ``stb`` is asserted.
""" """
def __init__(self, *, mem_aligned=False, name=None, src_loc_at=0): def __init__(self, *, mem_aligned=False, illegal_insn_heai=False,
self.mem_aligned = bool(mem_aligned) name=None, src_loc_at=0):
self.mem_aligned = bool(mem_aligned)
self.illegal_insn_heai = bool(illegal_insn_heai)


layout = [ layout = [
("stb" , unsigned( 1)), ("stb" , unsigned( 1)),

Loading…
Cancel
Save