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,))
117 self.prev_cycle = Cycle.NONE
118 self.op_state = self.state_IDLE
121 self.out_ann = self.register(srd.OUTPUT_ANN)
123 self.samplenum = None
124 self.addr_start = None
125 self.data_start = None
126 self.dasm_start = None
127 self.pend_addr = None
128 self.pend_data = None
131 self.prev_cycle = Cycle.NONE
132 self.op_state = self.state_IDLE
137 # TODO: Come up with more appropriate self.wait() conditions.
140 if pins[Pin.MREQ] != 1: # default to asserted
141 if pins[Pin.RD] == 0:
142 cycle = Cycle.FETCH if pins[Pin.M1] == 0 else Cycle.MEMRD
143 elif pins[Pin.WR] == 0:
145 elif pins[Pin.IORQ] == 0: # default to not asserted
146 if pins[Pin.M1] == 0:
148 elif pins[Pin.RD] == 0:
150 elif pins[Pin.WR] == 0:
153 if cycle != Cycle.NONE:
154 self.bus_data = reduce_bus(pins[Pin.D0:Pin.D7+1])
155 if cycle != self.prev_cycle:
156 if self.prev_cycle == Cycle.NONE:
157 self.on_cycle_begin(reduce_bus(pins[Pin.A0:Pin.A15+1]))
158 elif cycle == Cycle.NONE:
161 self.on_cycle_trans()
162 self.prev_cycle = cycle
164 def on_cycle_begin(self, bus_addr):
165 if self.pend_addr is not None:
166 self.put_text(self.addr_start, Ann.ADDR,
167 '{:04X}'.format(self.pend_addr))
168 self.addr_start = self.samplenum
169 self.pend_addr = bus_addr
171 def on_cycle_end(self):
173 self.op_state = self.op_state()
174 if self.ann_dasm is not None:
176 if self.op_state == self.state_RESTART:
177 self.op_state = self.state_IDLE()
179 if self.ann_data is not None:
180 self.put_text(self.data_start, self.ann_data,
181 '{:02X}'.format(self.pend_data))
182 self.data_start = self.samplenum
183 self.pend_data = self.bus_data
184 self.ann_data = ann_data_cycle_map[self.prev_cycle]
186 def on_cycle_trans(self):
187 self.put_text(self.samplenum - 1, Ann.WARN,
188 'Illegal transition between control states')
189 self.pend_addr = None
193 def put_disasm(self):
194 text = formatter.format(self.mnemonic, r=self.arg_reg, d=self.arg_dis,
195 j=self.arg_dis+self.instr_len, i=self.arg_imm,
196 ro=self.arg_read, wo=self.arg_write)
197 self.put_text(self.dasm_start, self.ann_dasm, text)
199 self.dasm_start = self.samplenum
201 def put_text(self, ss, ann_idx, ann_text):
202 self.put(ss, self.samplenum, self.out_ann, [ann_idx, [ann_text]])
204 def state_RESTART(self):
205 return self.state_IDLE
207 def state_IDLE(self):
208 if self.prev_cycle != Cycle.FETCH:
209 return self.state_IDLE
214 self.want_wr_be = False
215 self.op_repeat = False
222 self.instr_pend = False
223 self.read_pend = False
224 self.write_pend = False
225 self.dasm_start = self.samplenum
228 if self.bus_data in (0xCB, 0xED, 0xDD, 0xFD):
229 return self.state_PRE1
231 return self.state_OPCODE
233 def state_PRE1(self):
234 if self.prev_cycle != Cycle.FETCH:
235 self.mnemonic = 'Prefix not followed by fetch'
236 self.ann_dasm = Ann.WARN
237 return self.state_RESTART
238 self.op_prefix = self.pend_data
239 if self.op_prefix in (0xDD, 0xFD):
240 if self.bus_data == 0xCB:
241 return self.state_PRE2
242 if self.bus_data in (0xDD, 0xED, 0xFD):
243 return self.state_PRE1
244 return self.state_OPCODE
246 def state_PRE2(self):
247 if self.prev_cycle != Cycle.MEMRD:
248 self.mnemonic = 'Missing displacement'
249 self.ann_dasm = Ann.WARN
250 return self.state_RESTART
251 self.op_prefix = (self.op_prefix << 8) | self.pend_data
252 return self.state_PREDIS
254 def state_PREDIS(self):
255 if self.prev_cycle != Cycle.MEMRD:
256 self.mnemonic = 'Missing opcode'
257 self.ann_dasm = Ann.WARN
258 return self.state_RESTART
259 self.arg_dis = signed_byte(self.pend_data)
260 return self.state_OPCODE
262 def state_OPCODE(self):
263 (table, self.arg_reg) = instr_table_by_prefix[self.op_prefix]
265 instruction = table.get(self.pend_data, None)
266 if instruction is None:
267 self.mnemonic = 'Invalid instruction'
268 self.ann_dasm = Ann.WARN
269 return self.state_RESTART
270 (self.want_dis, self.want_imm, self.want_read, want_write,
271 self.op_repeat, self.mnemonic) = instruction
272 self.want_write = abs(want_write)
273 self.want_wr_be = (want_write < 0)
274 if self.want_dis > 0:
275 return self.state_POSTDIS
276 if self.want_imm > 0:
277 return self.state_IMM1
278 self.ann_dasm = Ann.INSTR
279 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
280 return self.state_ROP1
281 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
282 return self.state_WOP1
283 return self.state_RESTART
285 def state_POSTDIS(self):
286 self.arg_dis = signed_byte(self.pend_data)
287 if self.want_imm > 0:
288 return self.state_IMM1
289 self.ann_dasm = Ann.INSTR
290 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
291 return self.state_ROP1
292 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
293 return self.state_WOP1
294 return self.state_RESTART
296 def state_IMM1(self):
297 self.arg_imm = self.pend_data
298 if self.want_imm > 1:
299 return self.state_IMM2
300 self.ann_dasm = Ann.INSTR
301 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
302 return self.state_ROP1
303 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
304 return self.state_WOP1
305 return self.state_RESTART
307 def state_IMM2(self):
308 self.arg_imm |= self.pend_data << 8
309 self.ann_dasm = Ann.INSTR
310 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
311 return self.state_ROP1
312 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
313 return self.state_WOP1
314 return self.state_RESTART
316 def state_ROP1(self):
317 self.arg_read = self.pend_data
318 if self.want_read < 2:
319 self.mnemonic = '{ro:02X}'
320 self.ann_dasm = Ann.ROP
321 if self.want_write > 0:
322 return self.state_WOP1
323 if self.want_read > 1:
324 return self.state_ROP2
325 if self.op_repeat and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
326 return self.state_ROP1
327 return self.state_RESTART
329 def state_ROP2(self):
330 self.arg_read |= self.pend_data << 8
331 self.mnemonic = '{ro:04X}'
332 self.ann_dasm = Ann.ROP
333 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
334 return self.state_WOP1
335 return self.state_RESTART
337 def state_WOP1(self):
338 self.arg_write = self.pend_data
339 if self.want_read > 1:
340 return self.state_ROP2
341 if self.want_write > 1:
342 return self.state_WOP2
343 self.mnemonic = '{wo:02X}'
344 self.ann_dasm = Ann.WOP
345 if self.want_read > 0 and self.op_repeat and \
346 self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
347 return self.state_ROP1
348 return self.state_RESTART
350 def state_WOP2(self):
352 self.arg_write = (self.arg_write << 8) | self.pend_data
354 self.arg_write |= self.pend_data << 8
355 self.mnemonic = '{wo:04X}'
356 self.ann_dasm = Ann.WOP
357 return self.state_RESTART