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.'
75 tags = ['Retro computing']
79 'desc': 'Data bus line %d' % i
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'},
87 {'id': 'mreq', 'name': '/MREQ', 'desc': 'Memory request'},
88 {'id': 'iorq', 'name': '/IORQ', 'desc': 'I/O request'},
92 'desc': 'Address bus line %d' % i
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 ('warning', 'Warning'),
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,))
118 self.prev_cycle = Cycle.NONE
119 self.op_state = self.state_IDLE
122 self.out_ann = self.register(srd.OUTPUT_ANN)
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
132 self.prev_cycle = Cycle.NONE
133 self.op_state = self.state_IDLE
138 # TODO: Come up with more appropriate self.wait() conditions.
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:
146 elif pins[Pin.IORQ] == 0: # default to not asserted
147 if pins[Pin.M1] == 0:
149 elif pins[Pin.RD] == 0:
151 elif pins[Pin.WR] == 0:
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:
162 self.on_cycle_trans()
163 self.prev_cycle = cycle
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
172 def on_cycle_end(self):
174 self.op_state = self.op_state()
175 if self.ann_dasm is not None:
177 if self.op_state == self.state_RESTART:
178 self.op_state = self.state_IDLE()
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]
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
194 def put_disasm(self):
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,
197 ro=self.arg_read, wo=self.arg_write)
198 self.put_text(self.dasm_start, self.ann_dasm, text)
200 self.dasm_start = self.samplenum
202 def put_text(self, ss, ann_idx, ann_text):
203 self.put(ss, self.samplenum, self.out_ann, [ann_idx, [ann_text]])
205 def state_RESTART(self):
206 return self.state_IDLE
208 def state_IDLE(self):
209 if self.prev_cycle != Cycle.FETCH:
210 return self.state_IDLE
215 self.want_wr_be = False
216 self.op_repeat = False
223 self.instr_pend = False
224 self.read_pend = False
225 self.write_pend = False
226 self.dasm_start = self.samplenum
229 if self.bus_data in (0xCB, 0xED, 0xDD, 0xFD):
230 return self.state_PRE1
232 return self.state_OPCODE
234 def state_PRE1(self):
235 if self.prev_cycle != Cycle.FETCH:
236 self.mnemonic = 'Prefix not followed by fetch'
237 self.ann_dasm = Ann.WARN
238 return self.state_RESTART
239 self.op_prefix = self.pend_data
240 if self.op_prefix in (0xDD, 0xFD):
241 if self.bus_data == 0xCB:
242 return self.state_PRE2
243 if self.bus_data in (0xDD, 0xED, 0xFD):
244 return self.state_PRE1
245 return self.state_OPCODE
247 def state_PRE2(self):
248 if self.prev_cycle != Cycle.MEMRD:
249 self.mnemonic = 'Missing displacement'
250 self.ann_dasm = Ann.WARN
251 return self.state_RESTART
252 self.op_prefix = (self.op_prefix << 8) | self.pend_data
253 return self.state_PREDIS
255 def state_PREDIS(self):
256 if self.prev_cycle != Cycle.MEMRD:
257 self.mnemonic = 'Missing opcode'
258 self.ann_dasm = Ann.WARN
259 return self.state_RESTART
260 self.arg_dis = signed_byte(self.pend_data)
261 return self.state_OPCODE
263 def state_OPCODE(self):
264 (table, self.arg_reg) = instr_table_by_prefix[self.op_prefix]
266 instruction = table.get(self.pend_data, None)
267 if instruction is None:
268 self.mnemonic = 'Invalid instruction'
269 self.ann_dasm = Ann.WARN
270 return self.state_RESTART
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:
276 return self.state_POSTDIS
277 if self.want_imm > 0:
278 return self.state_IMM1
279 self.ann_dasm = Ann.INSTR
280 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
281 return self.state_ROP1
282 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
283 return self.state_WOP1
284 return self.state_RESTART
286 def state_POSTDIS(self):
287 self.arg_dis = signed_byte(self.pend_data)
288 if self.want_imm > 0:
289 return self.state_IMM1
290 self.ann_dasm = Ann.INSTR
291 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
292 return self.state_ROP1
293 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
294 return self.state_WOP1
295 return self.state_RESTART
297 def state_IMM1(self):
298 self.arg_imm = self.pend_data
299 if self.want_imm > 1:
300 return self.state_IMM2
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_IMM2(self):
309 self.arg_imm |= self.pend_data << 8
310 self.ann_dasm = Ann.INSTR
311 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
312 return self.state_ROP1
313 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
314 return self.state_WOP1
315 return self.state_RESTART
317 def state_ROP1(self):
318 self.arg_read = self.pend_data
319 if self.want_read < 2:
320 self.mnemonic = '{ro:02X}'
321 self.ann_dasm = Ann.ROP
322 if self.want_write > 0:
323 return self.state_WOP1
324 if self.want_read > 1:
325 return self.state_ROP2
326 if self.op_repeat and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
327 return self.state_ROP1
328 return self.state_RESTART
330 def state_ROP2(self):
331 self.arg_read |= self.pend_data << 8
332 self.mnemonic = '{ro:04X}'
333 self.ann_dasm = Ann.ROP
334 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
335 return self.state_WOP1
336 return self.state_RESTART
338 def state_WOP1(self):
339 self.arg_write = self.pend_data
340 if self.want_read > 1:
341 return self.state_ROP2
342 if self.want_write > 1:
343 return self.state_WOP2
344 self.mnemonic = '{wo:02X}'
345 self.ann_dasm = Ann.WOP
346 if self.want_read > 0 and self.op_repeat and \
347 self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
348 return self.state_ROP1
349 return self.state_RESTART
351 def state_WOP2(self):
353 self.arg_write = (self.arg_write << 8) | self.pend_data
355 self.arg_write |= self.pend_data << 8
356 self.mnemonic = '{wo:04X}'
357 self.ann_dasm = Ann.WOP
358 return self.state_RESTART