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;
""")

def __init__(self, **kwargs):
self.pfv = pfv.Interface(mem_aligned=False)
self.pfv = pfv.Interface(mem_aligned=False, illegal_insn_heai=False)
self.wb_insn = wishbone.Interface(addr_width=29, data_width=64, granularity=8,
features=("stall",))
self.wb_data = wishbone.Interface(addr_width=29, data_width=64, granularity=8,
@ -256,6 +255,14 @@ class MicrowattWrapper(Elaboratable):
Assume(~dmi.req),
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


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

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

m.submodules.ra = ra = _GPRFileTest(self.check, port="ra")
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),
]

with m.If(t_post.zero & ~spec.pfv.intr):
with m.If(t_post.zero):
m.d.comb += [
Assert(ra.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)

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

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),
]

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

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

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

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


__all__ = ["BranchSpec"]
@ -20,7 +21,9 @@ class BranchSpec(InsnSpec, Elaboratable):
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, (
BC , BCA , BCL , BCLA ,
@ -42,20 +45,43 @@ class BranchSpec(InsnSpec, Elaboratable):
"1-00-",
"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)
with m.If(illegal_insn.any()):
if self.pfv.illegal_insn_heai:
raise NotImplementedError

# Is this branch taken ?
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(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),
]

with m.Else():
taken = Signal()

cond_bit = Signal()
cond_ok = Signal()
ctr_any = Signal()
ctr_ok = Signal()

# Is this branch taken ?

if isinstance(self.insn, (B, BA, BL, BLA)):
m.d.comb += taken.eq(1)

@ -65,29 +91,29 @@ class BranchSpec(InsnSpec, Elaboratable):
BCCTR, BCCTRL,
)):

# If BO(0) = 0, test CR(BI)
with m.If(self.insn.BO[4 - 0]):
m.d.comb += cond_ok.eq(1)
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 += [
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)),
cond_bit.eq(self.pfv.cr.r_data.bit_select(31-self.insn.BI, width=1)),
cond_ok .eq(cond_bit == self.insn.BO[4 - 1]),
]

if isinstance(self.insn, (BCCTR, BCCTRL)):
m.d.comb += taken.eq(cond_ok)
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():
# 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]),
]

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

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

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


__all__ = ["LoadStoreSpec"]
@ -18,10 +19,53 @@ class LoadStoreSpec(InsnSpec, Elaboratable):
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),
]

# Raise an interrupt if RA is invalid

illegal_insn = Record([
("ra_zero", 1),
("ra_rt" , 1),
])

if isinstance(self.insn, (
LBZU, LBZUX, LHZU, LHZUX, LHAU, LHAUX, LWZU, LWZUX,
STBU, STBUX, STHU, STHUX, STWU, STWUX,
)):
m.d.comb += illegal_insn.ra_zero.eq(self.insn.RA == 0)
if isinstance(self.insn, (
LBZU, LBZUX, LHZU, LHZUX, LHAU, LHAUX, LWZU, LWZUX,
)):
m.d.comb += illegal_insn.ra_rt.eq(self.insn.RA == self.insn.RT)

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

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(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),
]

with m.Else():
# EA (effective address) = ea_base + ea_offset

ea = Signal(64)
@ -74,13 +118,13 @@ class LoadStoreSpec(InsnSpec, Elaboratable):

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)

# 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.

m.d.comb += self.pfv.mem.addr[3:].eq(ea[3:])

if self.pfv.mem_aligned:
@ -99,8 +143,52 @@ class LoadStoreSpec(InsnSpec, Elaboratable):
word_offset.eq(byte_offset[2:]),
]

msr_le = self.pfv.msr.r_data.le
# 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

with m.If(ea_misaligned):
m.d.comb += [
self.pfv.intr.eq(1),
self.pfv.nia .eq(INTR_ALIGNMENT.vector_addr),
INTR_ALIGNMENT.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_mask[63-36:64-33].eq(0),
self.pfv.srr1.w_mask[63-47:64-42].eq(Repl(1, 6)),
self.pfv.srr1.w_mask[63-47:64-42].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.msr.r_mask.le.eq(1)
msr_le = self.pfv.msr.r_data.le

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

@ -219,49 +307,8 @@ class LoadStoreSpec(InsnSpec, Elaboratable):
self.pfv.ra.w_data.eq(ea),
]

# Interrupt causes

intr = Record([
("misaligned", 1),
("update_zero", 1),
("update_rt", 1),
])

if isinstance(self.insn, (
LBZ, LBZX, LBZU, LBZUX,
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, (
LBZU, LBZUX, LHZU, LHZUX, LHAU, LHAUX, LWZU, LWZUX,
STBU, STBUX, STHU, STHUX, STWU, STWUX,
)):
m.d.comb += intr.update_zero.eq(self.insn.RA == 0)
else:
m.d.comb += intr.update_zero.eq(0)

if isinstance(self.insn, (
LBZU, LBZUX, LHZU, LHZUX, LHAU, LHAUX, LWZU, LWZUX,
)):
m.d.comb += intr.update_rt.eq(self.insn.RA == self.insn.RT)
else:
m.d.comb += intr.update_rt.eq(0)
# Update NIA

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

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

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

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


__all__ = ["MSRMoveSpec"]
@ -18,14 +19,36 @@ class MSRMoveSpec(InsnSpec, Elaboratable):
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),
self.pfv.msr.r_mask.pr.eq(1)
]

# Raise a Program Interrupt if executing from Problem State

# mtmsr/mfmsr are privileged
self.pfv.intr.eq(self.pfv.msr.r_data.pr),
self.pfv.msr.r_mask.pr.eq(1),
with m.If(self.pfv.msr.r_data.pr):
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(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.Else():
rs_as_msr = Record(msr_layout)
ultravisor = Signal()

@ -106,4 +129,8 @@ class MSRMoveSpec(InsnSpec, Elaboratable):
else:
assert False

# Update NIA

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

return m

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

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

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


__all__ = ["RotateShiftSpec"]
@ -17,11 +18,45 @@ class RotateShiftSpec(InsnSpec, Elaboratable):
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),
]

# Raise an interrupt if MB or ME are invalid

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

if isinstance(self.insn, (RLWINM, RLWINM_, RLWNM, RLWNM_, RLWIMI, RLWIMI_)):
m.d.comb += illegal_insn.mask.eq((self.insn.MB >= 32) | (self.insn.ME >= 32))

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

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(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),
]

with m.Else():
src = Signal(unsigned(64))
shamt = Signal(unsigned( 6))
rotl = Signal(unsigned(64))
@ -136,17 +171,8 @@ class RotateShiftSpec(InsnSpec, Elaboratable):
self.pfv.xer.w_data.ca32.eq(carry),
]

# Interrupt causes

intr = Record([
("rotl32_mask", 1),
])

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

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

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

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

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


__all__ = ["SPRMoveSpec"]
@ -18,12 +19,11 @@ class SPRMoveSpec(InsnSpec, Elaboratable):
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),
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_access_err = Signal()
@ -31,9 +31,32 @@ class SPRMoveSpec(InsnSpec, Elaboratable):
m.d.comb += [
spr_privileged.eq(self.insn.SPR[9 - 0]),
spr_access_err.eq(spr_privileged & self.pfv.msr.r_data.pr),
self.pfv.intr.eq(spr_access_err),
]

with m.If(spr_access_err):
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(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.Else():
def mXspr_spec(pfv_spr, mtspr_cls, mfspr_cls, reserved_mask):
if isinstance(self.insn, mtspr_cls):
# Copy (RS) to SPR.
@ -89,4 +112,8 @@ class SPRMoveSpec(InsnSpec, Elaboratable):
else:
assert False

# Update NIA

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

return m

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

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

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


__all__ = ["SystemCallSpec"]
@ -17,19 +18,15 @@ class SystemCallSpec(InsnSpec, Elaboratable):
m.d.comb += [
self.pfv.stb .eq(1),
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):
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 += [
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_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_data[63-47:64-42].eq(0),

_msr_to_srr1( 0, 32),
_msr_to_srr1(37, 41),
_msr_to_srr1(48, 63),

self.pfv.intr.eq(1),
self.pfv.nia .eq(0xc00),
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


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

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

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


__all__ = ["TrapSpec"]
@ -17,8 +18,6 @@ class TrapSpec(InsnSpec, Elaboratable):
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))
@ -47,7 +46,7 @@ class TrapSpec(InsnSpec, Elaboratable):
else:
assert False

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

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

# Trap if a condition is met

self.pfv.intr.eq(trap.any()),
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

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


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


def iea(addr, msr_sf):
@ -17,3 +17,12 @@ def byte_reversed(src, en=0):
assert len(src) in {8, 16, 32, 64}
res = Cat(src.word_select(i, width=8) for i in reversed(range(len(src) // 8)))
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
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,
name=None, src_loc_at=0):
self.mem_aligned = bool(mem_aligned)
self.illegal_insn_heai = bool(illegal_insn_heai)

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

Loading…
Cancel
Save