2 ## This file is part of the libsigrokdecode project.
4 ## Copyright (C) 2014 Daniel Elstner <daniel.kitta@gmail.com>
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.
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.
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/>.
20 import sigrokdecode as srd
21 from functools import reduce
22 from .tables import instr_table_by_prefix
26 ADDR, MEMRD, MEMWR, IORD, IOWR, INSTR, ROP, WOP, WARN = range(9)
28 ADDRBUS, DATABUS, INSTRUCTIONS, OPERANDS, WARNINGS = range(5)
31 M1, RD, WR, MREQ, IORQ = range(8, 13)
34 NONE, MEMRD, MEMWR, IORD, IOWR, FETCH, INTACK = range(7)
36 # Provide custom format type 'H' for hexadecimal output
37 # with leading decimal digit (assembler syntax).
38 class 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
44 return format(value, format_spec)
46 formatter = AsmFormatter()
48 ann_data_cycle_map = {
49 Cycle.MEMRD: Ann.MEMRD,
50 Cycle.MEMWR: Ann.MEMWR,
53 Cycle.FETCH: Ann.MEMRD,
54 Cycle.INTACK: Ann.IORD,
59 return None # unassigned bus probes
61 return reduce(lambda a, b: (a << 1) | b, reversed(bus))
63 def signed_byte(byte):
64 return byte if byte < 128 else byte - 256
66 class Decoder(srd.Decoder):
70 longname = 'Zilog Z80 CPU'
71 desc = 'Zilog Z80 microprocessor disassembly.'
76 {'id': 'd%d' % i, 'name': 'D%d' % i, 'desc': 'Data bus line %d' % i}
79 {'id': 'm1', 'name': '/M1', 'desc': 'Machine cycle 1'},
80 {'id': 'rd', 'name': '/RD', 'desc': 'Memory or I/O read'},
81 {'id': 'wr', 'name': '/WR', 'desc': 'Memory or I/O write'},
84 {'id': 'mreq', 'name': '/MREQ', 'desc': 'Memory request'},
85 {'id': 'iorq', 'name': '/IORQ', 'desc': 'I/O request'},
87 {'id': 'a%d' % i, 'name': 'A%d' % i, 'desc': 'Address bus line %d' % i}
92 ['addr', 'Memory or I/O address'],
93 ['memrd', 'Byte read from memory'],
94 ['memwr', 'Byte written to memory'],
95 ['iord', 'Byte read from I/O port'],
96 ['iowr', 'Byte written to I/O port'],
97 ['instr', 'Z80 CPU instruction'],
98 ['rop', 'Value of input operand'],
99 ['wop', 'Value of output operand'],
100 ['warn', 'Warning message'],
103 ('addrbus', 'Address bus', (Ann.ADDR,)),
104 ('databus', 'Data bus', (Ann.MEMRD, Ann.MEMWR, Ann.IORD, Ann.IOWR)),
105 ('instructions', 'Instructions', (Ann.INSTR,)),
106 ('operands', 'Operands', (Ann.ROP, Ann.WOP)),
107 ('warnings', 'Warnings', (Ann.WARN,))
110 def __init__(self, **kwargs):
111 self.prev_cycle = Cycle.NONE
112 self.op_state = self.state_IDLE
115 self.out_ann = self.register(srd.OUTPUT_ANN)
117 self.samplenum = None
118 self.addr_start = None
119 self.data_start = None
120 self.dasm_start = None
121 self.pend_addr = None
122 self.pend_data = None
125 self.prev_cycle = Cycle.NONE
126 self.op_state = self.state_IDLE
129 def decode(self, ss, es, data):
130 for (self.samplenum, pins) in data:
132 if pins[Pin.MREQ] != 1: # default to asserted
133 if pins[Pin.RD] == 0:
134 cycle = Cycle.FETCH if pins[Pin.M1] == 0 else Cycle.MEMRD
135 elif pins[Pin.WR] == 0:
137 elif pins[Pin.IORQ] == 0: # default to not asserted
138 if pins[Pin.M1] == 0:
140 elif pins[Pin.RD] == 0:
142 elif pins[Pin.WR] == 0:
145 if cycle != Cycle.NONE:
146 self.bus_data = reduce_bus(pins[Pin.D0:Pin.D7+1])
147 if cycle != self.prev_cycle:
148 if self.prev_cycle == Cycle.NONE:
149 self.on_cycle_begin(reduce_bus(pins[Pin.A0:Pin.A15+1]))
150 elif cycle == Cycle.NONE:
153 self.on_cycle_trans()
154 self.prev_cycle = cycle
156 def on_cycle_begin(self, bus_addr):
157 if self.pend_addr is not None:
158 self.put_text(self.addr_start, Ann.ADDR,
159 '{:04X}'.format(self.pend_addr))
160 self.addr_start = self.samplenum
161 self.pend_addr = bus_addr
163 def on_cycle_end(self):
165 self.op_state = self.op_state()
166 if self.ann_dasm is not None:
168 if self.op_state == self.state_RESTART:
169 self.op_state = self.state_IDLE()
171 if self.ann_data is not None:
172 self.put_text(self.data_start, self.ann_data,
173 '{:02X}'.format(self.pend_data))
174 self.data_start = self.samplenum
175 self.pend_data = self.bus_data
176 self.ann_data = ann_data_cycle_map[self.prev_cycle]
178 def on_cycle_trans(self):
179 self.put_text(self.samplenum - 1, Ann.WARN,
180 'Illegal transition between control states')
181 self.pend_addr = None
185 def put_disasm(self):
186 text = formatter.format(self.mnemonic, r=self.arg_reg, d=self.arg_dis,
187 j=self.arg_dis+self.instr_len, i=self.arg_imm,
188 ro=self.arg_read, wo=self.arg_write)
189 self.put_text(self.dasm_start, self.ann_dasm, text)
191 self.dasm_start = self.samplenum
193 def put_text(self, ss, ann_idx, ann_text):
194 self.put(ss, self.samplenum, self.out_ann, [ann_idx, [ann_text]])
196 def state_RESTART(self):
197 return self.state_IDLE
199 def state_IDLE(self):
200 if self.prev_cycle != Cycle.FETCH:
201 return self.state_IDLE
206 self.want_wr_be = False
207 self.op_repeat = False
214 self.instr_pend = False
215 self.read_pend = False
216 self.write_pend = False
217 self.dasm_start = self.samplenum
220 if self.bus_data in (0xCB, 0xED, 0xDD, 0xFD):
221 return self.state_PRE1
223 return self.state_OPCODE
225 def state_PRE1(self):
226 if self.prev_cycle != Cycle.FETCH:
227 self.mnemonic = 'Prefix not followed by fetch'
228 self.ann_dasm = Ann.WARN
229 return self.state_RESTART
230 self.op_prefix = self.pend_data
231 if self.op_prefix in (0xDD, 0xFD):
232 if self.bus_data == 0xCB:
233 return self.state_PRE2
234 if self.bus_data in (0xDD, 0xED, 0xFD):
235 return self.state_PRE1
236 return self.state_OPCODE
238 def state_PRE2(self):
239 if self.prev_cycle != Cycle.MEMRD:
240 self.mnemonic = 'Missing displacement'
241 self.ann_dasm = Ann.WARN
242 return self.state_RESTART
243 self.op_prefix = (self.op_prefix << 8) | self.pend_data
244 return self.state_PREDIS
246 def state_PREDIS(self):
247 if self.prev_cycle != Cycle.MEMRD:
248 self.mnemonic = 'Missing opcode'
249 self.ann_dasm = Ann.WARN
250 return self.state_RESTART
251 self.arg_dis = signed_byte(self.pend_data)
252 return self.state_OPCODE
254 def state_OPCODE(self):
255 (table, self.arg_reg) = instr_table_by_prefix[self.op_prefix]
257 instruction = table.get(self.pend_data, None)
258 if instruction is None:
259 self.mnemonic = 'Invalid instruction'
260 self.ann_dasm = Ann.WARN
261 return self.state_RESTART
262 (self.want_dis, self.want_imm, self.want_read, want_write,
263 self.op_repeat, self.mnemonic) = instruction
264 self.want_write = abs(want_write)
265 self.want_wr_be = (want_write < 0)
266 if self.want_dis > 0:
267 return self.state_POSTDIS
268 if self.want_imm > 0:
269 return self.state_IMM1
270 self.ann_dasm = Ann.INSTR
271 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
272 return self.state_ROP1
273 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
274 return self.state_WOP1
275 return self.state_RESTART
277 def state_POSTDIS(self):
278 self.arg_dis = signed_byte(self.pend_data)
279 if self.want_imm > 0:
280 return self.state_IMM1
281 self.ann_dasm = Ann.INSTR
282 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
283 return self.state_ROP1
284 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
285 return self.state_WOP1
286 return self.state_RESTART
288 def state_IMM1(self):
289 self.arg_imm = self.pend_data
290 if self.want_imm > 1:
291 return self.state_IMM2
292 self.ann_dasm = Ann.INSTR
293 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
294 return self.state_ROP1
295 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
296 return self.state_WOP1
297 return self.state_RESTART
299 def state_IMM2(self):
300 self.arg_imm |= self.pend_data << 8
301 self.ann_dasm = Ann.INSTR
302 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
303 return self.state_ROP1
304 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
305 return self.state_WOP1
306 return self.state_RESTART
308 def state_ROP1(self):
309 self.arg_read = self.pend_data
310 if self.want_read < 2:
311 self.mnemonic = '{ro:02X}'
312 self.ann_dasm = Ann.ROP
313 if self.want_write > 0:
314 return self.state_WOP1
315 if self.want_read > 1:
316 return self.state_ROP2
317 if self.op_repeat and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
318 return self.state_ROP1
319 return self.state_RESTART
321 def state_ROP2(self):
322 self.arg_read |= self.pend_data << 8
323 self.mnemonic = '{ro:04X}'
324 self.ann_dasm = Ann.ROP
325 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
326 return self.state_WOP1
327 return self.state_RESTART
329 def state_WOP1(self):
330 self.arg_write = self.pend_data
331 if self.want_read > 1:
332 return self.state_ROP2
333 if self.want_write > 1:
334 return self.state_WOP2
335 self.mnemonic = '{wo:02X}'
336 self.ann_dasm = Ann.WOP
337 if self.want_read > 0 and self.op_repeat and \
338 self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
339 return self.state_ROP1
340 return self.state_RESTART
342 def state_WOP2(self):
344 self.arg_write = (self.arg_write << 8) | self.pend_data
346 self.arg_write |= self.pend_data << 8
347 self.mnemonic = '{wo:04X}'
348 self.ann_dasm = Ann.WOP
349 return self.state_RESTART