checks.insn: add checks for MTSPR and MFSPR instructions.
parent
21be78c4f8
commit
8cf56ab5dc
@ -0,0 +1,165 @@
|
|||||||
|
from amaranth import *
|
||||||
|
from amaranth.asserts import *
|
||||||
|
|
||||||
|
from .. import PowerFVCheck
|
||||||
|
from ... import pfv, tb
|
||||||
|
|
||||||
|
from ._fmt import *
|
||||||
|
from ._insn import *
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["SPRMoveSpec", "SPRMoveCheck"]
|
||||||
|
|
||||||
|
|
||||||
|
class SPRMoveSpec(Elaboratable):
|
||||||
|
def __init__(self, insn_cls, post):
|
||||||
|
self.insn_cls = insn_cls
|
||||||
|
self.pfv = pfv.Interface()
|
||||||
|
self.post = tb.Trigger(cycle=post)
|
||||||
|
|
||||||
|
def triggers(self):
|
||||||
|
yield self.post
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# - don't hardcode SPRs, let cores declare what they support.
|
||||||
|
# - access restrictions (i.e. R/W, privileged)
|
||||||
|
|
||||||
|
def elaborate(self, platform):
|
||||||
|
m = Module()
|
||||||
|
|
||||||
|
spec_insn = self.insn_cls()
|
||||||
|
|
||||||
|
with m.If(self.post.stb):
|
||||||
|
m.d.sync += [
|
||||||
|
Assume(self.pfv.stb),
|
||||||
|
Assume(self.pfv.insn[32:] == spec_insn),
|
||||||
|
]
|
||||||
|
|
||||||
|
spr = Record([
|
||||||
|
("num", 10),
|
||||||
|
("reserved", 1),
|
||||||
|
("undefined", 1),
|
||||||
|
("pfv", [
|
||||||
|
("r_mask", 64),
|
||||||
|
("r_data", 64),
|
||||||
|
("w_mask", 64),
|
||||||
|
("w_data", 64),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
|
||||||
|
if isinstance(spec_insn, (MTSPR, MFSPR)):
|
||||||
|
m.d.comb += spr.num.eq(Cat(spec_insn.spr[5:10], spec_insn.spr[0:5]))
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
|
with m.Switch(spr.num):
|
||||||
|
for num in range(808, 812):
|
||||||
|
with m.Case(num):
|
||||||
|
m.d.comb += spr.reserved.eq(1)
|
||||||
|
|
||||||
|
pfv_sprs = [
|
||||||
|
( 1, self.pfv.xer ),
|
||||||
|
( 8, self.pfv.lr ),
|
||||||
|
( 9, self.pfv.ctr ),
|
||||||
|
( 26, self.pfv.srr0),
|
||||||
|
( 27, self.pfv.srr1),
|
||||||
|
(815, self.pfv.tar ),
|
||||||
|
]
|
||||||
|
|
||||||
|
for num, pfv_spr in pfv_sprs:
|
||||||
|
with m.Case(num):
|
||||||
|
m.d.comb += [
|
||||||
|
spr.pfv.r_mask.eq(pfv_spr.r_mask),
|
||||||
|
spr.pfv.r_data.eq(pfv_spr.r_data),
|
||||||
|
spr.pfv.w_mask.eq(pfv_spr.w_mask),
|
||||||
|
spr.pfv.w_data.eq(pfv_spr.w_data),
|
||||||
|
]
|
||||||
|
|
||||||
|
with m.Default():
|
||||||
|
m.d.comb += spr.undefined.eq(1)
|
||||||
|
|
||||||
|
with m.If(self.post.stb):
|
||||||
|
# TODO: turn into assert
|
||||||
|
m.d.sync += Assume(spr.undefined.implies(self.pfv.intr))
|
||||||
|
|
||||||
|
# # MSR
|
||||||
|
# pfv_msr_pr = Signal()
|
||||||
|
# m.d.comb += pfv_msr_pr.eq(self.pfv.msr.r_data[63 - 49])
|
||||||
|
|
||||||
|
# with m.If(self.post.stb):
|
||||||
|
# m.d.sync += Assert(self.pfv.msr.r_mask[63 - 49])
|
||||||
|
|
||||||
|
# GPR
|
||||||
|
|
||||||
|
spec_rs_r_stb = Signal()
|
||||||
|
spec_rt_w_stb = Signal()
|
||||||
|
# spec_rt_w_mask = Signal(64)
|
||||||
|
spec_rt_w_data = Signal(64)
|
||||||
|
|
||||||
|
if isinstance(spec_insn, MTSPR):
|
||||||
|
m.d.comb += [
|
||||||
|
spec_rs_r_stb.eq(~spr.reserved),
|
||||||
|
spec_rt_w_stb.eq(0),
|
||||||
|
]
|
||||||
|
|
||||||
|
elif isinstance(spec_insn, MFSPR):
|
||||||
|
m.d.comb += [
|
||||||
|
spec_rs_r_stb .eq(0),
|
||||||
|
spec_rt_w_stb .eq(~spr.reserved),
|
||||||
|
spec_rt_w_data.eq(spr.pfv.r_data),
|
||||||
|
]
|
||||||
|
|
||||||
|
# # In problem state, reserved fields must return 0, so we include them in the mask.
|
||||||
|
# # In privileged state, reserved fields may return anything.
|
||||||
|
# with m.If(pfv_msr_pr):
|
||||||
|
# m.d.comb += spec_rt_w_mask.eq(Repl(1, 64))
|
||||||
|
# with m.Else():
|
||||||
|
# m.d.comb += spec_rt_w_mask.eq(spr.pfv.r_mask)
|
||||||
|
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
|
with m.If(self.post.stb & ~self.pfv.intr):
|
||||||
|
m.d.sync += [
|
||||||
|
Assert(spec_rs_r_stb.implies(self.pfv.rs.r_stb)),
|
||||||
|
Assert(self.pfv.rt.w_stb == spec_rt_w_stb),
|
||||||
|
Assert(spec_rt_w_stb.implies(self.pfv.rt.w_data == (spr.pfv.r_data & spr.pfv.r_mask))),
|
||||||
|
]
|
||||||
|
# with m.If(spec_rt_w_stb):
|
||||||
|
# for i in range(64):
|
||||||
|
# with m.If(spr.pfv.w_mask[i]):
|
||||||
|
# m.d.sync += Assert(self.pfv.rt.w_data[i] == spec_rt_w_data[i])
|
||||||
|
|
||||||
|
# SPR
|
||||||
|
|
||||||
|
spec_spr_w_stb = Signal()
|
||||||
|
spec_spr_w_data = Signal(64)
|
||||||
|
|
||||||
|
if isinstance(spec_insn, MTSPR):
|
||||||
|
m.d.comb += [
|
||||||
|
spec_spr_w_stb .eq(1),
|
||||||
|
spec_spr_w_data.eq(self.pfv.rs.r_data),
|
||||||
|
]
|
||||||
|
elif isinstance(spec_insn, MFSPR):
|
||||||
|
m.d.comb += spec_spr_w_stb.eq(0)
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
|
with m.If(self.post.stb & ~self.pfv.intr):
|
||||||
|
m.d.sync += [
|
||||||
|
Assert(spec_spr_w_stb == spr.pfv.w_mask.any()),
|
||||||
|
Assert((spr.pfv.w_data & spr.pfv.w_mask) == (spec_spr_w_data & spr.pfv.w_mask)),
|
||||||
|
]
|
||||||
|
|
||||||
|
return m
|
||||||
|
|
||||||
|
|
||||||
|
class SPRMoveCheck(PowerFVCheck, name="_insn_spr"):
|
||||||
|
def __init_subclass__(cls, name, insn_cls):
|
||||||
|
super().__init_subclass__(name)
|
||||||
|
cls.insn_cls = insn_cls
|
||||||
|
|
||||||
|
def get_testbench(self, dut, post):
|
||||||
|
tb_spec = SPRMoveSpec(self.insn_cls, post)
|
||||||
|
tb_top = tb.Testbench(tb_spec, dut)
|
||||||
|
return tb_top
|
Loading…
Reference in New Issue