]> sigrok.org Git - libsigrokdecode.git/blobdiff - decoders/z80/pd.py
z80: Use methods directly as state values.
[libsigrokdecode.git] / decoders / z80 / pd.py
index cd58b488c5d8f939af53b79a2b9a92dedd4fc4c7..d98df7c8f91b79cb845aa24617e690a3eb5410ba 100644 (file)
@@ -20,6 +20,7 @@
 import sigrokdecode as srd
 from functools import reduce
 from .tables import instr_table_by_prefix
+import string
 
 class Ann:
     ADDR, MEMRD, MEMWR, IORD, IOWR, INSTR, ROP, WOP, WARN = range(9)
@@ -32,20 +33,17 @@ class Pin:
 class Cycle:
     NONE, MEMRD, MEMWR, IORD, IOWR, FETCH, INTACK = range(7)
 
-class OpState:
-    IDLE    = 'IDLE'    # no current instruction
-    PRE1    = 'PRE1'    # first prefix
-    PRE2    = 'PRE2'    # second prefix
-    PREDIS  = 'PREDIS'  # pre-opcode displacement
-    OPCODE  = 'OPCODE'  # opcode byte
-    POSTDIS = 'POSTDIS' # post-opcode displacement
-    IMM1    = 'IMM1'    # first byte of immediate
-    IMM2    = 'IMM2'    # second byte of immediate
-    ROP1    = 'ROP1'    # first byte of read operand
-    ROP2    = 'ROP2'    # second byte of read operand
-    WOP1    = 'WOP1'    # first byte of write operand
-    WOP2    = 'WOP2'    # second byte of write operand
-    RESTART = 'RESTART' # restart instruction decoding
+# Provide custom format type 'H' for hexadecimal output
+# with leading decimal digit (assembler syntax).
+class AsmFormatter(string.Formatter):
+    def format_field(self, value, format_spec):
+        if format_spec.endswith('H'):
+            result = format(value, format_spec[:-1] + 'X')
+            return result if result[0] in string.digits else '0' + result
+        else:
+            return format(value, format_spec)
+
+formatter = AsmFormatter()
 
 ann_data_cycle_map = {
     Cycle.MEMRD:  Ann.MEMRD,
@@ -67,13 +65,13 @@ def signed_byte(byte):
 
 class Decoder(srd.Decoder):
     api_version = 1
-    id          = 'z80'
-    name        = 'Z80'
-    longname    = 'Zilog Z80 CPU'
-    desc        = 'Zilog Z80 microprocessor disassembly.'
-    license     = 'gplv2+'
-    inputs      = ['logic']
-    outputs     = ['z80']
+    id       = 'z80'
+    name     = 'Z80'
+    longname = 'Zilog Z80 CPU'
+    desc     = 'Zilog Z80 microprocessor disassembly.'
+    license  = 'gplv2+'
+    inputs   = ['logic']
+    outputs  = ['z80']
     probes = [
         {'id': 'd%d' % i, 'name': 'D%d' % i, 'desc': 'Data bus line %d' % i}
             for i in range(8)
@@ -91,15 +89,15 @@ class Decoder(srd.Decoder):
     ]
     options = {}
     annotations = [
-        ['addr',    'Memory or I/O address'],
-        ['memrd',   'Byte read from memory'],
-        ['memwr',   'Byte written to memory'],
-        ['iord',    'Byte read from I/O port'],
-        ['iowr',    'Byte written to I/O port'],
-        ['instr',   'Z80 CPU instruction'],
-        ['rop',     'Value of input operand'],
-        ['wop',     'Value of output operand'],
-        ['warning', 'Warning message'],
+        ['addr',  'Memory or I/O address'],
+        ['memrd', 'Byte read from memory'],
+        ['memwr', 'Byte written to memory'],
+        ['iord',  'Byte read from I/O port'],
+        ['iowr',  'Byte written to I/O port'],
+        ['instr', 'Z80 CPU instruction'],
+        ['rop',   'Value of input operand'],
+        ['wop',   'Value of output operand'],
+        ['warn',  'Warning message'],
     ]
     annotation_rows = (
         ('addrbus', 'Address bus', (Ann.ADDR,)),
@@ -111,7 +109,7 @@ class Decoder(srd.Decoder):
 
     def __init__(self, **kwargs):
         self.prev_cycle = Cycle.NONE
-        self.op_state   = OpState.IDLE
+        self.op_state   = self.state_IDLE
 
     def start(self):
         self.out_ann    = self.register(srd.OUTPUT_ANN)
@@ -125,7 +123,8 @@ class Decoder(srd.Decoder):
         self.ann_data   = None
         self.ann_dasm   = None
         self.prev_cycle = Cycle.NONE
-        self.op_state   = OpState.IDLE
+        self.op_state   = self.state_IDLE
+        self.instr_len  = 0
 
     def decode(self, ss, es, data):
         for (self.samplenum, pins) in data:
@@ -162,11 +161,12 @@ class Decoder(srd.Decoder):
         self.pend_addr  = bus_addr
 
     def on_cycle_end(self):
-        self.op_state = getattr(self, 'on_state_' + self.op_state)()
+        self.instr_len += 1
+        self.op_state = self.op_state()
         if self.ann_dasm is not None:
             self.put_disasm()
-        if self.op_state == OpState.RESTART:
-            self.op_state = self.on_state_IDLE()
+        if self.op_state == self.state_RESTART:
+            self.op_state = self.state_IDLE()
 
         if self.ann_data is not None:
             self.put_text(self.data_start, self.ann_data,
@@ -183,9 +183,9 @@ class Decoder(srd.Decoder):
         self.ann_dasm  = None
 
     def put_disasm(self):
-        text = self.mnemonic.format(r=self.arg_reg, d=self.arg_dis,
-                                    i=self.arg_imm, ro=self.arg_read,
-                                    wo=self.arg_write)
+        text = formatter.format(self.mnemonic, r=self.arg_reg, d=self.arg_dis,
+                                j=self.arg_dis+self.instr_len, i=self.arg_imm,
+                                ro=self.arg_read, wo=self.arg_write)
         self.put_text(self.dasm_start, self.ann_dasm, text)
         self.ann_dasm   = None
         self.dasm_start = self.samplenum
@@ -193,9 +193,12 @@ class Decoder(srd.Decoder):
     def put_text(self, ss, ann_idx, ann_text):
         self.put(ss, self.samplenum, self.out_ann, [ann_idx, [ann_text]])
 
-    def on_state_IDLE(self):
+    def state_RESTART(self):
+        return self.state_IDLE
+
+    def state_IDLE(self):
         if self.prev_cycle != Cycle.FETCH:
-            return OpState.IDLE
+            return self.state_IDLE
         self.want_dis   = 0
         self.want_imm   = 0
         self.want_read  = 0
@@ -213,132 +216,134 @@ class Decoder(srd.Decoder):
         self.write_pend = False
         self.dasm_start = self.samplenum
         self.op_prefix  = 0
+        self.instr_len  = 0
         if self.bus_data in (0xCB, 0xED, 0xDD, 0xFD):
-            return OpState.PRE1
+            return self.state_PRE1
         else:
-            return OpState.OPCODE
+            return self.state_OPCODE
 
-    def on_state_PRE1(self):
+    def state_PRE1(self):
         if self.prev_cycle != Cycle.FETCH:
             self.mnemonic = 'Prefix not followed by fetch'
             self.ann_dasm = Ann.WARN
-            return OpState.RESTART
+            return self.state_RESTART
         self.op_prefix = self.pend_data
         if self.op_prefix in (0xDD, 0xFD):
             if self.bus_data == 0xCB:
-                return OpState.PRE2
+                return self.state_PRE2
             if self.bus_data in (0xDD, 0xED, 0xFD):
-                return OpState.PRE1
-        return OpState.OPCODE
+                return self.state_PRE1
+        return self.state_OPCODE
 
-    def on_state_PRE2(self):
+    def state_PRE2(self):
         if self.prev_cycle != Cycle.MEMRD:
             self.mnemonic = 'Missing displacement'
             self.ann_dasm = Ann.WARN
-            return OpState.RESTART
+            return self.state_RESTART
         self.op_prefix = (self.op_prefix << 8) | self.pend_data
-        return OpState.PREDIS
+        return self.state_PREDIS
 
-    def on_state_PREDIS(self):
+    def state_PREDIS(self):
         if self.prev_cycle != Cycle.MEMRD:
             self.mnemonic = 'Missing opcode'
             self.ann_dasm = Ann.WARN
-            return OpState.RESTART
+            return self.state_RESTART
         self.arg_dis = signed_byte(self.pend_data)
-        return OpState.OPCODE
+        return self.state_OPCODE
 
-    def on_state_OPCODE(self):
+    def state_OPCODE(self):
         (table, self.arg_reg) = instr_table_by_prefix[self.op_prefix]
         self.op_prefix = 0
         instruction = table.get(self.pend_data, None)
         if instruction is None:
             self.mnemonic = 'Invalid instruction'
             self.ann_dasm = Ann.WARN
-            return OpState.RESTART
+            return self.state_RESTART
         (self.want_dis, self.want_imm, self.want_read, want_write,
                 self.op_repeat, self.mnemonic) = instruction
         self.want_write = abs(want_write)
         self.want_wr_be = (want_write < 0)
         if self.want_dis > 0:
-            return OpState.POSTDIS
+            return self.state_POSTDIS
         if self.want_imm > 0:
-            return OpState.IMM1
+            return self.state_IMM1
         self.ann_dasm = Ann.INSTR
         if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
-            return OpState.ROP1
+            return self.state_ROP1
         if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
-            return OpState.WOP1
-        return OpState.RESTART
+            return self.state_WOP1
+        return self.state_RESTART
 
-    def on_state_POSTDIS(self):
+    def state_POSTDIS(self):
         self.arg_dis = signed_byte(self.pend_data)
         if self.want_imm > 0:
-            return OpState.IMM1
+            return self.state_IMM1
         self.ann_dasm = Ann.INSTR
-        if self.want_read > 0:
-            return OpState.ROP1
-        if self.want_write > 0:
-            return OpState.WOP1
-        return OpState.RESTART
+        if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
+            return self.state_ROP1
+        if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
+            return self.state_WOP1
+        return self.state_RESTART
 
-    def on_state_IMM1(self):
+    def state_IMM1(self):
         self.arg_imm = self.pend_data
         if self.want_imm > 1:
-            return OpState.IMM2
+            return self.state_IMM2
         self.ann_dasm = Ann.INSTR
-        if self.want_read > 0:
-            return OpState.ROP1
-        if self.want_write > 0:
-            return OpState.WOP1
-        return OpState.RESTART
+        if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
+            return self.state_ROP1
+        if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
+            return self.state_WOP1
+        return self.state_RESTART
 
-    def on_state_IMM2(self):
+    def state_IMM2(self):
         self.arg_imm |= self.pend_data << 8
         self.ann_dasm = Ann.INSTR
-        if self.want_read > 0:
-            return OpState.ROP1
-        if self.want_write > 0:
-            return OpState.WOP1
-        return OpState.RESTART
+        if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
+            return self.state_ROP1
+        if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
+            return self.state_WOP1
+        return self.state_RESTART
 
-    def on_state_ROP1(self):
+    def state_ROP1(self):
         self.arg_read = self.pend_data
+        if self.want_read < 2:
+            self.mnemonic = '{ro:02X}'
+            self.ann_dasm = Ann.ROP
         if self.want_write > 0:
-            return OpState.WOP1
+            return self.state_WOP1
         if self.want_read > 1:
-            return OpState.ROP2
+            return self.state_ROP2
         if self.op_repeat and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
-            return OpState.ROP1
-        self.mnemonic = '{ro:02X}'
-        self.ann_dasm = Ann.ROP
-        return OpState.RESTART
+            return self.state_ROP1
+        return self.state_RESTART
 
-    def on_state_ROP2(self):
+    def state_ROP2(self):
         self.arg_read |= self.pend_data << 8
         self.mnemonic = '{ro:04X}'
         self.ann_dasm = Ann.ROP
-        if self.want_write > 0:
-            return OpState.WOP1
-        return OpState.RESTART
+        if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
+            return self.state_WOP1
+        return self.state_RESTART
 
-    def on_state_WOP1(self):
+    def state_WOP1(self):
         self.arg_write = self.pend_data
         if self.want_read > 1:
-            return OpState.ROP2
+            return self.state_ROP2
         if self.want_write > 1:
-            return OpState.WOP2
-        if self.want_read > 0 and self.op_repeat and \
-                self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
-            return OpState.ROP1
+            return self.state_WOP2
         self.mnemonic = '{wo:02X}'
         self.ann_dasm = Ann.WOP
-        return OpState.RESTART
+        if self.want_read > 0 and self.op_repeat and \
+                self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
+            return self.state_ROP1
+        return self.state_RESTART
 
-    def on_state_WOP2(self):
+    def state_WOP2(self):
         if self.want_wr_be:
             self.arg_write = (self.arg_write << 8) | self.pend_data
         else:
             self.arg_write |= self.pend_data << 8
         self.mnemonic = '{wo:04X}'
         self.ann_dasm = Ann.WOP
-        return OpState.RESTART
+        return self.state_RESTART