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.

166 lines
4.9 KiB
Python

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