From 470b6873ca2cf539be0699c387067b873485cb31 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 18 Nov 2020 13:06:55 +0100 Subject: [PATCH] interconnect/csr/EventManager: simpifly/cleanup code that documents CSRs and always enable documentation. A read_only mode has been added to CSRStatus to allow enabling writes on pending register and get the written data used to clear events. --- litex/soc/cores/i2s.py | 2 +- litex/soc/integration/export.py | 2 +- litex/soc/interconnect/csr.py | 11 +- litex/soc/interconnect/csr_eventmanager.py | 163 +++++++++------------ 4 files changed, 78 insertions(+), 100 deletions(-) diff --git a/litex/soc/cores/i2s.py b/litex/soc/cores/i2s.py index 7573006d4..5f51a1a95 100644 --- a/litex/soc/cores/i2s.py +++ b/litex/soc/cores/i2s.py @@ -198,7 +198,7 @@ class S7I2S(Module, AutoCSR, AutoDoc): ] # Interrupts - self.submodules.ev = EventManager(document_fields=document_interrupts) + self.submodules.ev = EventManager() if hasattr(pads, 'rx'): self.ev.rx_ready = EventSourcePulse(description="Indicates FIFO is ready to read") # Rising edge triggered self.ev.rx_error = EventSourcePulse(description="Indicates an Rx error has happened (over/underflow)") diff --git a/litex/soc/integration/export.py b/litex/soc/integration/export.py index 4d9b70c0e..f7a83a12e 100644 --- a/litex/soc/integration/export.py +++ b/litex/soc/integration/export.py @@ -219,7 +219,7 @@ def get_csr_header(regions, constants, csr_base=None, with_access_functions=True for csr in region.obj: nr = (csr.size + region.busword - 1)//region.busword r += _get_rw_functions_c(name + "_" + csr.name, origin, nr, region.busword, alignment, - isinstance(csr, CSRStatus), with_access_functions) + getattr(csr, "read_only", False), with_access_functions) origin += alignment//8*nr if hasattr(csr, "fields"): for field in csr.fields.fields: diff --git a/litex/soc/interconnect/csr.py b/litex/soc/interconnect/csr.py index 89f38d144..382d1bb92 100644 --- a/litex/soc/interconnect/csr.py +++ b/litex/soc/interconnect/csr.py @@ -286,16 +286,19 @@ class CSRStatus(_CompoundCSR): The value of the CSRStatus register. """ - def __init__(self, size=1, reset=0, fields=[], name=None, description=None): + def __init__(self, size=1, reset=0, fields=[], name=None, description=None, read_only=True): if fields != []: self.fields = CSRFieldAggregate(fields, CSRAccess.ReadOnly) size = self.fields.get_size() reset = self.fields.get_reset() _CompoundCSR.__init__(self, size, name) self.description = description + self.read_only = read_only self.status = Signal(self.size, reset=reset) self.we = Signal() self.re = Signal() + if not read_only: + self.r = Signal(self.size) for field in fields: self.comb += self.status[field.offset:field.offset + field.size].eq(getattr(self.fields, field.name)) @@ -306,8 +309,12 @@ class CSRStatus(_CompoundCSR): sc = CSR(nbits, self.name + str(i) if nwords > 1 else self.name) self.comb += sc.w.eq(self.status[i*busword:i*busword+nbits]) self.simple_csrs.append(sc) + if not self.read_only: + lo = i*busword + hi = lo+nbits + self.sync += If(sc.re, self.r[lo:hi].eq(sc.r)) self.comb += self.we.eq(sc.we) - self.comb += self.re.eq(sc.re) + self.sync += self.re.eq(sc.re) def read(self): """Read method for simulation.""" diff --git a/litex/soc/interconnect/csr_eventmanager.py b/litex/soc/interconnect/csr_eventmanager.py index d01a93eec..2c445ca77 100644 --- a/litex/soc/interconnect/csr_eventmanager.py +++ b/litex/soc/interconnect/csr_eventmanager.py @@ -135,116 +135,87 @@ class EventManager(Module, AutoCSR): asserted. """ - def __init__(self, document_fields=False): + def __init__(self): self.irq = Signal() - self.document_fields = document_fields def do_finalize(self): - def source_description(src): - if hasattr(src, "name") and src.name is not None: - base_text = "`1` if a `{}` event occurred. ".format(src.name) + sources_u = [v for k, v in xdir(self, True) if isinstance(v, _EventSource)] + sources = sorted(sources_u, key=lambda x: x.duid) + n = len(sources) + + # Common + def get_source_name(src, i): + r = getattr(src, "name", None) + if r is None: + r = f"event{i}" + return r + + def get_pending_source_description(src): + r = "" + if getattr(src, "name", None) is not None: + r += "`1` if a `{}` event occurred. ".format(src.name) else: - base_text = "`1` if a this particular event occurred. " - if hasattr(src, "description") and src.description is not None: + r += "`1` if a this particular event occurred. " + if getattr(src, "description", None) is not None: return src.description elif isinstance(src, EventSourceLevel): - return base_text + "This Event is **level triggered** when the signal is **high**." + return r + "This Event is **level triggered** when the signal is **high**." elif isinstance(src, EventSourcePulse): - return base_text + "This Event is triggered on a **rising** edge." + return r + "This Event is triggered on a **rising** edge." elif isinstance(src, EventSourceProcess): - return base_text + "This Event is triggered on a **falling** edge." + return r + "This Event is triggered on a **falling** edge." else: - return base_text + "This Event uses an unknown method of triggering." + return r + "This Event uses an unknown method of triggering." - sources_u = [v for k, v in xdir(self, True) if isinstance(v, _EventSource)] - sources = sorted(sources_u, key=lambda x: x.duid) - n = len(sources) + # Status register + fields = [] + for i, source in enumerate(sources): + # Get source name and use default if None. + name = get_source_name(source, i) + # Get description and use default description if None. + desc = getattr(source, "description", None) + if desc is None: + desc = "This register contains the current raw level of the {} event trigger. Writes to this register have no effect.".format(str(name)) + # Add CSRField + fields.append(CSRField(name=name, size=1, description=f"Level of the ``{name}`` event")) + self.status = CSRStatus(n, description=desc, fields=fields) - if self.document_fields: - # annotate status - fields = [] - for i, source in enumerate(sources): - if source.description == None: - desc = "This register contains the current raw level of the {} event trigger. Writes to this register have no effect.".format(str(source.name)) - else: - desc = source.description + # Pending Register + fields = [] + for i, source in enumerate(sources): + # Get source name and use default if None. + name = get_source_name(source, i) + # Get description and use default description if None. + desc = getattr(source, "description", None) + if desc is None: + desc = "When a {} event occurs, the corresponding bit will be set in this register. To clear the Event, set the corresponding bit in this register.".format(str(name)) + # Add CSRField + fields.append(CSRField(name=name, size=1, description=get_pending_source_description(source))) + self.pending = CSRStatus(n, description=desc, fields=fields, read_only=False) - if hasattr(source, "name") and source.name is not None: - fields.append(CSRField( - name=source.name, - size=1, - description="Level of the ``{}`` event".format(source.name))) - else: - fields.append(CSRField( - name="event{}".format(i), - size=1, - description="Level of the ``event{}`` event".format(i))) - self.status = CSRStatus(n, description=desc, fields=fields) - - # annotate pending - fields = [] - for i, source in enumerate(sources): - if source.description is None: - desc = "When a {} event occurs, the corresponding bit will be set in this register. To clear the Event, set the corresponding bit in this register.".format(str(source.name)) - else: - desc = source.description - - if hasattr(source, "name") and source.name is not None: - fields.append(CSRField( - name=source.name, - size=1, - description=source_description(source))) - else: - fields.append(CSRField( - name="event{}".format(i), - size=1, - description=source_description(source))) - self.pending = CSRStatus(n, description=desc, fields=fields) - - # annotate enable - fields = [] - for i, source in enumerate(sources): - if source.description is None: - desc = "This register enables the corresponding {} events. Write a ``0`` to this register to disable individual events.".format(str(source.name)) - else: - desc = source.description - if hasattr(source, "name") and source.name is not None: - fields.append(CSRField( - name=source.name, - offset=i, - description="Write a ``1`` to enable the ``{}`` Event".format(source.name))) - else: - fields.append(CSRField( - name="event{}".format(i), - offset=i, - description="Write a ``1`` to enable the ``{}`` Event".format(i))) - self.enable = CSRStorage(n, description=desc, fields=fields) - - for i, source in enumerate(sources): - if source.name == None: - src_name = "event{}".format(i) - else: - src_name = source.name - self.comb += [ - getattr(self.status.fields, src_name).eq(source.status), - getattr(self.pending.fields, src_name).eq(source.pending), - If(self.pending.re & getattr(self.pending.fields, src_name), source.clear.eq(1)), - ] + # Enable Register + fields = [] + for i, source in enumerate(sources): + # Get source name and use default if None. + name = get_source_name(source, i) + # Get description and use default description if None. + desc = getattr(source, "description", None) + if desc is None: + desc = "This register enables the corresponding {} events. Write a ``0`` to this register to disable individual events.".format(str(name)) + # Add CSRField + fields.append(CSRField(name=name, offset=i, description=f"Write a ``1`` to enable the ``{name}`` Event")) + self.enable = CSRStorage(n, description=desc, fields=fields) + # Connect Events/Fields + for i, source in enumerate(sources): + # Get source name and use default if None. + name = get_source_name(source, i) + self.comb += [ + getattr(self.status.fields, name).eq(source.status), + getattr(self.pending.fields, name).eq(source.pending), + If(self.pending.re & self.pending.r[i], source.clear.eq(1)), + ] irqs = [self.pending.status[i] & self.enable.storage[i] for i in range(n)] - else: - self.status = CSR(n) - self.pending = CSR(n) - self.enable = CSRStorage(n) - - for i, source in enumerate(sources): - self.comb += [ - self.status.w[i].eq(source.status), - If(self.pending.re & self.pending.r[i], source.clear.eq(1)), - self.pending.w[i].eq(source.pending) - ] - - irqs = [self.pending.w[i] & self.enable.storage[i] for i in range(n)] self.comb += self.irq.eq(reduce(or_, irqs)) def __setattr__(self, name, value):