You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
228 lines
7.3 KiB
Python
228 lines
7.3 KiB
Python
from amaranth import *
|
|
from amaranth.asserts import *
|
|
|
|
from .. import pfv
|
|
from ..insn import *
|
|
from ..utils import iea_mask
|
|
|
|
|
|
__all__ = ["Check"]
|
|
|
|
|
|
class Check(Elaboratable):
|
|
_insn_cls = None
|
|
|
|
def __init_subclass__(cls, *, insn_cls):
|
|
cls._insn_cls = insn_cls
|
|
|
|
def __init__(self):
|
|
self.pfv = pfv.Interface()
|
|
self.trig = Record([
|
|
("pre", 1),
|
|
("post", 1),
|
|
])
|
|
|
|
def elaborate(self, platform):
|
|
m = Module()
|
|
|
|
spec_insn = self._insn_cls()
|
|
|
|
with m.If(self.trig.post):
|
|
m.d.sync += [
|
|
Assume(self.pfv.stb),
|
|
Assume(self.pfv.insn[32:] == spec_insn),
|
|
Assert(self.pfv.msr.w_stb),
|
|
]
|
|
|
|
msr_w_sf = Signal()
|
|
m.d.comb += msr_w_sf.eq(self.pfv.msr.w_data[63])
|
|
|
|
if isinstance(spec_insn, (Instruction_B, Instruction_XL_b)):
|
|
bo_valid_patterns = [
|
|
"001--",
|
|
"011--",
|
|
"1-1--",
|
|
]
|
|
if not isinstance(spec_insn, (BCCTR, BCCTRL)):
|
|
# bcctr/bcctrl forms with BO(2)=0 ("decrement and test CTR") are illegal.
|
|
bo_valid_patterns += [
|
|
"0000-",
|
|
"0001-",
|
|
"0100-",
|
|
"0101-",
|
|
"1-00-",
|
|
"1-01-",
|
|
]
|
|
|
|
bo_invalid = Signal()
|
|
m.d.comb += bo_invalid.eq(~spec_insn.bo.matches(*bo_valid_patterns))
|
|
|
|
with m.If(self.trig.post):
|
|
m.d.sync += Assert(bo_invalid.implies(self.pfv.intr))
|
|
|
|
# NIA
|
|
|
|
spec_nia = Signal(unsigned(64))
|
|
taken = Signal()
|
|
offset = Signal(signed(62))
|
|
target = Signal(signed(64))
|
|
|
|
if isinstance(spec_insn, Instruction_I):
|
|
m.d.comb += [
|
|
taken .eq(1),
|
|
offset.eq(spec_insn.li)
|
|
]
|
|
|
|
elif isinstance(spec_insn, (Instruction_B, Instruction_XL_b)):
|
|
cond_bit = Signal()
|
|
ctr_any = Signal()
|
|
cond_ok = Signal()
|
|
ctr_ok = Signal()
|
|
|
|
m.d.comb += [
|
|
cond_bit.eq(self.pfv.cr.r_data[::-1].bit_select(spec_insn.bi, width=1)),
|
|
ctr_any .eq( self.pfv.ctr.w_data[:32].any() |
|
|
(self.pfv.ctr.w_data[32:].any() & msr_w_sf)),
|
|
cond_ok .eq(spec_insn.bo[4-0] | (spec_insn.bo[4-1] == cond_bit)),
|
|
ctr_ok .eq(spec_insn.bo[4-2] | (ctr_any ^ spec_insn.bo[4-3])),
|
|
]
|
|
|
|
if isinstance(spec_insn, (BCCTR, BCCTRL)):
|
|
m.d.comb += taken.eq(cond_ok)
|
|
else:
|
|
m.d.comb += taken.eq(cond_ok & ctr_ok)
|
|
|
|
if isinstance(spec_insn, Instruction_B):
|
|
m.d.comb += offset.eq(spec_insn.bd)
|
|
elif isinstance(spec_insn, (BCLR, BCLRL)):
|
|
m.d.comb += offset.eq(self.pfv.lr .r_data[2:])
|
|
elif isinstance(spec_insn, (BCCTR, BCCTRL)):
|
|
m.d.comb += offset.eq(self.pfv.ctr.r_data[2:])
|
|
elif isinstance(spec_insn, (BCTAR, BCTARL)):
|
|
m.d.comb += offset.eq(self.pfv.tar.r_data[2:])
|
|
else:
|
|
assert False
|
|
|
|
else:
|
|
assert False
|
|
|
|
with m.If(taken):
|
|
if isinstance(spec_insn, (Instruction_I, Instruction_B)) and spec_insn.aa.value == 0:
|
|
m.d.comb += target.eq(self.pfv.cia + (offset << 2))
|
|
else:
|
|
m.d.comb += target.eq(offset << 2)
|
|
with m.Else():
|
|
m.d.comb += target.eq(self.pfv.cia + 4)
|
|
|
|
m.d.comb += spec_nia.eq(iea_mask(target, msr_w_sf))
|
|
|
|
with m.If(self.trig.post & ~self.pfv.intr):
|
|
m.d.sync += Assert(self.pfv.nia == spec_nia)
|
|
|
|
# CR
|
|
|
|
spec_cr_r_stb = Signal(8)
|
|
|
|
if isinstance(spec_insn, Instruction_I):
|
|
m.d.comb += spec_cr_r_stb.eq(0)
|
|
elif isinstance(spec_insn, (Instruction_B, Instruction_XL_b)):
|
|
m.d.comb += spec_cr_r_stb[::-1].bit_select(spec_insn.bi[2:], width=1).eq(1)
|
|
else:
|
|
assert False
|
|
|
|
with m.If(self.trig.post & ~self.pfv.intr):
|
|
for i, spec_cr_r_stb_bit in enumerate(spec_cr_r_stb):
|
|
pfv_cr_r_stb_bit = self.pfv.cr.r_stb[i]
|
|
m.d.sync += Assert(spec_cr_r_stb_bit.implies(pfv_cr_r_stb_bit))
|
|
|
|
# LR
|
|
|
|
spec_lr_r_stb = Signal()
|
|
spec_lr_w_stb = Signal()
|
|
spec_lr_w_data = Signal(64)
|
|
|
|
if isinstance(spec_insn, (Instruction_I, Instruction_B)):
|
|
m.d.comb += spec_lr_r_stb.eq(0)
|
|
elif isinstance(spec_insn, (Instruction_XL_b)):
|
|
if isinstance(spec_insn, (BCLR, BCLRL)):
|
|
m.d.comb += spec_lr_r_stb.eq(1)
|
|
else:
|
|
m.d.comb += spec_lr_r_stb.eq(0)
|
|
else:
|
|
assert False
|
|
|
|
cia_4 = Signal(unsigned(64))
|
|
m.d.comb += cia_4.eq(self.pfv.cia + 4)
|
|
|
|
m.d.comb += [
|
|
spec_lr_w_stb .eq(spec_insn.lk),
|
|
spec_lr_w_data.eq(iea_mask(cia_4, msr_w_sf)),
|
|
]
|
|
|
|
with m.If(self.trig.post & ~self.pfv.intr):
|
|
m.d.sync += [
|
|
Assert(self.pfv.lr.r_stb == spec_lr_r_stb),
|
|
Assert(self.pfv.lr.w_stb == spec_lr_w_stb),
|
|
Assert(self.pfv.lr.w_stb.implies(self.pfv.lr.w_data == spec_lr_w_data)),
|
|
]
|
|
|
|
# CTR
|
|
|
|
spec_ctr_r_stb = Signal()
|
|
spec_ctr_w_stb = Signal()
|
|
spec_ctr_w_data = Signal(64)
|
|
|
|
if isinstance(spec_insn, Instruction_I):
|
|
m.d.comb += spec_ctr_r_stb.eq(0)
|
|
elif isinstance(spec_insn, Instruction_B):
|
|
m.d.comb += spec_ctr_r_stb.eq(~spec_insn.bo[4-2])
|
|
elif isinstance(spec_insn, Instruction_XL_b):
|
|
if isinstance(spec_insn, (BCCTR, BCCTRL)):
|
|
m.d.comb += spec_ctr_r_stb.eq(1)
|
|
else:
|
|
m.d.comb += spec_ctr_r_stb.eq(~spec_insn.bo[4-2])
|
|
else:
|
|
assert False
|
|
|
|
if isinstance(spec_insn, Instruction_I):
|
|
m.d.comb += spec_ctr_w_stb.eq(0)
|
|
elif isinstance(spec_insn, Instruction_B):
|
|
m.d.comb += spec_ctr_w_stb.eq(~spec_insn.bo[4-2])
|
|
elif isinstance(spec_insn, Instruction_XL_b):
|
|
if isinstance(spec_insn, (BCCTR, BCCTRL)):
|
|
m.d.comb += spec_ctr_w_stb.eq(0)
|
|
else:
|
|
m.d.comb += spec_ctr_w_stb.eq(~spec_insn.bo[4-2])
|
|
else:
|
|
assert False
|
|
|
|
m.d.comb += spec_ctr_w_data.eq(self.pfv.ctr.r_data - 1)
|
|
|
|
with m.If(self.trig.post & ~self.pfv.intr):
|
|
m.d.sync += [
|
|
Assert(self.pfv.ctr.r_stb == spec_ctr_r_stb),
|
|
Assert(self.pfv.ctr.w_stb == spec_ctr_w_stb),
|
|
Assert(self.pfv.ctr.w_stb.implies(self.pfv.ctr.w_data == spec_ctr_w_data)),
|
|
]
|
|
|
|
# TAR
|
|
|
|
spec_tar_r_stb = Signal()
|
|
|
|
if isinstance(spec_insn, (Instruction_I, Instruction_B)):
|
|
m.d.comb += spec_tar_r_stb.eq(0)
|
|
elif isinstance(spec_insn, (Instruction_XL_b)):
|
|
if isinstance(spec_insn, (BCTAR, BCTARL)):
|
|
m.d.comb += spec_tar_r_stb.eq(1)
|
|
else:
|
|
m.d.comb += spec_tar_r_stb.eq(0)
|
|
else:
|
|
assert False
|
|
|
|
with m.If(self.trig.post & ~self.pfv.intr):
|
|
m.d.sync += [
|
|
Assert(self.pfv.tar.r_stb == spec_tar_r_stb),
|
|
]
|
|
|
|
return m
|