simplify code and use Sink/Source instead of records

This commit is contained in:
Florent Kermarrec 2015-01-25 13:41:09 +01:00
parent 6f7d85b95c
commit 4472dac603
9 changed files with 251 additions and 271 deletions

View File

@ -1,14 +1,9 @@
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))

View File

@ -1,16 +1,16 @@
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)

94
litescope/core/port.py Normal file
View File

@ -0,0 +1,94 @@
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)
]

View File

@ -1,27 +1,17 @@
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()
@ -37,78 +27,79 @@ class LiteScopeRunLengthEncoder(Module, AutoCSR):
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"))
)

View File

@ -1,140 +1,73 @@
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())
self._low = CSRStorage(width)
self._high = CSRStorage(width)
###
low = self._low.storage
high = self._high.storage
dat = self.sink.dat
hit = self.source.hit
self.comb += [
hit.eq((dat >= low) & (dat <= high)),
self.source.stb.eq(self.sink.stb)
]
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)
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)
]
class LiteScopeSum(Module, AutoCSR):
def __init__(self, ports=4):
def __init__(self, ports):
self.sinks = sinks = [Sink(hit_layout()) for i in range(ports)]
self.source = source = Source(hit_layout())
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
self._prog_dat = CSRStorage()
self.prog_we = Signal()
self.prog_adr = Signal(ports)
self.prog_dat = Signal()
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 = mem.get_port()
prog = mem.get_port(write_capable=True)
self.specials += mem, lut, prog
###
# Lut prog
# program port
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)
prog.we.eq(self.prog_we),
prog.adr.eq(self.prog_adr),
prog.dat_w.eq(self.prog_dat)
]
# Lut read
for i, sink in enumerate(self.sinks):
self.comb += lut_port.adr[i].eq(sink.hit)
# LUT port
for i, sink in enumerate(sinks):
self.comb += lut.adr[i].eq(sink.hit)
# Drive source
# drive source
self.comb += [
self.source.stb.eq(optree("&", [sink.stb for sink in self.sinks])),
self.source.hit.eq(lut_port.dat_r),
source.stb.eq(optree("&", [sink.stb for sink in sinks])),
source.hit.eq(lut.dat_r)
]
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()
###
self.comb += [
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)
]
class LiteScopeTrigger(Module, AutoCSR):
def __init__(self, width, ports):
self.width = width
self.ports = ports
def __init__(self, dw):
self.dw = dw
self.ports = []
self.sink = Sink(data_layout(dw))
self.source = Source(hit_layout())
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 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)

View File

@ -1,5 +1,4 @@
from migen.fhdl.structure import *
from migen.bank.description import *
from litescope.common import *
class LiteScopeIO(Module, AutoCSR):
def __init__(self, width):

View File

@ -1,96 +1,66 @@
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)

View File

@ -121,7 +121,7 @@ class LiteScopeLADriver():
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='#')
@ -208,11 +208,9 @@ class LiteScopeLADriver():
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()

View File

@ -11,7 +11,7 @@ from litescope.common import *
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):
@ -97,12 +97,12 @@ class LiteScopeSoC(GenSoC, AutoCSR):
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