Add initial sync parallel bus decoder.
authorUwe Hermann <uwe@hermann-uwe.de>
Sat, 19 Oct 2013 19:36:49 +0000 (21:36 +0200)
committerUwe Hermann <uwe@hermann-uwe.de>
Sun, 20 Oct 2013 11:15:58 +0000 (13:15 +0200)
configure.ac
decoders/Makefile.am
decoders/parallel/Makefile.am [new file with mode: 0644]
decoders/parallel/__init__.py [new file with mode: 0644]
decoders/parallel/pd.py [new file with mode: 0644]

index 60d913173a848ff3c1c1a08f5b8aba908536f59c..7e2775aca4d4f456f213530b9bf20be82e3de65e 100644 (file)
@@ -184,6 +184,7 @@ AC_CONFIG_FILES([Makefile
                 decoders/onewire_link/Makefile
                 decoders/onewire_network/Makefile
                 decoders/pan1321/Makefile
+                decoders/parallel/Makefile
                 decoders/rtc8564/Makefile
                 decoders/sdcard_spi/Makefile
                 decoders/spi/Makefile
index 4ad5930075a8887e083d679045c7dccda690646d..8371f391c0aeb0da545dc463f0aa2a3e4a1ada1c 100644 (file)
@@ -43,6 +43,7 @@ SUBDIRS = \
        onewire_link \
        onewire_network \
        pan1321 \
+       parallel \
        rtc8564 \
        sdcard_spi \
        spi \
diff --git a/decoders/parallel/Makefile.am b/decoders/parallel/Makefile.am
new file mode 100644 (file)
index 0000000..2371d10
--- /dev/null
@@ -0,0 +1,26 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2013 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+pkgdatadir = $(DECODERS_DIR)/parallel
+
+dist_pkgdata_DATA = __init__.py pd.py
+
+CLEANFILES = *.pyc
+
diff --git a/decoders/parallel/__init__.py b/decoders/parallel/__init__.py
new file mode 100644 (file)
index 0000000..a338c43
--- /dev/null
@@ -0,0 +1,32 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2013 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+'''
+This protocol decoder can decode synchronous parallel buses with various
+number of data bits/probes and one clock line.
+
+It is required to use the lowest data probes, and use consecutive ones.
+For example, for a 4-bit sync parallel bus, probes D0/D1/D2/D3 (and CLK)
+should be used. Using combinations like D7/D12/D3/D15 is not supported.
+For an 8-bit bus you should use D0-D7, for a 16-bit bus use D0-D15 and so on.
+'''
+
+from .pd import *
+
diff --git a/decoders/parallel/pd.py b/decoders/parallel/pd.py
new file mode 100644 (file)
index 0000000..476bf2f
--- /dev/null
@@ -0,0 +1,196 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2013 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# Parallel (sync) bus protocol decoder
+
+import sigrokdecode as srd
+
+'''
+Protocol output format:
+
+Packet:
+[<ptype>, <pdata>]
+
+<ptype>, <pdata>
+ - 'ITEM', [<item>, <itembitsize>]
+ - 'WORD', [<word>, <wordbitsize>, <worditemcount>]
+
+<item>:
+ - A single item (a number). It can be of arbitrary size. The max. number
+   of bits in this item is specified in <itembitsize>.
+
+<itembitsize>:
+ - The size of an item (in bits). For a 4-bit parallel bus this is 4,
+   for a 16-bit parallel bus this is 16, and so on.
+
+<word>:
+ - A single word (a number). It can be of arbitrary size. The max. number
+   of bits in this word is specified in <wordbitsize>. The (exact) number
+   of items in this word is specified in <worditemcount>.
+
+<wordbitsize>:
+ - The size of a word (in bits). For a 2-item word with 8-bit items
+   <wordbitsize> is 16, for a 3-item word with 4-bit items <wordbitsize>
+   is 12, and so on.
+
+<worditemcount>:
+ - The size of a word (in number of items). For a 4-item word (no matter
+   how many bits each item consists of) <worditemcount> is 4, for a 7-item
+   word <worditemcount> is 7, and so on.
+'''
+
+def probe_list(num_probes):
+    l = []
+    for i in range(num_probes):
+        d = {'id': 'd%d' % i, 'name': 'D%d' % i, 'desc': 'Data line %d' % i}
+        l.append(d)
+    return l
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'parallel'
+    name = 'Parallel'
+    longname = 'Parallel sync bus'
+    desc = 'Generic parallel synchronous bus.'
+    license = 'gplv2+'
+    inputs = ['logic']
+    outputs = ['parallel']
+    probes = [
+        {'id': 'clk', 'name': 'CLK', 'desc': 'Clock line'},
+    ]
+    optional_probes = probe_list(32)
+    options = {
+        'clock_edge': ['Clock edge to sample on', 'rising'],
+        'wordsize': ['Word size of the data', 1],
+        'endianness': ['Endianness of the data', 'little'],
+        'format': ['Data format', 'hex'],
+    }
+    annotations = [
+        ['items', 'Items'],
+        ['words', 'Words'],
+    ]
+
+    def __init__(self):
+        self.oldclk = None
+        self.items = []
+        self.itemcount = 0
+        self.saved_item = None
+        self.samplenum = 0
+        self.oldpins = None
+        self.ss_item = self.es_item = None
+        self.first = True
+        self.state = 'IDLE'
+
+    def start(self, metadata):
+        self.out_proto = self.add(srd.OUTPUT_PROTO, 'parallel')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'parallel')
+
+    def report(self):
+        pass
+
+    def putpb(self, data):
+        self.put(self.ss_item, self.es_item, self.out_proto, data)
+
+    def putb(self, data):
+        self.put(self.ss_item, self.es_item, self.out_ann, data)
+
+    def putpw(self, data):
+        self.put(self.ss_word, self.es_word, self.out_proto, data)
+
+    def putw(self, data):
+        self.put(self.ss_word, self.es_word, self.out_ann, data)
+
+    def handle_bits(self, datapins):
+        # If this is the first item in a word, save its sample number.
+        if self.itemcount == 0:
+            self.ss_word = self.samplenum
+
+        # Get the bits for this item.
+        item, used_pins = 0, datapins.count(b'\x01') + datapins.count(b'\x00')
+        for i in range(used_pins):
+            item |= datapins[i] << i
+
+        self.items.append(item)
+        self.itemcount += 1
+
+        if self.first == True:
+            # Save the start sample and item for later (no output yet).
+            self.ss_item = self.samplenum
+            self.first = False
+            self.saved_item = item
+        else:
+            # Output the saved item (from the last CLK edge to the current).
+            self.es_item = self.samplenum
+            self.putpb(['ITEM', self.saved_item])
+            self.putb([0, ['%X' % self.saved_item]])
+            self.ss_item = self.samplenum
+            self.saved_item = item
+
+        endian, ws = self.options['endianness'], self.options['wordsize']
+
+        # Get as many items as the configured wordsize says.
+        if self.itemcount < ws:
+            return
+
+        # Output annotations/proto for a word (a collection of items).
+        word = 0
+        for i in range(ws):
+            if endian == 'little':
+                word |= self.items[i] << ((ws - 1 - i) * used_pins)
+            elif endian == 'big':
+                word |= self.items[i] << (i * used_pins)
+
+        self.es_word = self.samplenum
+        # self.putpw(['WORD', word])
+        # self.putw([1, ['%X' % word]])
+        self.ss_word = self.samplenum
+
+        self.itemcount, self.items = 0, []
+
+    def find_clk_edge(self, clk, datapins):
+        # Ignore sample if the clock pin hasn't changed.
+        if clk == self.oldclk:
+            return
+        self.oldclk = clk
+
+        # Sample data on rising/falling clock edge (depends on config).
+        c = self.options['clock_edge']
+        if c == 'rising' and clk == 0: # Sample on rising clock edge.
+            return
+        elif c == 'falling' and clk == 1: # Sample on falling clock edge.
+            return
+
+        # Found the correct clock edge, now get the bits.
+        self.handle_bits(datapins)
+
+    def decode(self, ss, es, data):
+        for (self.samplenum, pins) in data:
+
+            # Ignore identical samples early on (for performance reasons).
+            if self.oldpins == pins:
+                continue
+            self.oldpins = pins
+
+            # State machine.
+            if self.state == 'IDLE':
+                self.find_clk_edge(pins[0], pins[1:])
+            else:
+                raise Exception('Invalid state: %s' % self.state)
+