118 lines
3.4 KiB
Python
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
|