from amaranth import * from amaranth.asserts import * from .. import pfv __all__ = ["Check"] class Check(Elaboratable): """General Purpose Registers check. Checks that: * reads from a GPR are consistent with the last value that was written to it; * writes to multiple GPRs by a single instruction (e.g. load with update) do not target the same register. """ def __init__(self): self.pfv = pfv.Interface() self.trig = Record([ ("pre", 1), ("post", 1), ]) def elaborate(self, platform): m = Module() spec_order = AnyConst(self.pfv.order.width) spec_gpr_index = AnyConst(5) gpr_ra_read = Signal() gpr_ra_write = Signal() gpr_rb_read = Signal() gpr_rs_read = Signal() gpr_rt_read = Signal() gpr_rt_write = Signal() gpr_conflict = Signal() gpr_written = Signal() gpr_shadow = Signal(64) m.d.comb += [ gpr_ra_read .eq(self.pfv.ra.r_stb & (self.pfv.ra.index == spec_gpr_index)), gpr_ra_write.eq(self.pfv.ra.w_stb & (self.pfv.ra.index == spec_gpr_index)), gpr_rb_read .eq(self.pfv.rb.r_stb & (self.pfv.rb.index == spec_gpr_index)), gpr_rs_read .eq(self.pfv.rs.r_stb & (self.pfv.rs.index == spec_gpr_index)), gpr_rt_read .eq(self.pfv.rt.r_stb & (self.pfv.rt.index == spec_gpr_index)), gpr_rt_write.eq(self.pfv.rt.w_stb & (self.pfv.rt.index == spec_gpr_index)), ] with m.If(self.pfv.stb & ~self.pfv.intr & (self.pfv.order <= spec_order)): with m.If(gpr_ra_write & gpr_rt_write): m.d.sync += gpr_conflict.eq(1) with m.If(gpr_ra_write | gpr_rt_write): m.d.sync += gpr_written.eq(1) with m.If(gpr_ra_write): m.d.sync += gpr_shadow.eq(self.pfv.ra.w_data) with m.Else(): m.d.sync += gpr_shadow.eq(self.pfv.rt.w_data) with m.If(self.trig.post): m.d.sync += [ Assume(Past(self.pfv.stb)), Assume(Past(self.pfv.order) == spec_order), ] with m.If(~Past(self.pfv.intr)): m.d.sync += Assert(gpr_written.implies(~gpr_conflict)) with m.If(gpr_written & Past(gpr_ra_read)): m.d.sync += Assert(Past(gpr_shadow) == Past(self.pfv.ra.r_data)) with m.If(gpr_written & Past(gpr_rb_read)): m.d.sync += Assert(Past(gpr_shadow) == Past(self.pfv.rb.r_data)) with m.If(gpr_written & Past(gpr_rs_read)): m.d.sync += Assert(Past(gpr_shadow) == Past(self.pfv.rs.r_data)) with m.If(gpr_written & Past(gpr_rt_read)): m.d.sync += Assert(Past(gpr_shadow) == Past(self.pfv.rt.r_data)) return m