riscv-formal-nmigen/rvfi/cores/minerva/units/trigger.py

118 lines
3.4 KiB
Python

from functools import reduce
from operator import or_
from nmigen import *
from nmigen.hdl.rec import *
from ..csr import *
from ..isa import *
__all__ = ["TriggerUnit"]
class Type:
NOP = 0
LEGACY = 1
MATCH = 2
INSN_COUNT = 3
INTERRUPT = 4
EXCEPTION = 5
mcontrol_layout = [
("load", 1),
("store", 1),
("execute", 1),
("u", 1),
("s", 1),
("zero0", 1),
("m", 1),
("match", 4),
("chain", 1),
("action", 4),
("size", 2),
("timing", 1),
("select", 1),
("hit", 1),
("maskmax", 6)
]
class TriggerUnit(Elaboratable, AutoCSR):
def __init__(self, nb_triggers):
if not isinstance(nb_triggers, int):
raise TypeError("Number of triggers must be an int, not {!r}"
.format(nb_triggers))
if nb_triggers == 0 or nb_triggers & nb_triggers - 1:
raise ValueError("Number of triggers must be a power of 2, not {!r}"
.format(nb_triggers))
self.nb_triggers = nb_triggers
self.tselect = CSR(0x7a0, flat_layout)
self.tdata1 = CSR(0x7a1, tdata1_layout)
self.tdata2 = CSR(0x7a2, flat_layout)
self.x_pc = Signal(32)
self.x_valid = Signal()
self.haltreq = Signal()
self.x_trap = Signal()
def elaborate(self, platform):
m = Module()
triggers = [Record.like(self.tdata1.r) for _ in range(self.nb_triggers)]
for t in triggers:
# We only support address/data match triggers.
m.d.comb += t.type.eq(Type.MATCH)
def do_trigger_update(trigger):
m.d.sync += trigger.dmode.eq(self.tdata1.w.dmode)
mcontrol = Record([("i", mcontrol_layout), ("o", mcontrol_layout)])
m.d.comb += [
mcontrol.i.eq(self.tdata1.w.data),
mcontrol.o.execute.eq(mcontrol.i.execute),
mcontrol.o.m.eq(mcontrol.i.m),
mcontrol.o.action.eq(mcontrol.i.action),
]
m.d.sync += trigger.data.eq(mcontrol.o)
with m.Switch(self.tselect.r.value):
for i, t in enumerate(triggers):
with m.Case(i):
m.d.comb += self.tdata1.r.eq(t)
with m.If(self.tdata1.we):
do_trigger_update(t)
with m.If(self.tselect.we):
with m.If(self.tselect.w.value & (self.nb_triggers - 1)):
m.d.sync += self.tselect.r.value.eq(self.tselect.w.value)
with m.If(self.tdata2.we):
m.d.sync += self.tdata2.r.eq(self.tdata2.w)
hit = Signal()
halt = Signal()
with m.Switch(self.tdata1.r.type):
with m.Case(Type.MATCH):
mcontrol = Record(mcontrol_layout)
m.d.comb += mcontrol.eq(self.tdata1.r.data)
match = Signal()
with m.If(mcontrol.execute):
m.d.comb += match.eq(self.tdata2.r == self.x_pc & self.x_valid)
m.d.comb += [
hit.eq(match & mcontrol.m),
halt.eq(mcontrol.action)
]
with m.If(hit):
with m.If(halt):
m.d.comb += self.haltreq.eq(self.tdata1.r.dmode)
with m.Else():
m.d.comb += self.x_trap.eq(1)
return m