X-Git-Url: https://sigrok.org/gitweb/?p=libsigrokdecode.git;a=blobdiff_plain;f=decoders%2Fz80%2Fpd.py;h=bcfcdbdab9dc779998d7d85e9cd73f0c10494b85;hp=2baa02a3a686599468e48519eff3effb1796eab9;hb=4c180223a8ae12feb7bc3601e07e848fb9cdb493;hpb=26abbf3762e19d89ab578905aaba24e8764d1696 diff --git a/decoders/z80/pd.py b/decoders/z80/pd.py index 2baa02a..bcfcdbd 100644 --- a/decoders/z80/pd.py +++ b/decoders/z80/pd.py @@ -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, @@ -58,7 +56,7 @@ ann_data_cycle_map = { def reduce_bus(bus): if 0xFF in bus: - return None # unassigned bus probes + return None # unassigned bus channels else: return reduce(lambda a, b: (a << 1) | b, reversed(bus)) @@ -66,59 +64,45 @@ def signed_byte(byte): return byte if byte < 128 else byte - 256 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'] - probes = [ - {'id': 'd0', 'name': 'D0', 'desc': 'Data bus line 0'}, - {'id': 'd1', 'name': 'D1', 'desc': 'Data bus line 1'}, - {'id': 'd2', 'name': 'D2', 'desc': 'Data bus line 2'}, - {'id': 'd3', 'name': 'D3', 'desc': 'Data bus line 3'}, - {'id': 'd4', 'name': 'D4', 'desc': 'Data bus line 4'}, - {'id': 'd5', 'name': 'D5', 'desc': 'Data bus line 5'}, - {'id': 'd6', 'name': 'D6', 'desc': 'Data bus line 6'}, - {'id': 'd7', 'name': 'D7', 'desc': 'Data bus line 7'}, + api_version = 3 + id = 'z80' + name = 'Z80' + longname = 'Zilog Z80 CPU' + desc = 'Zilog Z80 microprocessor disassembly.' + license = 'gplv3+' + inputs = ['logic'] + outputs = ['z80'] + tags = ['Logic', 'MCU Debugging'] + channels = tuple({ + 'id': 'd%d' % i, + 'name': 'D%d' % i, + 'desc': 'Data bus line %d' % i + } for i in range(8) + ) + ( {'id': 'm1', 'name': '/M1', 'desc': 'Machine cycle 1'}, {'id': 'rd', 'name': '/RD', 'desc': 'Memory or I/O read'}, {'id': 'wr', 'name': '/WR', 'desc': 'Memory or I/O write'}, - ] - optional_probes = [ + ) + optional_channels = ( {'id': 'mreq', 'name': '/MREQ', 'desc': 'Memory request'}, {'id': 'iorq', 'name': '/IORQ', 'desc': 'I/O request'}, - {'id': 'a0', 'name': 'A0', 'desc': 'Address bus line 0'}, - {'id': 'a1', 'name': 'A1', 'desc': 'Address bus line 1'}, - {'id': 'a2', 'name': 'A2', 'desc': 'Address bus line 2'}, - {'id': 'a3', 'name': 'A3', 'desc': 'Address bus line 3'}, - {'id': 'a4', 'name': 'A4', 'desc': 'Address bus line 4'}, - {'id': 'a5', 'name': 'A5', 'desc': 'Address bus line 5'}, - {'id': 'a6', 'name': 'A6', 'desc': 'Address bus line 6'}, - {'id': 'a7', 'name': 'A7', 'desc': 'Address bus line 7'}, - {'id': 'a8', 'name': 'A8', 'desc': 'Address bus line 8'}, - {'id': 'a9', 'name': 'A9', 'desc': 'Address bus line 9'}, - {'id': 'a10', 'name': 'A10', 'desc': 'Address bus line 10'}, - {'id': 'a11', 'name': 'A11', 'desc': 'Address bus line 11'}, - {'id': 'a12', 'name': 'A12', 'desc': 'Address bus line 12'}, - {'id': 'a13', 'name': 'A13', 'desc': 'Address bus line 13'}, - {'id': 'a14', 'name': 'A14', 'desc': 'Address bus line 14'}, - {'id': 'a15', 'name': 'A15', 'desc': 'Address bus line 15'}, - ] - 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'], - ] + ) + tuple({ + 'id': 'a%d' % i, + 'name': 'A%d' % i, + 'desc': 'Address bus line %d' % i + } for i in range(16) + ) + 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'), + ('warn', 'Warning message'), + ) annotation_rows = ( ('addrbus', 'Address bus', (Ann.ADDR,)), ('databus', 'Data bus', (Ann.MEMRD, Ann.MEMWR, Ann.IORD, Ann.IOWR)), @@ -127,9 +111,12 @@ class Decoder(srd.Decoder): ('warnings', 'Warnings', (Ann.WARN,)) ) - def __init__(self, **kwargs): + def __init__(self): + self.reset() + + def reset(self): 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) @@ -143,10 +130,13 @@ 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: + def decode(self): + while True: + # TODO: Come up with more appropriate self.wait() conditions. + pins = self.wait() cycle = Cycle.NONE if pins[Pin.MREQ] != 1: # default to asserted if pins[Pin.RD] == 0: @@ -180,11 +170,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, @@ -201,9 +192,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 @@ -211,9 +202,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 @@ -231,132 +225,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