-from migen.fhdl.std import *
-from migen.genlib.record import *
-from migen.genlib.fsm import FSM, NextState
-from migen.genlib.misc import chooser
-from migen.bank.description import *
+from litescope.common import *
from migen.bus import wishbone
+from migen.genlib.misc import chooser
from misoclib.uart import UARTRX, UARTTX
-from litescope.common import *
-
class UART(Module, AutoCSR):
def __init__(self, pads, clk_freq, baud=115200):
self._tuning_word = CSRStorage(32, reset=int((baud/clk_freq)*2**32))
-from migen.genlib.record import *
+from migen.fhdl.std import *
+from migen.bank.description import *
+from migen.genlib.fsm import FSM, NextState
+from migen.flow.actor import *
+from migen.actorlib.fifo import AsyncFIFO, SyncFIFO
+from migen.flow.plumbing import Buffer
+from migen.fhdl.specials import Memory
-def dat_layout(dw):
- return [
- ("stb", 1, DIR_M_TO_S),
- ("dat", dw, DIR_M_TO_S)
- ]
+def data_layout(dw):
+ return [("data", dw, DIR_M_TO_S)]
def hit_layout():
- return [
- ("stb", 1, DIR_M_TO_S),
- ("hit", 1, DIR_M_TO_S)
- ]
+ return [("hit", 1, DIR_M_TO_S)]
@DecorateModule(InsertReset)
@DecorateModule(InsertCE)
--- /dev/null
+from litescope.common import *
+
+class LiteScopeTerm(Module):
+ def __init__(self, dw):
+ self.dw = dw
+ self.sink = sink = Sink(data_layout(dw))
+ self.source = source = Source(hit_layout())
+
+ self.trig = Signal(dw)
+ self.mask = Signal(dw)
+ ###
+ self.comb += [
+ source.stb.eq(sink.stb),
+ source.hit.eq((sink.data & self.mask) == self.trig),
+ sink.ack.eq(source.ack)
+ ]
+
+class LiteScopeTermCSR(LiteScopeTerm, AutoCSR):
+ def __init__(self, dw):
+ LiteScopeTerm.__init__(self, dw)
+ self._trig = CSRStorage(dw)
+ self._mask = CSRStorage(dw)
+ ###
+ self.comb += [
+ self.trig.eq(self._trig.storage),
+ self.mask.eq(self._mask.storage)
+ ]
+
+class LiteScopeRangeDetector(Module):
+ def __init__(self, dw):
+ self.dw = dw
+ self.sink = sink = Sink(data_layout(dw))
+ self.source = source = Source(hit_layout())
+
+ self.low = Signal(dw)
+ self.high = Signal(dw)
+ ###
+ self.comb += [
+ source.stb.eq(sink.stb),
+ source.hit.eq((sink.data >= self.low) & (sink.data <= self.high)),
+ sink.ack.eq(source.ack)
+ ]
+
+class LiteScopeRangeDetectorCSR(LiteScopeRangeDetector, AutoCSR):
+ def __init__(self, dw):
+ LiteScopeRangeDetector.__init__(self, dw)
+ self._low = CSRStorage(dw)
+ self._high = CSRStorage(dw)
+ ###
+ self.comb += [
+ self.low.eq(self._low.storage),
+ self.high.eq(self._high.storage)
+ ]
+
+class LiteScopeEdgeDetector(Module):
+ def __init__(self, dw):
+ self.dw = dw
+ self.sink = sink = Sink(data_layout(dw))
+ self.source = source = Source(hit_layout())
+
+ self.rising_mask = Signal(dw)
+ self.falling_mask = Signal(dw)
+ self.both_mask = Signal(dw)
+ ###
+ self.buffer = Buffer(self.sink.description)
+ self.comb += Record.connect(self.sink, self.buffer.sink)
+
+ rising = Signal(dw)
+ rising.eq(self.rising_mask & sink.data & ~self.buffer.source.data)
+
+ falling = Signal(dw)
+ falling.eq(self.falling_mask & sink.data & ~self.buffer.source.data)
+
+ both = Signal(dw)
+ both.eq(self.both_mask & sink.data & ~self.buffer.source.data)
+
+ self.comb += [
+ source.stb.eq(sink.stb & self.buffer.source.stb),
+ self.buffer.source.ack.eq(source.ack),
+ source.hit.eq(rising | falling | both)
+ ]
+
+class LiteScopeEdgeDetectorCSR(LiteScopeEdgeDetector, AutoCSR):
+ def __init__(self, dw):
+ LiteScopeEdgeDetector.__init__(self, dw)
+ self._rising = CSRStorage(dw)
+ self._falling = CSRStorage(dw)
+ self._both = CSRStorage(dw)
+ ###
+ self.comb += [
+ self.rising.eq(self._rising.storage),
+ self.falling.eq(self._falling.storage),
+ self.both.eq(self._both.storage)
+ ]
-from migen.fhdl.std import *
-from migen.bank.description import *
-from migen.genlib.fifo import SyncFIFOBuffered as SyncFIFO
-from migen.genlib.fsm import FSM, NextState
-from migen.genlib.record import *
-
from litescope.common import *
-class LiteScopeRunLengthEncoder(Module, AutoCSR):
- def __init__(self, width, length=1024):
- self.width = width
+class LiteScopeRunLengthEncoder(Module):
+ def __init__(self, dw, length=1024):
+ self.dw = dw
self.length = length
- self.sink = Record(dat_layout(width))
- self.source = Record(dat_layout(width))
-
- self._enable = CSRStorage()
+ self.sink = sink = Sink(data_layout(dw))
+ self.source = source = Source(data_layout(dw))
+ self.enable = Signal()
###
-
- enable = self._enable.storage
-
- sink_d = Record(dat_layout(width))
- self.sync += If(self.sink.stb, sink_d.eq(self.sink))
+ sink_d = Sink(data_layout(dw))
+ self.sync += If(sink.stb, sink_d.eq(sink))
cnt = Signal(max=length)
cnt_inc = Signal()
self.comb += cnt_max.eq(cnt == length)
change = Signal()
- self.comb += change.eq(self.sink.stb & (self.sink.dat != sink_d.dat))
+ self.comb += change.eq(sink.stb & (sink.dat != sink_d.dat))
fsm = FSM(reset_state="BYPASS")
self.submodules += fsm
-
fsm.act("BYPASS",
- sink_d.connect(self.source),
+ Record.connect(sink_d, source),
cnt_reset.eq(1),
- If(enable & ~change & self.sink.stb, NextState("COUNT"))
+ If(self.enable & ~change & sink.stb, NextState("COUNT"))
)
-
fsm.act("COUNT",
- cnt_inc.eq(self.sink.stb),
- If(change | cnt_max | ~enable,
- self.source.stb.eq(1),
- self.source.dat[width-1].eq(1), # Set RLE bit
- self.source.dat[:flen(cnt)].eq(cnt),
+ cnt_inc.eq(sink.stb),
+ If(change | cnt_max | ~self.enable,
+ source.stb.eq(1),
+ source.dat[dw-1].eq(1), # Set RLE bit
+ source.dat[:flen(cnt)].eq(cnt),
NextState("BYPASS")
)
- ),
+ )
+
+class LiteScopeRunLengthEncoderCSR(Module, AutoCSR):
+ def __init__(self, rle):
+ self.submodules += rle
+ self._enable = CSRStorage()
+ ###
+ self.comb += rle.enable.eq(self_enable.storage)
class LiteScopeRecorder(Module, AutoCSR):
- def __init__(self, width, depth):
- self.width = width
+ def __init__(self, dw, depth):
+ self.dw = dw
- self.trig_sink = Record(hit_layout())
- self.dat_sink = Record(dat_layout(width))
+ self.trigger_sink = trigger_sink = Sink(hit_layout())
+ self.data_sink = data_sink = Sink(data_layout(dw))
self._trigger = CSR()
self._length = CSRStorage(bits_for(depth))
self._offset = CSRStorage(bits_for(depth))
self._done = CSRStatus()
- self._read_en = CSR()
- self._read_empty = CSRStatus()
- self._read_dat = CSRStatus(width)
+ self._source_stb = CSRStatus()
+ self._source_ack = CSR()
+ self._source_data = CSRStatus(dw)
###
- fifo = InsertReset(SyncFIFO(width, depth))
+ fifo = InsertReset(SyncFIFO(data_layout(dw), depth, buffered=True))
self.submodules += fifo
fsm = FSM(reset_state="IDLE")
self.submodules += fsm
-
-
self.comb += [
- self._read_empty.status.eq(~fifo.readable),
- self._read_dat.status.eq(fifo.dout),
+ self._source_stb.status.eq(fifo.source.stb),
+ self._source_data.status.eq(fifo.source.data)
]
-
fsm.act("IDLE",
- If(self._trigger.re & self._trigger.r,
+ self._done.status.eq(1),
+ If(self._trigger.re,
NextState("PRE_HIT_RECORDING"),
fifo.reset.eq(1),
),
- fifo.re.eq(self._read_en.re & self._read_en.r),
- self._done.status.eq(1)
+ fifo.source.ack.eq(self._source_ack.re)
)
-
fsm.act("PRE_HIT_RECORDING",
- fifo.we.eq(self.dat_sink.stb),
- fifo.din.eq(self.dat_sink.dat),
+ fifo.sink.stb.eq(data_sink.stb),
+ fifo.sink.data.eq(data_sink.data),
+ data_sink.ack.eq(fifo.sink.ack),
- fifo.re.eq(fifo.level >= self._offset.storage),
-
- If(self.trig_sink.stb & self.trig_sink.hit, NextState("POST_HIT_RECORDING"))
+ fifo.source.ack.eq(fifo.fifo.level >= self._offset.storage),
+ If(trigger_sink.stb & trigger_sink.hit, NextState("POST_HIT_RECORDING"))
)
-
fsm.act("POST_HIT_RECORDING",
- fifo.we.eq(self.dat_sink.stb),
- fifo.din.eq(self.dat_sink.dat),
+ fifo.sink.stb.eq(data_sink.stb),
+ fifo.sink.data.eq(data_sink.data),
+ data_sink.ack.eq(fifo.sink.ack),
- If(~fifo.writable | (fifo.level >= self._length.storage), NextState("IDLE"))
+ If(~fifo.sink.ack | (fifo.fifo.level >= self._length.storage), NextState("IDLE"))
)
-from migen.fhdl.std import *
-from migen.fhdl.specials import Memory
-from migen.bank.description import *
-from migen.genlib.record import *
-
from litescope.common import *
-class LiteScopeTerm(Module, AutoCSR):
- def __init__(self, width):
- self.width = width
-
- self.sink = Record(dat_layout(width))
- self.source = Record(hit_layout())
-
- self._trig = CSRStorage(width)
- self._mask = CSRStorage(width)
-
- ###
-
- trig = self._trig.storage
- mask = self._mask.storage
- dat = self.sink.dat
- hit = self.source.hit
-
- self.comb += [
- hit.eq((dat & mask) == trig),
- self.source.stb.eq(self.sink.stb)
- ]
-
-class LiteScopeRangeDetector(Module, AutoCSR):
- def __init__(self, width):
- self.width = width
-
- self.sink = Record(dat_layout(width))
- self.source = Record(hit_layout())
+class LiteScopeSum(Module, AutoCSR):
+ def __init__(self, ports):
+ self.sinks = sinks = [Sink(hit_layout()) for i in range(ports)]
+ self.source = source = Source(hit_layout())
- self._low = CSRStorage(width)
- self._high = CSRStorage(width)
+ self.prog_we = Signal()
+ self.prog_adr = Signal(ports)
+ self.prog_dat = Signal()
- ###
+ mem = Memory(1, 2**ports)
+ lut = mem.get_port()
+ prog = mem.get_port(write_capable=True)
+ self.specials += mem, lut, prog
- low = self._low.storage
- high = self._high.storage
- dat = self.sink.dat
- hit = self.source.hit
+ ###
+ # program port
self.comb += [
- hit.eq((dat >= low) & (dat <= high)),
- self.source.stb.eq(self.sink.stb)
+ prog.we.eq(self.prog_we),
+ prog.adr.eq(self.prog_adr),
+ prog.dat_w.eq(self.prog_dat)
]
-class LiteScopeEdgeDetector(Module, AutoCSR):
- def __init__(self, width):
- self.width = width
-
- self.sink = Record(dat_layout(width))
- self.source = Record(hit_layout())
-
- self._rising_mask = CSRStorage(width)
- self._falling_mask = CSRStorage(width)
- self._both_mask = CSRStorage(width)
-
- ###
-
- rising_mask = self._rising_mask.storage
- falling_mask = self._falling_mask.storage
- both_mask = self._both_mask.storage
-
- dat = self.sink.dat
- dat_d = Signal(width)
- rising_hit = Signal()
- falling_hit = Signal()
- both_hit = Signal()
- hit = self.source.hit
-
- self.sync += dat_d.eq(dat)
+ # LUT port
+ for i, sink in enumerate(sinks):
+ self.comb += lut.adr[i].eq(sink.hit)
+ # drive source
self.comb += [
- rising_hit.eq(rising_mask & dat & ~dat_d),
- falling_hit.eq(rising_mask & ~dat & dat_d),
- both_hit.eq((both_mask & dat) != (both_mask & dat_d)),
- hit.eq(rising_hit | falling_hit | both_hit),
- self.source.stb.eq(self.sink.stb)
+ source.stb.eq(optree("&", [sink.stb for sink in sinks])),
+ source.hit.eq(lut.dat_r)
]
-
-class LiteScopeSum(Module, AutoCSR):
- def __init__(self, ports=4):
-
- self.sinks = [Record(hit_layout()) for p in range(ports)]
- self.source = Record(hit_layout())
-
- self._prog_we = CSRStorage()
- self._prog_adr = CSRStorage(ports) #FIXME
+ for i, sink in enumerate(sinks):
+ self.comb += sink.ack.eq(sink.stb & source.ack)
+
+class LiteScopeSumCSR(Module, AutoCSR):
+ def __init__(self, ports):
+ LiteScopeSum.__init__(self, ports)
+ self._prog_we = CSR()
+ self._prog_adr = CSRStorage(ports)
self._prog_dat = CSRStorage()
-
- mem = Memory(1, 2**ports)
- lut_port = mem.get_port()
- prog_port = mem.get_port(write_capable=True)
-
- self.specials += mem, lut_port, prog_port
-
###
-
- # Lut prog
self.comb += [
- prog_port.we.eq(self._prog_we.storage),
- prog_port.adr.eq(self._prog_adr.storage),
- prog_port.dat_w.eq(self._prog_dat.storage)
+ self.prog_we.eq(self._prog_we.re & self._prog_we.r),
+ self.prog_adr.eq(self._prog_adr.storage),
+ self.prog_dat.eq(self._prog_dat.storage)
]
- # Lut read
- for i, sink in enumerate(self.sinks):
- self.comb += lut_port.adr[i].eq(sink.hit)
-
- # Drive source
- self.comb += [
- self.source.stb.eq(optree("&", [sink.stb for sink in self.sinks])),
- self.source.hit.eq(lut_port.dat_r),
- ]
-
-
class LiteScopeTrigger(Module, AutoCSR):
- def __init__(self, width, ports):
- self.width = width
- self.ports = ports
-
- self.submodules.sum = LiteScopeSum(len(ports))
- for i, port in enumerate(ports):
- setattr(self.submodules, "port"+str(i), port)
-
- self.sink = Record(dat_layout(width))
- self.source = self.sum.source
-
+ def __init__(self, dw):
+ self.dw = dw
+ self.ports = []
+ self.sink = Sink(data_layout(dw))
+ self.source = Source(hit_layout())
+
+ def add_port(self, port):
+ setattr(self.submodules, "port"+str(len(self.ports)), port)
+ self.ports.append(port)
+
+ def do_finalize(self):
+ self.submodules.sum = LiteScopeSumCSR(len(self.ports))
###
-
- for i, port in enumerate(ports):
+ for i, port in enumerate(self.ports):
+ # Note: port's ack is not used and supposed to be always 1
self.comb += [
- self.sink.connect(port.sink),
- port.source.connect(self.sum.sinks[i])
+ port.sink.stb.eq(self.sink.stb),
+ port.sink.data.eq(self.sink.data),
+ self.sink.ack.eq(1),
+ Record.connect(port.source, self.sum.sinks[i])
]
+ self.comb += Record.connect(self.sum.source, self.source)
-from migen.fhdl.structure import *
-from migen.bank.description import *
+from litescope.common import *
class LiteScopeIO(Module, AutoCSR):
def __init__(self, width):
-from migen.fhdl.std import *
-from migen.bank.description import *
-from migen.actorlib.fifo import AsyncFIFO
-
from litescope.common import *
from litescope.core.trigger import LiteScopeTrigger
from litescope.core.storage import LiteScopeRecorder, LiteScopeRunLengthEncoder
from mibuild.tools import write_to_file
-def _getattr_all(l, attr):
- it = iter(l)
- r = getattr(next(it), attr)
- for e in it:
- if getattr(e, attr) != r:
- raise ValueError
- return r
-
class LiteScopeLA(Module, AutoCSR):
- def __init__(self, depth, dat, with_rle=False, clk_domain="sys", pipe=False):
+ def __init__(self, layout, depth, clk_domain="sys", input_buffer=False, with_rle=False):
+ self.layout = layout
+ self.data = Cat(*layout)
+ self.dw = flen(self.data)
self.depth = depth
- if isinstance(dat, tuple):
- dat = Cat(*dat)
self.with_rle = with_rle
self.clk_domain = clk_domain
- self.pipe = pipe
- self.ports = []
- self.width = flen(dat)
+ self.input_buffer = input_buffer
- self.stb = Signal(reset=1)
- self.dat = dat
+ self.sink = Sink(data_layout(self.dw))
+ self.comb += [
+ self.sink.stb.eq(1),
+ self.sink.data.eq(self.data)
+ ]
- def add_port(self, port_class):
- port = port_class(self.width)
- self.ports.append(port)
+ self.submodules.trigger = trigger = LiteScopeTrigger(self.dw)
+ self.submodules.recorder = recorder = LiteScopeRecorder(self.dw, self.depth)
def do_finalize(self):
- stb = self.stb
- dat = self.dat
- if self.pipe:
- sync = getattr(self.sync, self.clk_domain)
- stb_new = Signal()
- dat_new = Signal(flen(dat))
- sync += [
- stb_new.eq(stb),
- dat_new.eq(dat)
- ]
- stb = stb_new
- dat = dat_new
+ # insert Buffer on sink (optional, can be used to improve timings)
+ if self.input_buffer:
+ self.submodules.buffer = Buffer(self.sink.description)
+ self.comb += Record.connect(self.sink, self.buffer.sink)
+ self.sink = self.buffer.source
+ # clock domain crossing (optional, required when capture_clk is not sys_clk)
+ # XXX : sys_clk must be faster than capture_clk, add Converter on data to remove this limitation
if self.clk_domain is not "sys":
- fifo = AsyncFIFO([("dat", self.width)], 32)
- self.submodules += RenameClockDomains(fifo, {"write": self.clk_domain, "read": "sys"})
- self.comb += [
- fifo.sink.stb.eq(stb),
- fifo.sink.dat.eq(dat)
- ]
- sink = Record(dat_layout(self.width))
- self.comb += [
- sink.stb.eq(fifo.source.stb),
- sink.dat.eq(fifo.source.dat),
- fifo.source.ack.eq(1)
- ]
- else:
- sink = Record(dat_layout(self.width))
- self.comb += [
- sink.stb.eq(stb),
- sink.dat.eq(dat)
- ]
+ self.submodules.fifo = AsyncFIFO(self.sink.description, 32)
+ self.submodules += RenameClockDomains(self.fifo, {"write": self.clk_domain, "read": "sys"})
+ self.comb += Record.connect(self.sink, self.fifo.sink)
+ self.sink = self.fifo.source
- self.submodules.trigger = trigger = LiteScopeTrigger(self.width, self.ports)
- self.submodules.recorder = recorder = LiteScopeRecorder(self.width, self.depth)
+ # connect everything
self.comb += [
- sink.connect(trigger.sink),
- trigger.source.connect(recorder.trig_sink)
+ self.trigger.sink.stb.eq(self.sink.stb),
+ self.trigger.sink.data.eq(self.sink.data),
+ Record.connect(self.trigger.source, self.recorder.trigger_sink)
]
-
if self.with_rle:
- self.submodules.rle = rle = LiteScopeRunLengthEncoder(self.width)
+ rle = LiteScopeRunLengthEncoder(self.dw)
+ self.submodules += rle
self.comb += [
- sink.connect(rle.sink),
- rle.source.connect(recorder.dat_sink)
+ Record.connect(self.sink, rle.sink),
+ Record.connect(rle.source, self.recorder.data_sink)
]
else:
- self.comb += sink.connect(recorder.dat_sink)
+ self.comb += Record.connect(self.sink, self.recorder.data_sink)
- def export(self, layout, vns, filename):
+ def export(self, vns, filename):
def format_line(*args):
return ",".join(args) + "\n"
r = ""
- r += format_line("config", "width", str(self.width))
+ r += format_line("config", "dw", str(self.dw))
r += format_line("config", "depth", str(self.depth))
r += format_line("config", "with_rle", str(int(self.with_rle)))
- for e in layout:
+ for e in self.layout:
r += format_line("layout", vns.get_name(e), str(flen(e)))
write_to_file(filename, r)
self.get_config()
self.get_layout()
self.build()
- self.dat = Dat(self.width)
+ self.dat = Dat(self.dw)
def get_config(self):
csv_reader = csv.reader(open(self.config_csv), delimiter=',', quotechar='#')
def read(self):
self.show_state("READ")
- empty = self.recorder_read_empty.read()
- while(not empty):
- self.dat.append(self.recorder_read_dat.read())
- empty = self.recorder_read_empty.read()
- self.recorder_read_en.write(1)
+ while self.recorder_source_stb.read():
+ self.dat.append(self.recorder_source_data.read())
+ self.recorder_source_ack.write(1)
if self.with_rle:
if self.use_rle:
self.dat = self.dat.decode_rle()
from litescope.bridge.uart2wb import LiteScopeUART2WB
from litescope.frontend.io import LiteScopeIO
from litescope.frontend.la import LiteScopeLA
-from litescope.core.trigger import LiteScopeTerm
+from litescope.core.port import LiteScopeTermCSR
class _CRG(Module):
def __init__(self, clk_in):
cnt0,
cnt1
)
- self.submodules.la = LiteScopeLA(512, self.debug)
- self.la.add_port(LiteScopeTerm)
+ self.submodules.la = LiteScopeLA(self.debug, 512)
+ self.la.trigger.add_port(LiteScopeTermCSR(self.la.dw))
atexit.register(self.exit, platform)
def exit(self, platform):
if platform.vns is not None:
- self.la.export(self.debug, platform.vns, "./test/la.csv")
+ self.la.export(platform.vns, "./test/la.csv")
default_subtarget = LiteScopeSoC