From 6deb750d6e3fa844565e7c80bf5234fd3f4d26a1 Mon Sep 17 00:00:00 2001 From: bunnie Date: Sun, 15 Nov 2020 16:33:14 +0800 Subject: [PATCH 1/7] Improve soc.svd output for eventmanager events Right now no data is created for which bit means what in the soc.svd file. Attempt to extend event manager finalization to use "fields" instead of bit positions, so that the SVD file can auto-generate the events correctly. --- litex/soc/interconnect/csr_eventmanager.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/litex/soc/interconnect/csr_eventmanager.py b/litex/soc/interconnect/csr_eventmanager.py index c291869f6..b7bc664fe 100644 --- a/litex/soc/interconnect/csr_eventmanager.py +++ b/litex/soc/interconnect/csr_eventmanager.py @@ -142,18 +142,22 @@ class EventManager(Module, AutoCSR): 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) - self.status = CSR(n) - self.pending = CSR(n) - self.enable = CSRStorage(n) + + fields = [] + for i, source in enumerate(sources): + fields += [CSRField(source.name, size=1, description="Mask bit for {}".format(str(source.name)))] + self.status = CSRStatus(n, fields=fields) + self.pending = CSRStatus(n, fields=fields) + self.enable = CSRStorage(n, fields=fields) 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) + getattr(self.status.fields, source.name).eq(source.status), + getattr(self.pending.fields, source.name).eq(source.pending), + If(self.pending.re & getattr(self.pending.fields, source.name), source.clear.eq(1)), ] - irqs = [self.pending.w[i] & self.enable.storage[i] for i in range(n)] + irqs = [self.pending.status[i] & self.enable.storage[i] for i in range(n)] self.comb += self.irq.eq(reduce(or_, irqs)) def __setattr__(self, name, value): From 6a0a896e9660a255f273b5002eacba2e96adb94a Mon Sep 17 00:00:00 2001 From: bunnie Date: Sun, 15 Nov 2020 17:07:33 +0800 Subject: [PATCH 2/7] improve documentation output --- litex/soc/interconnect/csr_eventmanager.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/litex/soc/interconnect/csr_eventmanager.py b/litex/soc/interconnect/csr_eventmanager.py index b7bc664fe..53cb3884d 100644 --- a/litex/soc/interconnect/csr_eventmanager.py +++ b/litex/soc/interconnect/csr_eventmanager.py @@ -145,8 +145,16 @@ class EventManager(Module, AutoCSR): fields = [] for i, source in enumerate(sources): - fields += [CSRField(source.name, size=1, description="Mask bit for {}".format(str(source.name)))] + if source.description == None: + desc = "Mask bit for {}".format(str(source.name)) + else: + desc = source.description + fields += [CSRField(source.name, size=1, description=desc)] self.status = CSRStatus(n, fields=fields) + fields = [] + for i, source in enumerate(sources): + desc = "Mask bit for {}".format(str(source.name)) + fields += [CSRField(source.name, size=1, description=desc)] self.pending = CSRStatus(n, fields=fields) self.enable = CSRStorage(n, fields=fields) From ea80e9ef32b9cd144dd1cb4d28ad83839681646d Mon Sep 17 00:00:00 2001 From: bunnie Date: Sun, 15 Nov 2020 21:50:26 +0800 Subject: [PATCH 3/7] improve documentation strings, try to handle unnamed events better --- litex/soc/interconnect/csr_eventmanager.py | 74 ++++++++++++++++++++-- 1 file changed, 67 insertions(+), 7 deletions(-) diff --git a/litex/soc/interconnect/csr_eventmanager.py b/litex/soc/interconnect/csr_eventmanager.py index 53cb3884d..cd6e39df6 100644 --- a/litex/soc/interconnect/csr_eventmanager.py +++ b/litex/soc/interconnect/csr_eventmanager.py @@ -139,24 +139,84 @@ class EventManager(Module, AutoCSR): self.irq = Signal() 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) + else: + base_text = "`1` if a this particular event occurred. " + if hasattr(src, "description") and src.description is not None: + return src.description + elif isinstance(src, EventSourceLevel): + return base_text + "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." + elif isinstance(src, EventSourceProcess): + return base_text + "This Event is triggered on a **falling** edge." + else: + return base_text + "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) + # annotate status fields = [] for i, source in enumerate(sources): if source.description == None: - desc = "Mask bit for {}".format(str(source.name)) + 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 - fields += [CSRField(source.name, size=1, description=desc)] - self.status = CSRStatus(n, fields=fields) + + 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): - desc = "Mask bit for {}".format(str(source.name)) - fields += [CSRField(source.name, size=1, description=desc)] - self.pending = CSRStatus(n, fields=fields) - self.enable = CSRStorage(n, fields=fields) + 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): self.comb += [ From 5d6c851f3267d38eee7f71a2f79f67908772a2dc Mon Sep 17 00:00:00 2001 From: bunnie Date: Sun, 15 Nov 2020 22:03:23 +0800 Subject: [PATCH 4/7] try to fix issue with unnamed sources --- litex/soc/interconnect/csr_eventmanager.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/litex/soc/interconnect/csr_eventmanager.py b/litex/soc/interconnect/csr_eventmanager.py index cd6e39df6..43c57c2f5 100644 --- a/litex/soc/interconnect/csr_eventmanager.py +++ b/litex/soc/interconnect/csr_eventmanager.py @@ -219,10 +219,14 @@ class EventManager(Module, AutoCSR): 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, source.name).eq(source.status), - getattr(self.pending.fields, source.name).eq(source.pending), - If(self.pending.re & getattr(self.pending.fields, source.name), source.clear.eq(1)), + 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)), ] irqs = [self.pending.status[i] & self.enable.storage[i] for i in range(n)] From 3dc18efe7094363b7a42897d85c3fd3e34bb2864 Mon Sep 17 00:00:00 2001 From: bunnie Date: Sun, 15 Nov 2020 23:18:46 +0800 Subject: [PATCH 5/7] make documented events optional --- litex/soc/integration/export.py | 2 +- litex/soc/interconnect/csr_eventmanager.py | 147 ++++++++++++--------- 2 files changed, 82 insertions(+), 67 deletions(-) diff --git a/litex/soc/integration/export.py b/litex/soc/integration/export.py index 2a6c01484..4d9b70c0e 100644 --- a/litex/soc/integration/export.py +++ b/litex/soc/integration/export.py @@ -308,7 +308,7 @@ def get_csr_svd(soc, vendor="litex", name="soc", description=None): svd.append(' 0x{:04x}'.format(csr_address)) svd.append(' 0x{:02x}'.format(csr.reset_value)) svd.append(' {}'.format(length)) - svd.append(' {}'.format(csr.access)) + # svd.append(' {}'.format(csr.access)) # 'access' is a lie: "read-only" registers can legitimately change state based on a write, and is in fact used to handle the "pending" field in events csr_address = csr_address + 4 svd.append(' ') if hasattr(csr, "fields") and len(csr.fields) > 0: diff --git a/litex/soc/interconnect/csr_eventmanager.py b/litex/soc/interconnect/csr_eventmanager.py index 43c57c2f5..5e4edf9a8 100644 --- a/litex/soc/interconnect/csr_eventmanager.py +++ b/litex/soc/interconnect/csr_eventmanager.py @@ -135,8 +135,9 @@ class EventManager(Module, AutoCSR): asserted. """ - def __init__(self): + def __init__(self, document_fields=False): self.irq = Signal() + self.document_fields = document_fields def do_finalize(self): def source_description(src): @@ -159,77 +160,91 @@ class EventManager(Module, AutoCSR): sources = sorted(sources_u, key=lambda x: x.duid) n = len(sources) - # 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 + 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 - 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) + 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 + # 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) + 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) + # 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)), - ] + 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)), + ] - irqs = [self.pending.status[i] & self.enable.storage[i] for i in range(n)] + 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): From 377794748b7e57e6e18145a884423a0b99207ea1 Mon Sep 17 00:00:00 2001 From: bunnie Date: Tue, 17 Nov 2020 04:55:46 +0800 Subject: [PATCH 6/7] add API to turn on documentation in I2S block for interrupts --- litex/soc/cores/i2s.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/i2s.py b/litex/soc/cores/i2s.py index 0af6b48a3..7573006d4 100644 --- a/litex/soc/cores/i2s.py +++ b/litex/soc/cores/i2s.py @@ -19,7 +19,7 @@ class I2S_FORMAT(Enum): I2S_LEFT_JUSTIFIED = 2 class S7I2S(Module, AutoCSR, AutoDoc): - def __init__(self, pads, fifo_depth=256, controller=False, master=False, concatenate_channels=True, sample_width=16, frame_format=I2S_FORMAT.I2S_LEFT_JUSTIFIED, lrck_ref_freq=100e6, lrck_freq=44100, bits_per_channel=28): + def __init__(self, pads, fifo_depth=256, controller=False, master=False, concatenate_channels=True, sample_width=16, frame_format=I2S_FORMAT.I2S_LEFT_JUSTIFIED, lrck_ref_freq=100e6, lrck_freq=44100, bits_per_channel=28, document_interrupts=False): if master == True: print("Master/slave terminology deprecated, please use controller/peripheral. Please see http://oshwa.org/a-resolution-to-redefine-spi-signal-names.") controller = True @@ -198,7 +198,7 @@ class S7I2S(Module, AutoCSR, AutoDoc): ] # Interrupts - self.submodules.ev = EventManager() + self.submodules.ev = EventManager(document_fields=document_interrupts) 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)") From 10256aa109e178567add7f367a7439906ddc5417 Mon Sep 17 00:00:00 2001 From: bunnie Date: Tue, 17 Nov 2020 05:10:16 +0800 Subject: [PATCH 7/7] resolve xobs review comments --- litex/soc/interconnect/csr_eventmanager.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/litex/soc/interconnect/csr_eventmanager.py b/litex/soc/interconnect/csr_eventmanager.py index 5e4edf9a8..d01a93eec 100644 --- a/litex/soc/interconnect/csr_eventmanager.py +++ b/litex/soc/interconnect/csr_eventmanager.py @@ -173,12 +173,12 @@ class EventManager(Module, AutoCSR): fields.append(CSRField( name=source.name, size=1, - description="Level of the `{}` event".format(source.name))) + 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))) + description="Level of the ``event{}`` event".format(i))) self.status = CSRStatus(n, description=desc, fields=fields) # annotate pending @@ -205,19 +205,19 @@ class EventManager(Module, AutoCSR): 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)) + 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))) + 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))) + description="Write a ``1`` to enable the ``{}`` Event".format(i))) self.enable = CSRStorage(n, description=desc, fields=fields) for i, source in enumerate(sources):