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 channels
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.'
78 'desc': 'Data bus line %d' % i
81 {'id': 'm1', 'name': '/M1', 'desc': 'Machine cycle 1'},
82 {'id': 'rd', 'name': '/RD', 'desc': 'Memory or I/O read'},
83 {'id': 'wr', 'name': '/WR', 'desc': 'Memory or I/O write'},
86 {'id': 'mreq', 'name': '/MREQ', 'desc': 'Memory request'},
87 {'id': 'iorq', 'name': '/IORQ', 'desc': 'I/O request'},
91 'desc': 'Address bus line %d' % i
95 ('addr', 'Memory or I/O address'),
96 ('memrd', 'Byte read from memory'),
97 ('memwr', 'Byte written to memory'),
98 ('iord', 'Byte read from I/O port'),
99 ('iowr', 'Byte written to I/O port'),
100 ('instr', 'Z80 CPU instruction'),
101 ('rop', 'Value of input operand'),
102 ('wop', 'Value of output operand'),
103 ('warn', 'Warning message'),
106 ('addrbus', 'Address bus', (Ann.ADDR,)),
107 ('databus', 'Data bus', (Ann.MEMRD, Ann.MEMWR, Ann.IORD, Ann.IOWR)),
108 ('instructions', 'Instructions', (Ann.INSTR,)),
109 ('operands', 'Operands', (Ann.ROP, Ann.WOP)),
110 ('warnings', 'Warnings', (Ann.WARN,))
114 self.prev_cycle = Cycle.NONE
115 self.op_state = self.state_IDLE
118 self.out_ann = self.register(srd.OUTPUT_ANN)
120 self.samplenum = None
121 self.addr_start = None
122 self.data_start = None
123 self.dasm_start = None
124 self.pend_addr = None
125 self.pend_data = None
128 self.prev_cycle = Cycle.NONE
129 self.op_state = self.state_IDLE
134 # TODO: Come up with more appropriate self.wait() conditions.
135 pins = self.wait({'skip': 1})
137 if pins[Pin.MREQ] != 1: # default to asserted
138 if pins[Pin.RD] == 0:
139 cycle = Cycle.FETCH if pins[Pin.M1] == 0 else Cycle.MEMRD
140 elif pins[Pin.WR] == 0:
142 elif pins[Pin.IORQ] == 0: # default to not asserted
143 if pins[Pin.M1] == 0:
145 elif pins[Pin.RD] == 0:
147 elif pins[Pin.WR] == 0:
150 if cycle != Cycle.NONE:
151 self.bus_data = reduce_bus(pins[Pin.D0:Pin.D7+1])
152 if cycle != self.prev_cycle:
153 if self.prev_cycle == Cycle.NONE:
154 self.on_cycle_begin(reduce_bus(pins[Pin.A0:Pin.A15+1]))
155 elif cycle == Cycle.NONE:
158 self.on_cycle_trans()
159 self.prev_cycle = cycle
161 def on_cycle_begin(self, bus_addr):
162 if self.pend_addr is not None:
163 self.put_text(self.addr_start, Ann.ADDR,
164 '{:04X}'.format(self.pend_addr))
165 self.addr_start = self.samplenum
166 self.pend_addr = bus_addr
168 def on_cycle_end(self):
170 self.op_state = self.op_state()
171 if self.ann_dasm is not None:
173 if self.op_state == self.state_RESTART:
174 self.op_state = self.state_IDLE()
176 if self.ann_data is not None:
177 self.put_text(self.data_start, self.ann_data,
178 '{:02X}'.format(self.pend_data))
179 self.data_start = self.samplenum
180 self.pend_data = self.bus_data
181 self.ann_data = ann_data_cycle_map[self.prev_cycle]
183 def on_cycle_trans(self):
184 self.put_text(self.samplenum - 1, Ann.WARN,
185 'Illegal transition between control states')
186 self.pend_addr = None
190 def put_disasm(self):
191 text = formatter.format(self.mnemonic, r=self.arg_reg, d=self.arg_dis,
192 j=self.arg_dis+self.instr_len, i=self.arg_imm,
193 ro=self.arg_read, wo=self.arg_write)
194 self.put_text(self.dasm_start, self.ann_dasm, text)
196 self.dasm_start = self.samplenum
198 def put_text(self, ss, ann_idx, ann_text):
199 self.put(ss, self.samplenum, self.out_ann, [ann_idx, [ann_text]])
201 def state_RESTART(self):
202 return self.state_IDLE
204 def state_IDLE(self):
205 if self.prev_cycle != Cycle.FETCH:
206 return self.state_IDLE
211 self.want_wr_be = False
212 self.op_repeat = False
219 self.instr_pend = False
220 self.read_pend = False
221 self.write_pend = False
222 self.dasm_start = self.samplenum
225 if self.bus_data in (0xCB, 0xED, 0xDD, 0xFD):
226 return self.state_PRE1
228 return self.state_OPCODE
230 def state_PRE1(self):
231 if self.prev_cycle != Cycle.FETCH:
232 self.mnemonic = 'Prefix not followed by fetch'
233 self.ann_dasm = Ann.WARN
234 return self.state_RESTART
235 self.op_prefix = self.pend_data
236 if self.op_prefix in (0xDD, 0xFD):
237 if self.bus_data == 0xCB:
238 return self.state_PRE2
239 if self.bus_data in (0xDD, 0xED, 0xFD):
240 return self.state_PRE1
241 return self.state_OPCODE
243 def state_PRE2(self):
244 if self.prev_cycle != Cycle.MEMRD:
245 self.mnemonic = 'Missing displacement'
246 self.ann_dasm = Ann.WARN
247 return self.state_RESTART
248 self.op_prefix = (self.op_prefix << 8) | self.pend_data
249 return self.state_PREDIS
251 def state_PREDIS(self):
252 if self.prev_cycle != Cycle.MEMRD:
253 self.mnemonic = 'Missing opcode'
254 self.ann_dasm = Ann.WARN
255 return self.state_RESTART
256 self.arg_dis = signed_byte(self.pend_data)
257 return self.state_OPCODE
259 def state_OPCODE(self):
260 (table, self.arg_reg) = instr_table_by_prefix[self.op_prefix]
262 instruction = table.get(self.pend_data, None)
263 if instruction is None:
264 self.mnemonic = 'Invalid instruction'
265 self.ann_dasm = Ann.WARN
266 return self.state_RESTART
267 (self.want_dis, self.want_imm, self.want_read, want_write,
268 self.op_repeat, self.mnemonic) = instruction
269 self.want_write = abs(want_write)
270 self.want_wr_be = (want_write < 0)
271 if self.want_dis > 0:
272 return self.state_POSTDIS
273 if self.want_imm > 0:
274 return self.state_IMM1
275 self.ann_dasm = Ann.INSTR
276 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
277 return self.state_ROP1
278 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
279 return self.state_WOP1
280 return self.state_RESTART
282 def state_POSTDIS(self):
283 self.arg_dis = signed_byte(self.pend_data)
284 if self.want_imm > 0:
285 return self.state_IMM1
286 self.ann_dasm = Ann.INSTR
287 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
288 return self.state_ROP1
289 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
290 return self.state_WOP1
291 return self.state_RESTART
293 def state_IMM1(self):
294 self.arg_imm = self.pend_data
295 if self.want_imm > 1:
296 return self.state_IMM2
297 self.ann_dasm = Ann.INSTR
298 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
299 return self.state_ROP1
300 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
301 return self.state_WOP1
302 return self.state_RESTART
304 def state_IMM2(self):
305 self.arg_imm |= self.pend_data << 8
306 self.ann_dasm = Ann.INSTR
307 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
308 return self.state_ROP1
309 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
310 return self.state_WOP1
311 return self.state_RESTART
313 def state_ROP1(self):
314 self.arg_read = self.pend_data
315 if self.want_read < 2:
316 self.mnemonic = '{ro:02X}'
317 self.ann_dasm = Ann.ROP
318 if self.want_write > 0:
319 return self.state_WOP1
320 if self.want_read > 1:
321 return self.state_ROP2
322 if self.op_repeat and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
323 return self.state_ROP1
324 return self.state_RESTART
326 def state_ROP2(self):
327 self.arg_read |= self.pend_data << 8
328 self.mnemonic = '{ro:04X}'
329 self.ann_dasm = Ann.ROP
330 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
331 return self.state_WOP1
332 return self.state_RESTART
334 def state_WOP1(self):
335 self.arg_write = self.pend_data
336 if self.want_read > 1:
337 return self.state_ROP2
338 if self.want_write > 1:
339 return self.state_WOP2
340 self.mnemonic = '{wo:02X}'
341 self.ann_dasm = Ann.WOP
342 if self.want_read > 0 and self.op_repeat and \
343 self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
344 return self.state_ROP1
345 return self.state_RESTART
347 def state_WOP2(self):
349 self.arg_write = (self.arg_write << 8) | self.pend_data
351 self.arg_write |= self.pend_data << 8
352 self.mnemonic = '{wo:04X}'
353 self.ann_dasm = Ann.WOP
354 return self.state_RESTART