Update SPR interface and split consistency check.
* Use bitmasks to describe SPR accesses at the field granularity. * Use separate checks for each SPR, instead of covering them all at once. Users may run them in the same batch, and know which SPR passes or fails its check.main
parent
e3f4bf6e24
commit
a413025fcb
@ -1,5 +1,5 @@
|
||||
from .unique import *
|
||||
from .ia_fwd import *
|
||||
from .gpr import *
|
||||
from .cr import *
|
||||
from .spr import *
|
||||
from .unique import *
|
||||
from .ia_fwd import *
|
||||
from .gpr import *
|
||||
from .cr import *
|
||||
from .spr.all import *
|
||||
|
@ -1,69 +0,0 @@
|
||||
from collections import OrderedDict
|
||||
|
||||
from amaranth import *
|
||||
from amaranth.asserts import *
|
||||
|
||||
from .. import PowerFVCheck
|
||||
from ... import pfv, tb
|
||||
|
||||
|
||||
__all__ = ["SPRSpec", "SPRCheck"]
|
||||
|
||||
|
||||
class SPRSpec(Elaboratable):
|
||||
"""SPR consistency specification.
|
||||
|
||||
Checks that reads from supported SPRs are the last value that was written to
|
||||
them.
|
||||
"""
|
||||
def __init__(self, post):
|
||||
self.pfv = pfv.Interface()
|
||||
self.post = tb.Trigger(cycle=post)
|
||||
|
||||
def triggers(self):
|
||||
yield self.post
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
spr_map = OrderedDict()
|
||||
|
||||
for spr_name in ("lr", "ctr", "xer", "tar"):
|
||||
spr = Record([
|
||||
("written", 1),
|
||||
("shadow", 64),
|
||||
], name=spr_name)
|
||||
spr_map[spr_name] = spr
|
||||
|
||||
spec_order = AnyConst(self.pfv.order.width)
|
||||
|
||||
with m.If(self.pfv.stb & (self.pfv.order <= spec_order)):
|
||||
for spr_name, spr in spr_map.items():
|
||||
pfv_spr = getattr(self.pfv, spr_name)
|
||||
|
||||
with m.If(pfv_spr.w_stb):
|
||||
m.d.sync += [
|
||||
spr.written.eq(1),
|
||||
spr.shadow .eq(pfv_spr.w_data),
|
||||
]
|
||||
|
||||
with m.If(self.post.stb):
|
||||
m.d.sync += [
|
||||
Assume(Past(self.pfv.stb)),
|
||||
Assume(Past(self.pfv.order) == spec_order),
|
||||
]
|
||||
|
||||
for spr_name, spr in spr_map.items():
|
||||
pfv_spr = getattr(self.pfv, spr_name)
|
||||
|
||||
with m.If(spr.written & Past(pfv_spr.r_stb)):
|
||||
m.d.sync += Assert(Past(spr.shadow) == Past(pfv_spr.r_data))
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class SPRCheck(PowerFVCheck, name="cons_spr"):
|
||||
def get_testbench(self, dut, post):
|
||||
tb_spec = SPRSpec(post)
|
||||
tb_top = tb.Testbench(tb_spec, dut)
|
||||
return tb_top
|
@ -0,0 +1,77 @@
|
||||
from collections import OrderedDict
|
||||
|
||||
from amaranth import *
|
||||
from amaranth.asserts import *
|
||||
|
||||
from ... import PowerFVCheck
|
||||
from .... import pfv, tb
|
||||
|
||||
|
||||
__all__ = ["SPRSpec", "SPRCheck"]
|
||||
|
||||
|
||||
class StorageSPRSpec(Elaboratable):
|
||||
"""Storage SPR specification.
|
||||
|
||||
Checks that reads from supported SPRs return the last value that was written to them.
|
||||
"""
|
||||
def __init__(self, spr_name, spr_reset, post):
|
||||
self.spr_name = spr_name
|
||||
self.spr_reset = spr_reset
|
||||
|
||||
self.pfv = pfv.Interface()
|
||||
self.post = tb.Trigger(cycle=post)
|
||||
|
||||
def triggers(self):
|
||||
yield self.post
|
||||
|
||||
@property
|
||||
def pfv_spr(self):
|
||||
return getattr(self.pfv, self.spr_name)
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
spr = Record([
|
||||
("written", 1),
|
||||
("shadow", self.pfv_spr.r_data.width),
|
||||
], name=self.spr_name)
|
||||
|
||||
spec_order = AnyConst(self.pfv.order.width)
|
||||
|
||||
with m.If(Initial()):
|
||||
m.d.sync += Assume(spr.shadow == self.spr_reset)
|
||||
|
||||
with m.If(self.pfv.stb & (self.pfv.order <= spec_order)):
|
||||
with m.If(self.pfv_spr.w_mask.any()):
|
||||
m.d.sync += [
|
||||
spr.written.eq(1),
|
||||
spr.shadow .eq((spr.shadow & ~self.pfv_spr.w_mask) | (self.pfv_spr.w_data & self.pfv_spr.w_mask)),
|
||||
]
|
||||
|
||||
with m.If(self.post.stb):
|
||||
m.d.sync += [
|
||||
Assume(Past(self.pfv.stb)),
|
||||
Assume(Past(self.pfv.order) == spec_order),
|
||||
]
|
||||
|
||||
with m.If(spr.written):
|
||||
p_spr_r_mask = Past(self.pfv_spr.r_mask)
|
||||
p_spr_r_data = Past(self.pfv_spr.r_data)
|
||||
p_spr_shadow = Past(spr.shadow)
|
||||
m.d.sync += Assert((p_spr_r_data & p_spr_r_mask) == (p_spr_shadow & p_spr_r_mask))
|
||||
|
||||
m.d.sync += Assume(spr.written & Past(self.pfv_spr.r_mask).any()) # FIXME rm
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class StorageSPRCheck(PowerFVCheck, name="_cons_spr_storage"):
|
||||
def __init_subclass__(cls, name, spr_name):
|
||||
super().__init_subclass__(name)
|
||||
cls.spr_name = spr_name
|
||||
|
||||
def get_testbench(self, dut, post, spr_reset=0):
|
||||
tb_spec = StorageSPRSpec(self.spr_name, spr_reset, post)
|
||||
tb_top = tb.Testbench(tb_spec, dut)
|
||||
return tb_top
|
@ -0,0 +1,9 @@
|
||||
from ._storage import StorageSPRCheck
|
||||
|
||||
|
||||
class LR (StorageSPRCheck, name="cons_lr", spr_name="lr" ): pass
|
||||
class CTR (StorageSPRCheck, name="cons_ctr", spr_name="ctr" ): pass
|
||||
class XER (StorageSPRCheck, name="cons_xer", spr_name="xer" ): pass
|
||||
class TAR (StorageSPRCheck, name="cons_tar", spr_name="tar" ): pass
|
||||
class SRR0 (StorageSPRCheck, name="cons_srr0", spr_name="srr0"): pass
|
||||
class SRR1 (StorageSPRCheck, name="cons_srr1", spr_name="srr1"): pass
|
Loading…
Reference in New Issue