]> sigrok.org Git - libsigrokdecode.git/commitdiff
parallel: add support for optional reset/enable/select signal
authorGerhard Sittig <redacted>
Sat, 7 Nov 2020 13:38:05 +0000 (14:38 +0100)
committerGerhard Sittig <redacted>
Wed, 11 Nov 2020 18:47:41 +0000 (19:47 +0100)
Add an optional 'reset' signal of user configurable polarity. When the
signal is asserted, the data lines are not interpreted. Assertion will
flush previously accumulated data bits and words. Deassertion can help
synchronize to input streams when the capture started in the middle of
a word. Despite the "reset" name this signal can also be thought of as
"enable" or "select", and increases the versatility and usefulness of
the parallel decoder beyond strictly parallel memory busses.

Construct the list of .wait() conditions and track the positions of
individual terms in that list. This is necessary because "always false"
conditions are not available, thus pin/channel indices and .matched[]
indices don't correspond for sparse input signal assignments.

Accept when previously gathered information became void again, and
re-use existing initialization code for reset related activity.

decoders/parallel/pd.py

index abf48eb170fc5b5ae3acc979f7d6ba340a56f873..e0623e73fe0d073916fc714f8dbd31503f5c8172 100644 (file)
@@ -60,6 +60,9 @@ class Pin:
     CLOCK = 0
     DATA_0 = CLOCK + 1
     DATA_N = DATA_0 + NUM_CHANNELS
+    # BEWARE! DATA_N points _beyond_ the data partition (Python range(3)
+    # semantics, useful to have to simplify other code locations).
+    RESET = DATA_N
 
 class Ann:
     ITEM, WORD = range(2)
@@ -82,11 +85,14 @@ class Decoder(srd.Decoder):
         [
             {'id': 'd%d' % i, 'name': 'D%d' % i, 'desc': 'Data line %d' % i}
             for i in range(NUM_CHANNELS)
-        ]
+        ] +
+        [{'id': 'rst', 'name': 'RST', 'desc': 'RESET line'}]
     )
     options = (
         {'id': 'clock_edge', 'desc': 'Clock edge to sample on',
             'default': 'rising', 'values': ('rising', 'falling', 'either')},
+        {'id': 'reset_polarity', 'desc': 'Reset line polarity',
+            'default': 'low-active', 'values': ('low-active', 'high-active')},
         {'id': 'wordsize', 'desc': 'Data wordsize (# bus cycles)',
             'default': 0},
         {'id': 'endianness', 'desc': 'Data endianness',
@@ -147,6 +153,8 @@ class Decoder(srd.Decoder):
             self.ss_item = self.samplenum
             self.first = False
             self.saved_item = item
+        elif self.saved_item is None:
+            pass
         else:
             # Output the saved item (from the last CLK edge to the current).
             self.es_item = self.samplenum
@@ -202,23 +210,57 @@ class Decoder(srd.Decoder):
         # clock signal. Either inspect samples on the configured edge of
         # the clock, or inspect samples upon ANY edge of ANY of the pins
         # which provide input data.
+        conds = []
+        cond_idx_clock = None
+        cond_idx_data_0 = None
+        cond_idx_data_N = None
+        cond_idx_reset = None
         has_clock = self.has_channel(Pin.CLOCK)
         if has_clock:
+            cond_idx_clock = len(conds)
             edge = {
                 'rising': 'r',
                 'falling': 'f',
                 'either': 'e',
             }.get(self.options['clock_edge'])
-            conds = [{Pin.CLOCK: edge}]
+            conds.append({Pin.CLOCK: edge})
         else:
-            conds = [{idx: 'e'} for idx in has_data]
+            cond_idx_data_0 = len(conds)
+            conds.extend([{idx: 'e'} for idx in has_data])
+            cond_idx_data_N = len(conds)
+        has_reset = self.has_channel(Pin.RESET)
+        if has_reset:
+            cond_idx_reset = len(conds)
+            conds.append({Pin.RESET: 'e'})
+            reset_active = {
+                'low-active': 0,
+                'high-active': 1,
+            }.get(self.options['reset_polarity'])
 
         # Keep processing the input stream. Assume "always zero" for
         # not-connected input lines. Pass data bits (all inputs except
-        # clock) to the handle_bits() method.
+        # clock and reset) to the handle_bits() method. Handle reset
+        # edges first and data changes then, within the same iteration.
+        # This results in robust operation for low-oversampled input.
+        in_reset = False
         while True:
             pins = self.wait(conds)
-            data_bits = [0 if idx is None else pins[idx] for idx in data_indices]
-            data_bits = data_bits[:num_item_bits]
-            item = bitpack(data_bits)
-            self.handle_bits(item, num_item_bits)
+            clock_edge = cond_idx_clock is not None and self.matched[cond_idx_clock]
+            data_edge = cond_idx_data_0 is not None and [idx for idx in range(cond_idx_data_0, cond_idx_data_N) if self.matched[idx]]
+            reset_edge = cond_idx_reset is not None and self.matched[cond_idx_reset]
+
+            if reset_edge:
+                in_reset = pins[Pin.RESET] == reset_active
+                if in_reset:
+                    self.handle_bits(None, num_item_bits)
+                    self.saved_item = None
+                    self.saved_word = None
+                    self.first = True
+            if in_reset:
+                continue
+
+            if clock_edge or data_edge:
+                data_bits = [0 if idx is None else pins[idx] for idx in data_indices]
+                data_bits = data_bits[:num_item_bits]
+                item = bitpack(data_bits)
+                self.handle_bits(item, num_item_bits)