summaryrefslogtreecommitdiff
path: root/decoders
diff options
context:
space:
mode:
authorGerhard Sittig <gerhard.sittig@gmx.net>2020-11-07 14:38:05 +0100
committerGerhard Sittig <gerhard.sittig@gmx.net>2020-11-11 19:47:41 +0100
commit76b64d3a64c61f4de996d40c55d44c77471a48d8 (patch)
tree51bd8f3ca0c77066e9e0c23cdfc2b10d6121ac32 /decoders
parente2317ec49b8b04c7f8b3358c2e9c264de4280539 (diff)
downloadlibsigrokdecode-76b64d3a64c61f4de996d40c55d44c77471a48d8.tar.gz
libsigrokdecode-76b64d3a64c61f4de996d40c55d44c77471a48d8.zip
parallel: add support for optional reset/enable/select signal
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.
Diffstat (limited to 'decoders')
-rw-r--r--decoders/parallel/pd.py58
1 files changed, 50 insertions, 8 deletions
diff --git a/decoders/parallel/pd.py b/decoders/parallel/pd.py
index abf48eb..e0623e7 100644
--- a/decoders/parallel/pd.py
+++ b/decoders/parallel/pd.py
@@ -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)