litex/miscope/trigger.py

319 lines
7.7 KiB
Python

from migen.fhdl.structure import *
from migen.fhdl.specials import Memory
from migen.bus import csr
from migen.bank import description, csrgen
from migen.bank.description import *
from migen.genlib.misc import optree
class RegParams:
def __init__(self, name, base, width, nb):
self.name = name
self.base = base
self.width = width
self.nb = nb
self.size = nb*width
self.words = int(2**bits_for(self.width-1)/8)
def list_regs(objects):
r = []
for object in objects:
if "_reg" in object:
r.append(objects[object])
return r
class Term:
#
# Definition
#
def __init__(self, width):
self.width = width
self.interface = None
self.i = Signal(width)
self.t = Signal(width)
self.m = Signal(width)
self.o = Signal()
self.reg_p = RegParams("term_reg", 0, width, 2)
self.reg = None
def get_registers_comb(self):
comb = [self.t.eq(self.reg.field.r[0*self.width:1*self.width])]
comb += [self.m.eq(self.reg.field.r[1*self.width:2*self.width])]
return comb
def get_fragment(self):
comb = [self.o.eq((self.m & self.i) == self.t)]
comb += self.get_registers_comb()
return Fragment(comb)
#
# Driver
#
def set(self, dat, mask=None):
if mask is None:
mask = (2**self.width)-1
self.interface.write_n(self.reg_p.base, mask, self.width)
self.interface.write_n(self.reg_p.base + self.reg_p.words, dat, self.width)
class RangeDetector:
#
# Definition
#
def __init__(self, width):
self.width = width
self.pipe = pipe
self.interface = None
self.reg_p = RegParams("range_reg", 0, width, 2)
self.reg = None
self.i = Signal(width)
self.low = Signal(width)
self.high = Signal(width)
self.o = Signal()
def get_registers_comb(self):
comb = [self.low.eq(self.reg.field.r[0*self.width:1*self.width])]
comb += [self.low.eq(self.reg.field.r[1*self.width:2*self.width])]
return comb
def get_fragment(self):
comb = [self.o.eq((self.i >= self.low) & (self.i <= self.high))]
comb += self.get_registers_comb()
return Fragment(comb)
#
# Driver
#
def set_low(self, dat):
self.interface.write_n(self.reg_p.base, dat ,self.width)
def set_high(self, dat):
self.interface.write_n(self.reg_p.base + self.reg_p.words, dat ,self.width)
class EdgeDetector:
#
# Definition
#
def __init__(self, width, mode = "RFB"):
self.width = width
self.mode = mode
self.interface = None
self.reg_p = RegParams("edge_reg", 0, width, len(self.mode))
self.reg = None
self.i = Signal(self.width)
self.i_d = Signal(self.width)
if "R" in self.mode:
self.r_mask = Signal(self.width)
self.ro = Signal()
if "F" in self.mode:
self.f_mask = Signal(self.width)
self.fo = Signal()
if "B" in self.mode:
self.b_mask = Signal(self.width)
self.bo = Signal()
self.o = Signal()
def get_registers_comb(self):
comb = []
i = 0
if "R" in self.mode:
comb += [self.r_mask.eq(self.reg.field.r[i*self.width:(i+1)*self.width])]
i += 1
if "F" in self.mode:
comb += [self.f_mask.eq(self.reg.field.r[i*self.width:(i+1)*self.width])]
i += 1
if "B" in self.mode:
comb += [self.b_mask.eq(self.reg.field.r[i*self.width:(i+1)*self.width])]
i += 1
return comb
def get_fragment(self):
comb = []
sync = [self.i_d.eq(self.i)]
# Rising Edge
if "R" in self.mode:
comb += [self.ro.eq(self.r_mask & self.i & (~self.i_d))]
else:
comb += [self.ro.eq(0)]
# Falling Edge
if "F" in self.mode:
comb += [self.fo.eq(self.f_mask & (~self.i) & self.i_d)]
else:
comb += [self.fo.eq(0)]
# Both
if "B" in self.mode:
comb += [self.bo.eq((self.b_mask & self.i) != self.i_d)]
else:
comb += [self.bo.eq(0)]
# Output
comb += [self.o.eq(self.ro | self.fo | self.bo)]
# Registers
comb += self.get_registers_comb()
return Fragment(comb, sync)
#
# Driver
#
def get_offset(self, type):
if type == "R":
r = 0
r = r + self.words if "F" in self.mode else r
r = r + self.words if "B" in self.mode else r
return r
elif type == "F":
r = 0
r = r + self.words if "B" in self.mode else r
return r
elif type == "B":
r = 0
return r
return 0
def set_r(self, dat):
self.interface.write_n(self.reg_p.base + self.get_offset("R"), dat ,self.width)
def set_f(self, dat):
self.interface.write_n(self.reg_p.base + self.get_offset("F"), dat ,self.width)
def set_b(self, dat):
self.interface.write_n(self.reg_p.base + self.get_offset("B"), dat ,self.width)
class Sum:
#
# Definition
#
def __init__(self, width=4):
self.width = width
self.interface = None
self.i = Signal(self.width)
self._o = Signal()
self.o = Signal()
self.reg_p = RegParams("sum_reg", 0, 8, 4)
self.reg = None
self.prog_stb = Signal()
self.prog_adr = Signal(width)
self.prog_dat = Signal()
self._mem = Memory(1, 2**self.width)
self._lut_port = self._mem.get_port()
self._prog_port = self._mem.get_port(write_capable=True)
def get_registers_comb(self):
comb = [
self.prog_adr.eq(self.reg.field.r[0:16]),
self.prog_dat.eq(self.reg.field.r[16]),
self.prog_stb.eq(self.reg.field.r[17])
]
return comb
def get_fragment(self):
comb = [
self._lut_port.adr.eq(self.i),
self._o.eq(self._lut_port.dat_r),
self._prog_port.adr.eq(self.prog_adr),
self._prog_port.we.eq(self.prog_stb),
self._prog_port.dat_w.eq(self.prog_dat),
self.o.eq(self._o)
]
comb += self.get_registers_comb()
return Fragment(comb, specials={self._mem})
#
# Driver
#
def set(self, truth_table):
for i in range(len(truth_table)):
val = truth_table[i]
we = 1<<17
dat = val<<16
addr = i
self.interface.write_n(self.reg_p.base, we + dat + addr, self.reg_p.size)
self.interface.write_n(self.reg_p.base, dat + addr, self.reg_p.size)
class Trigger:
#
# Definition
#
def __init__(self, trig_w, ports, address=0x0000, interface=None):
self.trig_w = trig_w
self.ports = ports
self.sum = Sum(len(ports))
self.trig = Signal(self.trig_w)
self.hit = Signal()
# insert port number in port reg name
for i in range(len(self.ports)):
self.ports[i].reg_p.name += "_%d"%i
# generate ports csr registers fields
for port in self.ports:
rf = RegisterField(port.reg_p.name, port.reg_p.size, reset=0,
access_bus=WRITE_ONLY, access_dev=READ_ONLY)
setattr(self, port.reg_p.name, rf)
# generate sum csr registers fields
self.sum_reg = RegisterField(self.sum.reg_p.name, self.sum.reg_p.size, reset=0,
access_bus=WRITE_ONLY, access_dev=READ_ONLY)
# generate registers
self.regs = list_regs(self.__dict__)
self.bank = csrgen.Bank(self.regs, address=address)
# update base addr & interface
self.set_address(address)
self.set_interface(interface)
self.set_registers()
def set_address(self, address):
self.address = address
self.bank = csrgen.Bank(self.regs, address=self.address)
for port in self.ports:
port.reg_p.base = self.bank.get_base(port.reg_p.name)
self.sum.reg_p.base = self.bank.get_base(self.sum.reg_p.name)
def set_interface(self, interface):
self.interface = interface
for port in self.ports:
port.interface = self.interface
self.sum.interface = self.interface
def set_registers(self):
self.sum.reg=self.sum_reg
for port in self.ports:
port.reg=getattr(self, port.reg_p.name)
def get_fragment(self):
# connect trig to input of each trig element
comb = [port.i.eq(self.trig) for port in self.ports]
# connect output of trig elements to sum
comb += [self.sum.i[j].eq(self.ports[j].o) for j in range(len(self.ports))]
# connect sum ouput to hit
comb += [self.hit.eq(self.sum.o)]
# add ports & sum to frag
frag = self.bank.get_fragment()
frag += self.sum.get_fragment()
for port in self.ports:
frag += port.get_fragment()
return frag + Fragment(comb)