]> sigrok.org Git - libsigrokdecode.git/blame - decoders/z80/pd.py
Add PD tags handling and some tags
[libsigrokdecode.git] / decoders / z80 / pd.py
CommitLineData
26abbf37
DE
1##
2## This file is part of the libsigrokdecode project.
3##
4## Copyright (C) 2014 Daniel Elstner <daniel.kitta@gmail.com>
5##
6## This program is free software; you can redistribute it and/or modify
7## it under the terms of the GNU General Public License as published by
8## the Free Software Foundation; either version 3 of the License, or
9## (at your option) any later version.
10##
11## This program is distributed in the hope that it will be useful,
12## but WITHOUT ANY WARRANTY; without even the implied warranty of
13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14## GNU General Public License for more details.
15##
16## You should have received a copy of the GNU General Public License
17## along with this program; if not, see <http://www.gnu.org/licenses/>.
18##
19
20import sigrokdecode as srd
21from functools import reduce
22from .tables import instr_table_by_prefix
aef3c109 23import string
26abbf37
DE
24
25class Ann:
26 ADDR, MEMRD, MEMWR, IORD, IOWR, INSTR, ROP, WOP, WARN = range(9)
27class Row:
28 ADDRBUS, DATABUS, INSTRUCTIONS, OPERANDS, WARNINGS = range(5)
29class Pin:
30 D0, D7 = 0, 7
31 M1, RD, WR, MREQ, IORQ = range(8, 13)
32 A0, A15 = 13, 28
33class Cycle:
34 NONE, MEMRD, MEMWR, IORD, IOWR, FETCH, INTACK = range(7)
35
aef3c109
DE
36# Provide custom format type 'H' for hexadecimal output
37# with leading decimal digit (assembler syntax).
38class AsmFormatter(string.Formatter):
39 def format_field(self, value, format_spec):
40 if format_spec.endswith('H'):
41 result = format(value, format_spec[:-1] + 'X')
42 return result if result[0] in string.digits else '0' + result
43 else:
44 return format(value, format_spec)
45
46formatter = AsmFormatter()
47
26abbf37
DE
48ann_data_cycle_map = {
49 Cycle.MEMRD: Ann.MEMRD,
50 Cycle.MEMWR: Ann.MEMWR,
51 Cycle.IORD: Ann.IORD,
52 Cycle.IOWR: Ann.IOWR,
53 Cycle.FETCH: Ann.MEMRD,
54 Cycle.INTACK: Ann.IORD,
55}
56
57def reduce_bus(bus):
58 if 0xFF in bus:
6a15597a 59 return None # unassigned bus channels
26abbf37
DE
60 else:
61 return reduce(lambda a, b: (a << 1) | b, reversed(bus))
62
63def signed_byte(byte):
64 return byte if byte < 128 else byte - 256
65
66class Decoder(srd.Decoder):
2bde58c5 67 api_version = 3
e029ab1f
DE
68 id = 'z80'
69 name = 'Z80'
70 longname = 'Zilog Z80 CPU'
71 desc = 'Zilog Z80 microprocessor disassembly.'
486858f7 72 license = 'gplv3+'
e029ab1f
DE
73 inputs = ['logic']
74 outputs = ['z80']
4c180223 75 tags = ['Logic', 'MCU Debugging']
6a15597a 76 channels = tuple({
da9bcbd9
BV
77 'id': 'd%d' % i,
78 'name': 'D%d' % i,
79 'desc': 'Data bus line %d' % i
80 } for i in range(8)
81 ) + (
26abbf37
DE
82 {'id': 'm1', 'name': '/M1', 'desc': 'Machine cycle 1'},
83 {'id': 'rd', 'name': '/RD', 'desc': 'Memory or I/O read'},
84 {'id': 'wr', 'name': '/WR', 'desc': 'Memory or I/O write'},
da9bcbd9 85 )
6a15597a 86 optional_channels = (
26abbf37
DE
87 {'id': 'mreq', 'name': '/MREQ', 'desc': 'Memory request'},
88 {'id': 'iorq', 'name': '/IORQ', 'desc': 'I/O request'},
da9bcbd9
BV
89 ) + tuple({
90 'id': 'a%d' % i,
91 'name': 'A%d' % i,
92 'desc': 'Address bus line %d' % i
93 } for i in range(16)
94 )
95 annotations = (
96 ('addr', 'Memory or I/O address'),
97 ('memrd', 'Byte read from memory'),
98 ('memwr', 'Byte written to memory'),
99 ('iord', 'Byte read from I/O port'),
100 ('iowr', 'Byte written to I/O port'),
101 ('instr', 'Z80 CPU instruction'),
102 ('rop', 'Value of input operand'),
103 ('wop', 'Value of output operand'),
104 ('warn', 'Warning message'),
105 )
26abbf37
DE
106 annotation_rows = (
107 ('addrbus', 'Address bus', (Ann.ADDR,)),
108 ('databus', 'Data bus', (Ann.MEMRD, Ann.MEMWR, Ann.IORD, Ann.IOWR)),
109 ('instructions', 'Instructions', (Ann.INSTR,)),
110 ('operands', 'Operands', (Ann.ROP, Ann.WOP)),
111 ('warnings', 'Warnings', (Ann.WARN,))
112 )
113
92b7b49f 114 def __init__(self):
10aeb8ea
GS
115 self.reset()
116
117 def reset(self):
26abbf37 118 self.prev_cycle = Cycle.NONE
697967f2 119 self.op_state = self.state_IDLE
26abbf37
DE
120
121 def start(self):
122 self.out_ann = self.register(srd.OUTPUT_ANN)
123 self.bus_data = None
124 self.samplenum = None
125 self.addr_start = None
126 self.data_start = None
127 self.dasm_start = None
128 self.pend_addr = None
129 self.pend_data = None
130 self.ann_data = None
131 self.ann_dasm = None
132 self.prev_cycle = Cycle.NONE
697967f2 133 self.op_state = self.state_IDLE
8830db5d 134 self.instr_len = 0
26abbf37 135
2bde58c5
GS
136 def decode(self):
137 while True:
138 # TODO: Come up with more appropriate self.wait() conditions.
1b9ef18b 139 pins = self.wait()
26abbf37
DE
140 cycle = Cycle.NONE
141 if pins[Pin.MREQ] != 1: # default to asserted
142 if pins[Pin.RD] == 0:
143 cycle = Cycle.FETCH if pins[Pin.M1] == 0 else Cycle.MEMRD
144 elif pins[Pin.WR] == 0:
145 cycle = Cycle.MEMWR
146 elif pins[Pin.IORQ] == 0: # default to not asserted
147 if pins[Pin.M1] == 0:
148 cycle = Cycle.INTACK
149 elif pins[Pin.RD] == 0:
150 cycle = Cycle.IORD
151 elif pins[Pin.WR] == 0:
152 cycle = Cycle.IOWR
153
154 if cycle != Cycle.NONE:
155 self.bus_data = reduce_bus(pins[Pin.D0:Pin.D7+1])
156 if cycle != self.prev_cycle:
157 if self.prev_cycle == Cycle.NONE:
158 self.on_cycle_begin(reduce_bus(pins[Pin.A0:Pin.A15+1]))
159 elif cycle == Cycle.NONE:
160 self.on_cycle_end()
161 else:
162 self.on_cycle_trans()
163 self.prev_cycle = cycle
164
165 def on_cycle_begin(self, bus_addr):
166 if self.pend_addr is not None:
167 self.put_text(self.addr_start, Ann.ADDR,
168 '{:04X}'.format(self.pend_addr))
169 self.addr_start = self.samplenum
170 self.pend_addr = bus_addr
171
172 def on_cycle_end(self):
8830db5d 173 self.instr_len += 1
697967f2 174 self.op_state = self.op_state()
26abbf37
DE
175 if self.ann_dasm is not None:
176 self.put_disasm()
697967f2
DE
177 if self.op_state == self.state_RESTART:
178 self.op_state = self.state_IDLE()
26abbf37
DE
179
180 if self.ann_data is not None:
181 self.put_text(self.data_start, self.ann_data,
182 '{:02X}'.format(self.pend_data))
183 self.data_start = self.samplenum
184 self.pend_data = self.bus_data
185 self.ann_data = ann_data_cycle_map[self.prev_cycle]
186
187 def on_cycle_trans(self):
188 self.put_text(self.samplenum - 1, Ann.WARN,
189 'Illegal transition between control states')
190 self.pend_addr = None
191 self.ann_data = None
192 self.ann_dasm = None
193
194 def put_disasm(self):
8830db5d
DE
195 text = formatter.format(self.mnemonic, r=self.arg_reg, d=self.arg_dis,
196 j=self.arg_dis+self.instr_len, i=self.arg_imm,
aef3c109 197 ro=self.arg_read, wo=self.arg_write)
26abbf37
DE
198 self.put_text(self.dasm_start, self.ann_dasm, text)
199 self.ann_dasm = None
200 self.dasm_start = self.samplenum
201
202 def put_text(self, ss, ann_idx, ann_text):
203 self.put(ss, self.samplenum, self.out_ann, [ann_idx, [ann_text]])
204
697967f2
DE
205 def state_RESTART(self):
206 return self.state_IDLE
207
208 def state_IDLE(self):
26abbf37 209 if self.prev_cycle != Cycle.FETCH:
697967f2 210 return self.state_IDLE
26abbf37
DE
211 self.want_dis = 0
212 self.want_imm = 0
213 self.want_read = 0
214 self.want_write = 0
215 self.want_wr_be = False
216 self.op_repeat = False
217 self.arg_dis = 0
218 self.arg_imm = 0
219 self.arg_read = 0
220 self.arg_write = 0
221 self.arg_reg = ''
222 self.mnemonic = ''
223 self.instr_pend = False
224 self.read_pend = False
225 self.write_pend = False
226 self.dasm_start = self.samplenum
227 self.op_prefix = 0
8830db5d 228 self.instr_len = 0
26abbf37 229 if self.bus_data in (0xCB, 0xED, 0xDD, 0xFD):
697967f2 230 return self.state_PRE1
26abbf37 231 else:
697967f2 232 return self.state_OPCODE
26abbf37 233
697967f2 234 def state_PRE1(self):
26abbf37
DE
235 if self.prev_cycle != Cycle.FETCH:
236 self.mnemonic = 'Prefix not followed by fetch'
237 self.ann_dasm = Ann.WARN
697967f2 238 return self.state_RESTART
26abbf37
DE
239 self.op_prefix = self.pend_data
240 if self.op_prefix in (0xDD, 0xFD):
241 if self.bus_data == 0xCB:
697967f2 242 return self.state_PRE2
26abbf37 243 if self.bus_data in (0xDD, 0xED, 0xFD):
697967f2
DE
244 return self.state_PRE1
245 return self.state_OPCODE
26abbf37 246
697967f2 247 def state_PRE2(self):
26abbf37
DE
248 if self.prev_cycle != Cycle.MEMRD:
249 self.mnemonic = 'Missing displacement'
250 self.ann_dasm = Ann.WARN
697967f2 251 return self.state_RESTART
26abbf37 252 self.op_prefix = (self.op_prefix << 8) | self.pend_data
697967f2 253 return self.state_PREDIS
26abbf37 254
697967f2 255 def state_PREDIS(self):
26abbf37
DE
256 if self.prev_cycle != Cycle.MEMRD:
257 self.mnemonic = 'Missing opcode'
258 self.ann_dasm = Ann.WARN
697967f2 259 return self.state_RESTART
26abbf37 260 self.arg_dis = signed_byte(self.pend_data)
697967f2 261 return self.state_OPCODE
26abbf37 262
697967f2 263 def state_OPCODE(self):
26abbf37
DE
264 (table, self.arg_reg) = instr_table_by_prefix[self.op_prefix]
265 self.op_prefix = 0
266 instruction = table.get(self.pend_data, None)
267 if instruction is None:
268 self.mnemonic = 'Invalid instruction'
269 self.ann_dasm = Ann.WARN
697967f2 270 return self.state_RESTART
26abbf37
DE
271 (self.want_dis, self.want_imm, self.want_read, want_write,
272 self.op_repeat, self.mnemonic) = instruction
273 self.want_write = abs(want_write)
274 self.want_wr_be = (want_write < 0)
275 if self.want_dis > 0:
697967f2 276 return self.state_POSTDIS
26abbf37 277 if self.want_imm > 0:
697967f2 278 return self.state_IMM1
26abbf37
DE
279 self.ann_dasm = Ann.INSTR
280 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
697967f2 281 return self.state_ROP1
26abbf37 282 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
697967f2
DE
283 return self.state_WOP1
284 return self.state_RESTART
26abbf37 285
697967f2 286 def state_POSTDIS(self):
26abbf37
DE
287 self.arg_dis = signed_byte(self.pend_data)
288 if self.want_imm > 0:
697967f2 289 return self.state_IMM1
26abbf37 290 self.ann_dasm = Ann.INSTR
3831aa89 291 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
697967f2 292 return self.state_ROP1
3831aa89 293 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
697967f2
DE
294 return self.state_WOP1
295 return self.state_RESTART
26abbf37 296
697967f2 297 def state_IMM1(self):
26abbf37
DE
298 self.arg_imm = self.pend_data
299 if self.want_imm > 1:
697967f2 300 return self.state_IMM2
26abbf37 301 self.ann_dasm = Ann.INSTR
3831aa89 302 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
697967f2 303 return self.state_ROP1
3831aa89 304 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
697967f2
DE
305 return self.state_WOP1
306 return self.state_RESTART
26abbf37 307
697967f2 308 def state_IMM2(self):
26abbf37
DE
309 self.arg_imm |= self.pend_data << 8
310 self.ann_dasm = Ann.INSTR
3831aa89 311 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
697967f2 312 return self.state_ROP1
3831aa89 313 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
697967f2
DE
314 return self.state_WOP1
315 return self.state_RESTART
26abbf37 316
697967f2 317 def state_ROP1(self):
26abbf37 318 self.arg_read = self.pend_data
739f9313
DE
319 if self.want_read < 2:
320 self.mnemonic = '{ro:02X}'
321 self.ann_dasm = Ann.ROP
26abbf37 322 if self.want_write > 0:
697967f2 323 return self.state_WOP1
26abbf37 324 if self.want_read > 1:
697967f2 325 return self.state_ROP2
26abbf37 326 if self.op_repeat and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
697967f2
DE
327 return self.state_ROP1
328 return self.state_RESTART
26abbf37 329
697967f2 330 def state_ROP2(self):
26abbf37
DE
331 self.arg_read |= self.pend_data << 8
332 self.mnemonic = '{ro:04X}'
333 self.ann_dasm = Ann.ROP
3831aa89 334 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
697967f2
DE
335 return self.state_WOP1
336 return self.state_RESTART
26abbf37 337
697967f2 338 def state_WOP1(self):
26abbf37
DE
339 self.arg_write = self.pend_data
340 if self.want_read > 1:
697967f2 341 return self.state_ROP2
26abbf37 342 if self.want_write > 1:
697967f2 343 return self.state_WOP2
739f9313
DE
344 self.mnemonic = '{wo:02X}'
345 self.ann_dasm = Ann.WOP
26abbf37
DE
346 if self.want_read > 0 and self.op_repeat and \
347 self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
697967f2
DE
348 return self.state_ROP1
349 return self.state_RESTART
26abbf37 350
697967f2 351 def state_WOP2(self):
26abbf37
DE
352 if self.want_wr_be:
353 self.arg_write = (self.arg_write << 8) | self.pend_data
354 else:
355 self.arg_write |= self.pend_data << 8
356 self.mnemonic = '{wo:04X}'
357 self.ann_dasm = Ann.WOP
697967f2 358 return self.state_RESTART