core: Update code to LiteXModule and current coding style.

This commit is contained in:
Florent Kermarrec 2024-07-25 10:33:44 +02:00
parent 976656b519
commit 74ddd945c2
1 changed files with 57 additions and 38 deletions

View File

@ -1,7 +1,7 @@
# #
# This file is part of LiteScope. # This file is part of LiteScope.
# #
# Copyright (c) 2016-2019 Florent Kermarrec <florent@enjoy-digital.fr> # Copyright (c) 2016-2024 Florent Kermarrec <florent@enjoy-digital.fr>
# Copyright (c) 2018 bunnie <bunnie@kosagi.com> # Copyright (c) 2018 bunnie <bunnie@kosagi.com>
# Copyright (c) 2016 Tim 'mithro' Ansell <mithro@mithis.com> # Copyright (c) 2016 Tim 'mithro' Ansell <mithro@mithis.com>
# SPDX-License-Identifier: BSD-2-Clause # SPDX-License-Identifier: BSD-2-Clause
@ -9,16 +9,19 @@
from migen import * from migen import *
from migen.genlib.cdc import MultiReg, PulseSynchronizer from migen.genlib.cdc import MultiReg, PulseSynchronizer
from litex.gen import *
from litex.gen.genlib.misc import WaitTimer from litex.gen.genlib.misc import WaitTimer
from litex.build.tools import write_to_file from litex.build.tools import write_to_file
from litex.soc.interconnect.csr import * from litex.soc.interconnect.csr import *
from litex.soc.cores.gpio import GPIOInOut
from litex.soc.cores.gpio import GPIOInOut
from litex.soc.interconnect import stream from litex.soc.interconnect import stream
# LiteScope IO ------------------------------------------------------------------------------------- # LiteScope IO -------------------------------------------------------------------------------------
class LiteScopeIO(Module, AutoCSR): class LiteScopeIO(LiteXModule):
def __init__(self, data_width): def __init__(self, data_width):
self.data_width = data_width self.data_width = data_width
self.input = Signal(data_width) self.input = Signal(data_width)
@ -26,18 +29,19 @@ class LiteScopeIO(Module, AutoCSR):
# # # # # #
self.submodules.gpio = GPIOInOut(self.input, self.output) self.gpio = GPIOInOut(self.input, self.output)
def get_csrs(self): def get_csrs(self):
return self.gpio.get_csrs() return self.gpio.get_csrs()
# LiteScope Analyzer ------------------------------------------------------------------------------- # LiteScope Analyzer Constants/Layouts -------------------------------------------------------------
def core_layout(data_width): def core_layout(data_width):
return [("data", data_width), ("hit", 1)] return [("data", data_width), ("hit", 1)]
# LiteScope Analyzer Trigger -----------------------------------------------------------------------
class _Trigger(Module, AutoCSR): class _Trigger(LiteXModule):
def __init__(self, data_width, depth=16): def __init__(self, data_width, depth=16):
self.sink = sink = stream.Endpoint(core_layout(data_width)) self.sink = sink = stream.Endpoint(core_layout(data_width))
self.source = source = stream.Endpoint(core_layout(data_width)) self.source = source = stream.Endpoint(core_layout(data_width))
@ -52,17 +56,17 @@ class _Trigger(Module, AutoCSR):
# # # # # #
# Control re-synchronization # Control re-synchronization.
enable = Signal() enable = Signal()
enable_d = Signal() enable_d = Signal()
self.specials += MultiReg(self.enable.storage, enable, "scope") self.specials += MultiReg(self.enable.storage, enable, "scope")
self.sync.scope += enable_d.eq(enable) self.sync.scope += enable_d.eq(enable)
# Status re-synchronization # Status re-synchronization.
done = Signal() done = Signal()
self.specials += MultiReg(done, self.done.status) self.specials += MultiReg(done, self.done.status)
# Memory and configuration # Memory and configuration.
mem = stream.AsyncFIFO([("mask", data_width), ("value", data_width)], depth) mem = stream.AsyncFIFO([("mask", data_width), ("value", data_width)], depth)
mem = ClockDomainsRenamer({"write": "sys", "read": "scope"})(mem) mem = ClockDomainsRenamer({"write": "sys", "read": "scope"})(mem)
self.submodules += mem self.submodules += mem
@ -73,7 +77,7 @@ class _Trigger(Module, AutoCSR):
self.mem_full.status.eq(~mem.sink.ready) self.mem_full.status.eq(~mem.sink.ready)
] ]
# Hit and memory read/flush # Hit and memory read/flush.
hit = Signal() hit = Signal()
flush = WaitTimer(2*depth) flush = WaitTimer(2*depth)
flush = ClockDomainsRenamer("scope")(flush) flush = ClockDomainsRenamer("scope")(flush)
@ -84,15 +88,17 @@ class _Trigger(Module, AutoCSR):
mem.source.ready.eq((enable & hit) | ~flush.done), mem.source.ready.eq((enable & hit) | ~flush.done),
] ]
# Output # Output.
self.comb += [ self.comb += [
sink.connect(source), sink.connect(source),
# Done when all triggers have been consumed # Done when all triggers have been consumed.
done.eq(~mem.source.valid), done.eq(~mem.source.valid),
source.hit.eq(done) source.hit.eq(done)
] ]
class _SubSampler(Module, AutoCSR): # LiteScope Analyzer SubSampler --------------------------------------------------------------------
class _SubSampler(LiteXModule):
def __init__(self, data_width): def __init__(self, data_width):
self.sink = sink = stream.Endpoint(core_layout(data_width)) self.sink = sink = stream.Endpoint(core_layout(data_width))
self.source = source = stream.Endpoint(core_layout(data_width)) self.source = source = stream.Endpoint(core_layout(data_width))
@ -121,8 +127,9 @@ class _SubSampler(Module, AutoCSR):
source.valid.eq(sink.valid & done) source.valid.eq(sink.valid & done)
] ]
# LiteScope Analyzer Mux ---------------------------------------------------------------------------
class _Mux(Module, AutoCSR): class _Mux(LiteXModule):
def __init__(self, data_width, n): def __init__(self, data_width, n):
self.sinks = sinks = [stream.Endpoint(core_layout(data_width)) for i in range(n)] self.sinks = sinks = [stream.Endpoint(core_layout(data_width)) for i in range(n)]
self.source = source = stream.Endpoint(core_layout(data_width)) self.source = source = stream.Endpoint(core_layout(data_width))
@ -139,8 +146,9 @@ class _Mux(Module, AutoCSR):
cases[i] = sinks[i].connect(source) cases[i] = sinks[i].connect(source)
self.comb += Case(value, cases) self.comb += Case(value, cases)
# LiteScope Analyzer Storage -----------------------------------------------------------------------
class _Storage(Module, AutoCSR): class _Storage(LiteXModule):
def __init__(self, data_width, depth): def __init__(self, data_width, depth):
self.sink = sink = stream.Endpoint(core_layout(data_width)) self.sink = sink = stream.Endpoint(core_layout(data_width))
@ -156,7 +164,7 @@ class _Storage(Module, AutoCSR):
# # # # # #
# Control re-synchronization # Control re-synchronization.
enable = Signal() enable = Signal()
enable_d = Signal() enable_d = Signal()
self.specials += MultiReg(self.enable.storage, enable, "scope") self.specials += MultiReg(self.enable.storage, enable, "scope")
@ -167,28 +175,27 @@ class _Storage(Module, AutoCSR):
self.specials += MultiReg(self.length.storage, length, "scope") self.specials += MultiReg(self.length.storage, length, "scope")
self.specials += MultiReg(self.offset.storage, offset, "scope") self.specials += MultiReg(self.offset.storage, offset, "scope")
# Status re-synchronization # Status re-synchronization.
done = Signal() done = Signal()
level = Signal().like(self.mem_level.status) level = Signal().like(self.mem_level.status)
self.specials += MultiReg(done, self.done.status) self.specials += MultiReg(done, self.done.status)
self.specials += MultiReg(level, self.mem_level.status) self.specials += MultiReg(level, self.mem_level.status)
# Memory # Memory.
mem = stream.SyncFIFO([("data", data_width)], depth, buffered=True) mem = stream.SyncFIFO([("data", data_width)], depth, buffered=True)
mem = ClockDomainsRenamer("scope")(mem) mem = ClockDomainsRenamer("scope")(mem)
cdc = stream.AsyncFIFO([("data", data_width)], 4) cdc = stream.AsyncFIFO([("data", data_width)], 4)
cdc = ClockDomainsRenamer( cdc = ClockDomainsRenamer({"write": "scope", "read": "sys"})(cdc)
{"write": "scope", "read": "sys"})(cdc)
self.submodules += mem, cdc self.submodules += mem, cdc
self.comb += level.eq(mem.level) self.comb += level.eq(mem.level)
# Flush # Flush.
mem_flush = WaitTimer(depth) mem_flush = WaitTimer(depth)
mem_flush = ClockDomainsRenamer("scope")(mem_flush) mem_flush = ClockDomainsRenamer("scope")(mem_flush)
self.submodules += mem_flush self.submodules += mem_flush
# FSM # FSM.
fsm = FSM(reset_state="IDLE") fsm = FSM(reset_state="IDLE")
fsm = ClockDomainsRenamer("scope")(fsm) fsm = ClockDomainsRenamer("scope")(fsm)
self.submodules += fsm self.submodules += fsm
@ -222,7 +229,7 @@ class _Storage(Module, AutoCSR):
) )
) )
# Memory read # Memory read.
read_source = stream.Endpoint([("data", data_width)]) read_source = stream.Endpoint([("data", data_width)])
if data_width > read_width: if data_width > read_width:
pad_bits = - data_width % read_width pad_bits = - data_width % read_width
@ -238,9 +245,16 @@ class _Storage(Module, AutoCSR):
self.mem_data.status.eq(read_source.data) self.mem_data.status.eq(read_source.data)
] ]
# LiteScope Analyzer -------------------------------------------------------------------------------
class LiteScopeAnalyzer(Module, AutoCSR): class LiteScopeAnalyzer(LiteXModule):
def __init__(self, groups, depth, samplerate=1e12, clock_domain="sys", trigger_depth=16, register=False, csr_csv="analyzer.csv"): def __init__(self, groups, depth,
samplerate = 1e12,
clock_domain = "sys",
trigger_depth = 16,
register = False,
csr_csv = "analyzer.csv",
):
self.groups = groups = self.format_groups(groups) self.groups = groups = self.format_groups(groups)
self.depth = depth self.depth = depth
self.samplerate = int(samplerate) self.samplerate = int(samplerate)
@ -251,12 +265,13 @@ class LiteScopeAnalyzer(Module, AutoCSR):
# # # # # #
# Create scope clock domain # Create scope clock domain.
self.clock_domains.cd_scope = ClockDomain() self.cd_scope = ClockDomain()
self.comb += self.cd_scope.clk.eq(ClockSignal(clock_domain)) self.comb += self.cd_scope.clk.eq(ClockSignal(clock_domain))
# Mux # Mux.
self.submodules.mux = _Mux(data_width, len(groups)) # ----
self.mux = _Mux(data_width, len(groups))
sd = getattr(self.sync, clock_domain) sd = getattr(self.sync, clock_domain)
for i, signals in groups.items(): for i, signals in groups.items():
s = Cat(signals) s = Cat(signals)
@ -269,19 +284,23 @@ class LiteScopeAnalyzer(Module, AutoCSR):
self.mux.sinks[i].data.eq(s) self.mux.sinks[i].data.eq(s)
] ]
# Frontend # Frontend.
self.submodules.trigger = _Trigger(data_width, depth=trigger_depth) # ---------
self.submodules.subsampler = _SubSampler(data_width) self.trigger = _Trigger(data_width, depth=trigger_depth)
self.subsampler = _SubSampler(data_width)
# Storage # Storage.
self.submodules.storage = _Storage(data_width, depth) # --------
self.storage = _Storage(data_width, depth)
# Pipeline # Pipeline: Mux -> Trigger -> Subsampler -> Storage.
self.submodules.pipeline = stream.Pipeline( # --------------------------------------------------
self.mux.source, self.pipeline = stream.Pipeline(
self.mux,
self.trigger, self.trigger,
self.subsampler, self.subsampler,
self.storage.sink) self.storage,
)
def format_groups(self, groups): def format_groups(self, groups):
if not isinstance(groups, dict): if not isinstance(groups, dict):