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
25 ADDR, MEMRD, MEMWR, IORD, IOWR, INSTR, ROP, WOP, WARN = range(9)
27 ADDRBUS, DATABUS, INSTRUCTIONS, OPERANDS, WARNINGS = range(5)
30 M1, RD, WR, MREQ, IORQ = range(8, 13)
33 NONE, MEMRD, MEMWR, IORD, IOWR, FETCH, INTACK = range(7)
36 IDLE = 'IDLE' # no current instruction
37 PRE1 = 'PRE1' # first prefix
38 PRE2 = 'PRE2' # second prefix
39 PREDIS = 'PREDIS' # pre-opcode displacement
40 OPCODE = 'OPCODE' # opcode byte
41 POSTDIS = 'POSTDIS' # post-opcode displacement
42 IMM1 = 'IMM1' # first byte of immediate
43 IMM2 = 'IMM2' # second byte of immediate
44 ROP1 = 'ROP1' # first byte of read operand
45 ROP2 = 'ROP2' # second byte of read operand
46 WOP1 = 'WOP1' # first byte of write operand
47 WOP2 = 'WOP2' # second byte of write operand
48 RESTART = 'RESTART' # restart instruction decoding
50 ann_data_cycle_map = {
51 Cycle.MEMRD: Ann.MEMRD,
52 Cycle.MEMWR: Ann.MEMWR,
55 Cycle.FETCH: Ann.MEMRD,
56 Cycle.INTACK: Ann.IORD,
61 return None # unassigned bus probes
63 return reduce(lambda a, b: (a << 1) | b, reversed(bus))
65 def signed_byte(byte):
66 return byte if byte < 128 else byte - 256
68 class Decoder(srd.Decoder):
72 longname = 'Zilog Z80 CPU'
73 desc = 'Zilog Z80 microprocessor disassembly.'
78 {'id': 'd%d' % i, 'name': 'D%d' % i, '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'},
89 {'id': 'a%d' % i, 'name': 'A%d' % i, 'desc': 'Address bus line %d' % i}
94 ['addr', 'Memory or I/O address'],
95 ['memrd', 'Byte read from memory'],
96 ['memwr', 'Byte written to memory'],
97 ['iord', 'Byte read from I/O port'],
98 ['iowr', 'Byte written to I/O port'],
99 ['instr', 'Z80 CPU instruction'],
100 ['rop', 'Value of input operand'],
101 ['wop', 'Value of output operand'],
102 ['warning', 'Warning message'],
105 ('addrbus', 'Address bus', (Ann.ADDR,)),
106 ('databus', 'Data bus', (Ann.MEMRD, Ann.MEMWR, Ann.IORD, Ann.IOWR)),
107 ('instructions', 'Instructions', (Ann.INSTR,)),
108 ('operands', 'Operands', (Ann.ROP, Ann.WOP)),
109 ('warnings', 'Warnings', (Ann.WARN,))
112 def __init__(self, **kwargs):
113 self.prev_cycle = Cycle.NONE
114 self.op_state = OpState.IDLE
117 self.out_ann = self.register(srd.OUTPUT_ANN)
119 self.samplenum = None
120 self.addr_start = None
121 self.data_start = None
122 self.dasm_start = None
123 self.pend_addr = None
124 self.pend_data = None
127 self.prev_cycle = Cycle.NONE
128 self.op_state = OpState.IDLE
130 def decode(self, ss, es, data):
131 for (self.samplenum, pins) in data:
133 if pins[Pin.MREQ] != 1: # default to asserted
134 if pins[Pin.RD] == 0:
135 cycle = Cycle.FETCH if pins[Pin.M1] == 0 else Cycle.MEMRD
136 elif pins[Pin.WR] == 0:
138 elif pins[Pin.IORQ] == 0: # default to not asserted
139 if pins[Pin.M1] == 0:
141 elif pins[Pin.RD] == 0:
143 elif pins[Pin.WR] == 0:
146 if cycle != Cycle.NONE:
147 self.bus_data = reduce_bus(pins[Pin.D0:Pin.D7+1])
148 if cycle != self.prev_cycle:
149 if self.prev_cycle == Cycle.NONE:
150 self.on_cycle_begin(reduce_bus(pins[Pin.A0:Pin.A15+1]))
151 elif cycle == Cycle.NONE:
154 self.on_cycle_trans()
155 self.prev_cycle = cycle
157 def on_cycle_begin(self, bus_addr):
158 if self.pend_addr is not None:
159 self.put_text(self.addr_start, Ann.ADDR,
160 '{:04X}'.format(self.pend_addr))
161 self.addr_start = self.samplenum
162 self.pend_addr = bus_addr
164 def on_cycle_end(self):
165 self.op_state = getattr(self, 'on_state_' + self.op_state)()
166 if self.ann_dasm is not None:
168 if self.op_state == OpState.RESTART:
169 self.op_state = self.on_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 = self.mnemonic.format(r=self.arg_reg, d=self.arg_dis,
187 i=self.arg_imm, ro=self.arg_read,
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 on_state_IDLE(self):
197 if self.prev_cycle != Cycle.FETCH:
203 self.want_wr_be = False
204 self.op_repeat = False
211 self.instr_pend = False
212 self.read_pend = False
213 self.write_pend = False
214 self.dasm_start = self.samplenum
216 if self.bus_data in (0xCB, 0xED, 0xDD, 0xFD):
219 return OpState.OPCODE
221 def on_state_PRE1(self):
222 if self.prev_cycle != Cycle.FETCH:
223 self.mnemonic = 'Prefix not followed by fetch'
224 self.ann_dasm = Ann.WARN
225 return OpState.RESTART
226 self.op_prefix = self.pend_data
227 if self.op_prefix in (0xDD, 0xFD):
228 if self.bus_data == 0xCB:
230 if self.bus_data in (0xDD, 0xED, 0xFD):
232 return OpState.OPCODE
234 def on_state_PRE2(self):
235 if self.prev_cycle != Cycle.MEMRD:
236 self.mnemonic = 'Missing displacement'
237 self.ann_dasm = Ann.WARN
238 return OpState.RESTART
239 self.op_prefix = (self.op_prefix << 8) | self.pend_data
240 return OpState.PREDIS
242 def on_state_PREDIS(self):
243 if self.prev_cycle != Cycle.MEMRD:
244 self.mnemonic = 'Missing opcode'
245 self.ann_dasm = Ann.WARN
246 return OpState.RESTART
247 self.arg_dis = signed_byte(self.pend_data)
248 return OpState.OPCODE
250 def on_state_OPCODE(self):
251 (table, self.arg_reg) = instr_table_by_prefix[self.op_prefix]
253 instruction = table.get(self.pend_data, None)
254 if instruction is None:
255 self.mnemonic = 'Invalid instruction'
256 self.ann_dasm = Ann.WARN
257 return OpState.RESTART
258 (self.want_dis, self.want_imm, self.want_read, want_write,
259 self.op_repeat, self.mnemonic) = instruction
260 self.want_write = abs(want_write)
261 self.want_wr_be = (want_write < 0)
262 if self.want_dis > 0:
263 return OpState.POSTDIS
264 if self.want_imm > 0:
266 self.ann_dasm = Ann.INSTR
267 if self.want_read > 0 and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
269 if self.want_write > 0 and self.prev_cycle in (Cycle.MEMWR, Cycle.IOWR):
271 return OpState.RESTART
273 def on_state_POSTDIS(self):
274 self.arg_dis = signed_byte(self.pend_data)
275 if self.want_imm > 0:
277 self.ann_dasm = Ann.INSTR
278 if self.want_read > 0:
280 if self.want_write > 0:
282 return OpState.RESTART
284 def on_state_IMM1(self):
285 self.arg_imm = self.pend_data
286 if self.want_imm > 1:
288 self.ann_dasm = Ann.INSTR
289 if self.want_read > 0:
291 if self.want_write > 0:
293 return OpState.RESTART
295 def on_state_IMM2(self):
296 self.arg_imm |= self.pend_data << 8
297 self.ann_dasm = Ann.INSTR
298 if self.want_read > 0:
300 if self.want_write > 0:
302 return OpState.RESTART
304 def on_state_ROP1(self):
305 self.arg_read = self.pend_data
306 if self.want_write > 0:
308 if self.want_read > 1:
310 if self.op_repeat and self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
312 self.mnemonic = '{ro:02X}'
313 self.ann_dasm = Ann.ROP
314 return OpState.RESTART
316 def on_state_ROP2(self):
317 self.arg_read |= self.pend_data << 8
318 self.mnemonic = '{ro:04X}'
319 self.ann_dasm = Ann.ROP
320 if self.want_write > 0:
322 return OpState.RESTART
324 def on_state_WOP1(self):
325 self.arg_write = self.pend_data
326 if self.want_read > 1:
328 if self.want_write > 1:
330 if self.want_read > 0 and self.op_repeat and \
331 self.prev_cycle in (Cycle.MEMRD, Cycle.IORD):
333 self.mnemonic = '{wo:02X}'
334 self.ann_dasm = Ann.WOP
335 return OpState.RESTART
337 def on_state_WOP2(self):
339 self.arg_write = (self.arg_write << 8) | self.pend_data
341 self.arg_write |= self.pend_data << 8
342 self.mnemonic = '{wo:04X}'
343 self.ann_dasm = Ann.WOP
344 return OpState.RESTART