mcs48: add reset method, make A12 optional, unassorted adjustment
authorGerhard Sittig <gerhard.sittig@gmx.net>
Sat, 12 May 2018 20:21:39 +0000 (22:21 +0200)
committerGerhard Sittig <gerhard.sittig@gmx.net>
Sat, 12 May 2018 21:35:15 +0000 (23:35 +0200)
Add the reset() method which recently has become essential. Make the A12
"memory bank" address line optional. Use more Python idioms. Update
comments.

The control signals had to move, to avoid gaps between D7 and A8 as well
as between A11 and A12 in the GUI decoder properties dialog. With
dynamic assignment in the UI and with named references in the CLI this
shall not harm. Unmodified automated tests still pass.

The logic is prepared to handle data, address, and "bank" pin groups at
arbitrary locations, A[11:8] and D[7:0] need not be adjacent any longer.
Support for more than one memory bank pin is prepared, but the number of
bank pins needs to get determined at the start of decode(), when this
feature is to get added in the future.

decoders/mcs48/__init__.py
decoders/mcs48/pd.py

index 424c6b45bff62db0980e3ad4f82fe7723831bc4b..54c01ccb2f3d17d47b1a90f847d4566191ed04d5 100644 (file)
@@ -23,9 +23,6 @@ program memory accesses. This requires 14 channels: 8 for D0-D7 (data and
 lower 8 bits of address), 4 for A8-A11 (output on port P2), ALE and PSEN.
 An optional A12 is supported, which may be an arbitrary I/O pin driven by
 software (use case is dumping ROM of an HP 3478A).
-
-The two groups D0-D7 and A8-A12 must be on consecutive channels, for
-example CH8..CH15 and CH0..CH4.
 '''
 
 from .pd import Decoder
index 2c331d1f31fd972ea13bec11cab7c8b0a540ff6b..185fd89437ebde3197737d0688ce241855c30c9e 100644 (file)
 ## along with this program; if not, see <http://www.gnu.org/licenses/>.
 ##
 
-# TODO: Make A12 optional; it's here because of an instrument (HP3478A) that
-# drives a generic I/O pin to access 8kB of ROM; the MCS-48 only has a 4kB
-# address space.
-
 import sigrokdecode as srd
 
 class ChannelError(Exception):
@@ -35,20 +31,25 @@ class Decoder(srd.Decoder):
     license = 'gplv2+'
     inputs = ['logic']
     outputs = ['mcs48']
-    channels = \
-    tuple({
+    channels = (
+        {'id': 'ale', 'name': 'ALE', 'desc': 'Address latch enable'},
+        {'id': 'psen', 'name': '/PSEN', 'desc': 'Program store enable'},
+    ) + tuple({
         'id': 'd%d' % i,
         'name': 'D%d' % i,
         'desc': 'CPU data line %d' % i
-        } for i in range(8)
+        } for i in range(0, 8)
     ) + tuple({
         'id': 'a%d' % i,
         'name': 'A%d' % i,
         'desc': 'CPU address line %d' % i
-        } for i in range(8, 13)
-    ) + (
-        {'id': 'ale', 'name': 'ALE', 'desc': 'Address latch enable'},
-        {'id': 'psen', 'name': '/PSEN', 'desc': 'Program store enable'},
+        } for i in range(8, 12)
+    )
+    optional_channels = tuple({
+        'id': 'a%d' % i,
+        'name': 'A%d' % i,
+        'desc': 'CPU address line %d' % i
+        } for i in range(12, 13)
     )
     annotations = (
         ('romdata', 'Address:Data'),
@@ -56,8 +57,15 @@ class Decoder(srd.Decoder):
     binary = (
         ('romdata', 'AAAA:DD'),
     )
+    OFF_ALE, OFF_PSEN = 0, 1
+    OFF_DATA_BOT, OFF_DATA_TOP = 2, 10
+    OFF_ADDR_BOT, OFF_ADDR_TOP = 10, 14
+    OFF_BANK_BOT, OFF_BANK_TOP = 14, 15
 
     def __init__(self):
+        self.reset()
+
+    def reset(self):
         self.addr = 0
         self.addr_s = 0
         self.data = 0
@@ -70,35 +78,44 @@ class Decoder(srd.Decoder):
         self.out_ann = self.register(srd.OUTPUT_ANN)
         self.out_bin = self.register(srd.OUTPUT_BINARY)
 
-    def newaddr(self, pins):
+    def newaddr(self, addr, data):
         # Falling edge on ALE: reconstruct address.
         self.started = 1
-        tempaddr = 0
-        for i in range(13):
-            tempaddr |= pins[i] << i
-        self.addr = tempaddr
+        addr = sum([bit << i for i, bit in enumerate(addr)])
+        addr <<= len(data)
+        addr |= sum([bit << i for i, bit in enumerate(data)])
+        self.addr = addr
         self.addr_s = self.samplenum
 
-    def newdata(self, pins):
+    def newdata(self, data):
         # Edge on PSEN: get data.
-        tempdata = 0
-        for i in range(8):
-            tempdata |= pins[i] << i
-        self.data = tempdata
+        data = sum([bit << i for i, bit in enumerate(data)])
+        self.data = data
         self.data_s = self.samplenum
         if self.started:
-            self.put(self.addr_s, self.samplenum, self.out_ann,
-                [0, ['%04X:' % self.addr + '%02X' % self.data]])
-            self.put(self.addr_s, self.samplenum, self.out_bin,
-                [0, bytes([(self.addr >> 8) & 0xFF, self.addr & 0xFF, self.data])])
+            anntext = '{:04X}:{:02X}'.format(self.addr, self.data)
+            self.put(self.addr_s, self.data_s, self.out_ann, [0, [anntext]])
+            bindata = self.addr.to_bytes(2, byteorder='big')
+            bindata += self.data.to_bytes(1, byteorder='big')
+            self.put(self.addr_s, self.data_s, self.out_bin, [0, bindata])
 
     def decode(self):
+        # Address bits above A11 are optional, and are considered to be A12+.
+        # This logic needs more adjustment when more bank address pins are
+        # to get supported. For now, having just A12 is considered sufficient.
+        has_bank = self.has_channel(self.OFF_BANK_BOT)
+        bank_pin_count = 1 if has_bank else 0
         # Sample address on the falling ALE edge.
         # Save data on falling edge of PSEN.
         while True:
-            pins = self.wait([{13: 'f'}, {14: 'r'}])
+            pins = self.wait([{self.OFF_ALE: 'f'}, {self.OFF_PSEN: 'r'}])
+            data = pins[self.OFF_DATA_BOT:self.OFF_DATA_TOP]
+            addr = pins[self.OFF_ADDR_BOT:self.OFF_ADDR_TOP]
+            bank = pins[self.OFF_BANK_BOT:self.OFF_BANK_TOP]
+            if has_bank:
+                addr += bank[:bank_pin_count]
             # Handle those conditions (one or more) that matched this time.
             if self.matched[0]:
-                self.newaddr(pins[0:])
+                self.newaddr(addr, data)
             if self.matched[1]:
-                self.newdata(pins[0:])
+                self.newdata(data)