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 litescope.common 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 migen.bus import wishbone from migen.bus import wishbone
from migen.genlib.misc import chooser
from misoclib.uart import UARTRX, UARTTX from misoclib.uart import UARTRX, UARTTX
from litescope.common import *
class UART(Module, AutoCSR): class UART(Module, AutoCSR):
def __init__(self, pads, clk_freq, baud=115200): def __init__(self, pads, clk_freq, baud=115200):
self._tuning_word = CSRStorage(32, reset=int((baud/clk_freq)*2**32)) 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): def data_layout(dw):
return [ return [("data", dw, DIR_M_TO_S)]
("stb", 1, DIR_M_TO_S),
("dat", dw, DIR_M_TO_S)
]
def hit_layout(): def hit_layout():
return [ return [("hit", 1, DIR_M_TO_S)]
("stb", 1, DIR_M_TO_S),
("hit", 1, DIR_M_TO_S)
]
@DecorateModule(InsertReset) @DecorateModule(InsertReset)
@DecorateModule(InsertCE) @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 * from litescope.common import *
class LiteScopeRunLengthEncoder(Module, AutoCSR): class LiteScopeRunLengthEncoder(Module):
def __init__(self, width, length=1024): def __init__(self, dw, length=1024):
self.width = width self.dw = dw
self.length = length self.length = length
self.sink = Record(dat_layout(width)) self.sink = sink = Sink(data_layout(dw))
self.source = Record(dat_layout(width)) self.source = source = Source(data_layout(dw))
self._enable = CSRStorage()
self.enable = Signal()
### ###
sink_d = Sink(data_layout(dw))
enable = self._enable.storage self.sync += If(sink.stb, sink_d.eq(sink))
sink_d = Record(dat_layout(width))
self.sync += If(self.sink.stb, sink_d.eq(self.sink))
cnt = Signal(max=length) cnt = Signal(max=length)
cnt_inc = Signal() cnt_inc = Signal()
@ -37,78 +27,79 @@ class LiteScopeRunLengthEncoder(Module, AutoCSR):
self.comb += cnt_max.eq(cnt == length) self.comb += cnt_max.eq(cnt == length)
change = Signal() 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") fsm = FSM(reset_state="BYPASS")
self.submodules += fsm self.submodules += fsm
fsm.act("BYPASS", fsm.act("BYPASS",
sink_d.connect(self.source), Record.connect(sink_d, source),
cnt_reset.eq(1), cnt_reset.eq(1),
If(enable & ~change & self.sink.stb, NextState("COUNT")) If(self.enable & ~change & sink.stb, NextState("COUNT"))
) )
fsm.act("COUNT", fsm.act("COUNT",
cnt_inc.eq(self.sink.stb), cnt_inc.eq(sink.stb),
If(change | cnt_max | ~enable, If(change | cnt_max | ~self.enable,
self.source.stb.eq(1), source.stb.eq(1),
self.source.dat[width-1].eq(1), # Set RLE bit source.dat[dw-1].eq(1), # Set RLE bit
self.source.dat[:flen(cnt)].eq(cnt), source.dat[:flen(cnt)].eq(cnt),
NextState("BYPASS") 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): class LiteScopeRecorder(Module, AutoCSR):
def __init__(self, width, depth): def __init__(self, dw, depth):
self.width = width self.dw = dw
self.trig_sink = Record(hit_layout()) self.trigger_sink = trigger_sink = Sink(hit_layout())
self.dat_sink = Record(dat_layout(width)) self.data_sink = data_sink = Sink(data_layout(dw))
self._trigger = CSR() self._trigger = CSR()
self._length = CSRStorage(bits_for(depth)) self._length = CSRStorage(bits_for(depth))
self._offset = CSRStorage(bits_for(depth)) self._offset = CSRStorage(bits_for(depth))
self._done = CSRStatus() self._done = CSRStatus()
self._read_en = CSR() self._source_stb = CSRStatus()
self._read_empty = CSRStatus() self._source_ack = CSR()
self._read_dat = CSRStatus(width) self._source_data = CSRStatus(dw)
### ###
fifo = InsertReset(SyncFIFO(width, depth)) fifo = InsertReset(SyncFIFO(data_layout(dw), depth, buffered=True))
self.submodules += fifo self.submodules += fifo
fsm = FSM(reset_state="IDLE") fsm = FSM(reset_state="IDLE")
self.submodules += fsm self.submodules += fsm
self.comb += [ self.comb += [
self._read_empty.status.eq(~fifo.readable), self._source_stb.status.eq(fifo.source.stb),
self._read_dat.status.eq(fifo.dout), self._source_data.status.eq(fifo.source.data)
] ]
fsm.act("IDLE", fsm.act("IDLE",
If(self._trigger.re & self._trigger.r, self._done.status.eq(1),
If(self._trigger.re,
NextState("PRE_HIT_RECORDING"), NextState("PRE_HIT_RECORDING"),
fifo.reset.eq(1), fifo.reset.eq(1),
), ),
fifo.re.eq(self._read_en.re & self._read_en.r), fifo.source.ack.eq(self._source_ack.re)
self._done.status.eq(1)
) )
fsm.act("PRE_HIT_RECORDING", fsm.act("PRE_HIT_RECORDING",
fifo.we.eq(self.dat_sink.stb), fifo.sink.stb.eq(data_sink.stb),
fifo.din.eq(self.dat_sink.dat), fifo.sink.data.eq(data_sink.data),
data_sink.ack.eq(fifo.sink.ack),
fifo.re.eq(fifo.level >= self._offset.storage), fifo.source.ack.eq(fifo.fifo.level >= self._offset.storage),
If(trigger_sink.stb & trigger_sink.hit, NextState("POST_HIT_RECORDING"))
If(self.trig_sink.stb & self.trig_sink.hit, NextState("POST_HIT_RECORDING"))
) )
fsm.act("POST_HIT_RECORDING", fsm.act("POST_HIT_RECORDING",
fifo.we.eq(self.dat_sink.stb), fifo.sink.stb.eq(data_sink.stb),
fifo.din.eq(self.dat_sink.dat), 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 * 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): 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.prog_we = Signal()
self.source = Record(hit_layout()) self.prog_adr = Signal(ports)
self.prog_dat = Signal()
self._prog_we = CSRStorage()
self._prog_adr = CSRStorage(ports) #FIXME
self._prog_dat = CSRStorage()
mem = Memory(1, 2**ports) mem = Memory(1, 2**ports)
lut_port = mem.get_port() lut = mem.get_port()
prog_port = mem.get_port(write_capable=True) prog = mem.get_port(write_capable=True)
self.specials += mem, lut, prog
self.specials += mem, lut_port, prog_port
### ###
# Lut prog # program port
self.comb += [ self.comb += [
prog_port.we.eq(self._prog_we.storage), prog.we.eq(self.prog_we),
prog_port.adr.eq(self._prog_adr.storage), prog.adr.eq(self.prog_adr),
prog_port.dat_w.eq(self._prog_dat.storage) prog.dat_w.eq(self.prog_dat)
] ]
# Lut read # LUT port
for i, sink in enumerate(self.sinks): for i, sink in enumerate(sinks):
self.comb += lut_port.adr[i].eq(sink.hit) self.comb += lut.adr[i].eq(sink.hit)
# Drive source # drive source
self.comb += [ self.comb += [
self.source.stb.eq(optree("&", [sink.stb for sink in self.sinks])), source.stb.eq(optree("&", [sink.stb for sink in sinks])),
self.source.hit.eq(lut_port.dat_r), 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): class LiteScopeTrigger(Module, AutoCSR):
def __init__(self, width, ports): def __init__(self, dw):
self.width = width self.dw = dw
self.ports = ports self.ports = []
self.sink = Sink(data_layout(dw))
self.source = Source(hit_layout())
self.submodules.sum = LiteScopeSum(len(ports)) def add_port(self, port):
for i, port in enumerate(ports): setattr(self.submodules, "port"+str(len(self.ports)), port)
setattr(self.submodules, "port"+str(i), port) self.ports.append(port)
self.sink = Record(dat_layout(width))
self.source = self.sum.source
def do_finalize(self):
self.submodules.sum = LiteScopeSumCSR(len(self.ports))
### ###
for i, port in enumerate(self.ports):
for i, port in enumerate(ports): # Note: port's ack is not used and supposed to be always 1
self.comb += [ self.comb += [
self.sink.connect(port.sink), port.sink.stb.eq(self.sink.stb),
port.source.connect(self.sum.sinks[i]) 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 litescope.common import *
from migen.bank.description import *
class LiteScopeIO(Module, AutoCSR): class LiteScopeIO(Module, AutoCSR):
def __init__(self, width): 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.common import *
from litescope.core.trigger import LiteScopeTrigger from litescope.core.trigger import LiteScopeTrigger
from litescope.core.storage import LiteScopeRecorder, LiteScopeRunLengthEncoder from litescope.core.storage import LiteScopeRecorder, LiteScopeRunLengthEncoder
from mibuild.tools import write_to_file 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): 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 self.depth = depth
if isinstance(dat, tuple):
dat = Cat(*dat)
self.with_rle = with_rle self.with_rle = with_rle
self.clk_domain = clk_domain self.clk_domain = clk_domain
self.pipe = pipe self.input_buffer = input_buffer
self.ports = []
self.width = flen(dat)
self.stb = Signal(reset=1) self.sink = Sink(data_layout(self.dw))
self.dat = dat
def add_port(self, port_class):
port = port_class(self.width)
self.ports.append(port)
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
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.trigger = trigger = LiteScopeTrigger(self.width, self.ports)
self.submodules.recorder = recorder = LiteScopeRecorder(self.width, self.depth)
self.comb += [ self.comb += [
sink.connect(trigger.sink), self.sink.stb.eq(1),
trigger.source.connect(recorder.trig_sink) self.sink.data.eq(self.data)
] ]
self.submodules.trigger = trigger = LiteScopeTrigger(self.dw)
self.submodules.recorder = recorder = LiteScopeRecorder(self.dw, self.depth)
def do_finalize(self):
# 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":
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
# connect everything
self.comb += [
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: if self.with_rle:
self.submodules.rle = rle = LiteScopeRunLengthEncoder(self.width) rle = LiteScopeRunLengthEncoder(self.dw)
self.submodules += rle
self.comb += [ self.comb += [
sink.connect(rle.sink), Record.connect(self.sink, rle.sink),
rle.source.connect(recorder.dat_sink) Record.connect(rle.source, self.recorder.data_sink)
] ]
else: 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): def format_line(*args):
return ",".join(args) + "\n" return ",".join(args) + "\n"
r = "" 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", "depth", str(self.depth))
r += format_line("config", "with_rle", str(int(self.with_rle))) 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))) r += format_line("layout", vns.get_name(e), str(flen(e)))
write_to_file(filename, r) write_to_file(filename, r)

View File

@ -121,7 +121,7 @@ class LiteScopeLADriver():
self.get_config() self.get_config()
self.get_layout() self.get_layout()
self.build() self.build()
self.dat = Dat(self.width) self.dat = Dat(self.dw)
def get_config(self): def get_config(self):
csv_reader = csv.reader(open(self.config_csv), delimiter=',', quotechar='#') csv_reader = csv.reader(open(self.config_csv), delimiter=',', quotechar='#')
@ -208,11 +208,9 @@ class LiteScopeLADriver():
def read(self): def read(self):
self.show_state("READ") self.show_state("READ")
empty = self.recorder_read_empty.read() while self.recorder_source_stb.read():
while(not empty): self.dat.append(self.recorder_source_data.read())
self.dat.append(self.recorder_read_dat.read()) self.recorder_source_ack.write(1)
empty = self.recorder_read_empty.read()
self.recorder_read_en.write(1)
if self.with_rle: if self.with_rle:
if self.use_rle: if self.use_rle:
self.dat = self.dat.decode_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.bridge.uart2wb import LiteScopeUART2WB
from litescope.frontend.io import LiteScopeIO from litescope.frontend.io import LiteScopeIO
from litescope.frontend.la import LiteScopeLA from litescope.frontend.la import LiteScopeLA
from litescope.core.trigger import LiteScopeTerm from litescope.core.port import LiteScopeTermCSR
class _CRG(Module): class _CRG(Module):
def __init__(self, clk_in): def __init__(self, clk_in):
@ -97,12 +97,12 @@ class LiteScopeSoC(GenSoC, AutoCSR):
cnt0, cnt0,
cnt1 cnt1
) )
self.submodules.la = LiteScopeLA(512, self.debug) self.submodules.la = LiteScopeLA(self.debug, 512)
self.la.add_port(LiteScopeTerm) self.la.trigger.add_port(LiteScopeTermCSR(self.la.dw))
atexit.register(self.exit, platform) atexit.register(self.exit, platform)
def exit(self, platform): def exit(self, platform):
if platform.vns is not None: 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 default_subtarget = LiteScopeSoC