Implement 386 instruction table, improve 8086/186/286 instruction table
[multi_emu.git] / decode_z80.py
1 #!/usr/bin/env python3
2
3 import sys
4
5 # end-relative range of operands that are rvalues
6 rvalue_opcodes = {
7   'ld': -1,
8   'add': -1,
9   'adc': -1,
10   'sub': -1,
11   'sbc': -1,
12   'or': -1,
13   'and': -1,
14   'xor': -1,
15   'cp': -1,
16   'jr': -1,
17   'jp': -1,
18   'call': -1,
19   'djnz': -1,
20   'in': -1,
21   'in_z80': -1,
22   'out': -1,
23   'push': -1,
24   'bit': -1,
25 }
26
27 # if it is in byte_opcodes it is treated as byte and has no suffix
28 byte_opcodes = {
29   'sub',
30   'or',
31   'and',
32   'xor',
33   'cp',
34   'in',
35   'in_z80',
36   'out',
37   'bit',
38   'res',
39   'set',
40   'rl',
41   'rlc',
42   'rr',
43   'rrc',
44   'sla',
45   'sll',
46   'sra',
47   'srl',
48 }
49 # if any operand is in byte_operands it is treated as byte and has suffix
50 # in this case it is mandatory that no operand also be in word_operands
51 byte_operands = {
52   '0x12',
53   '0x34',
54   'a',
55   'b',
56   'c',
57   'd',
58   'e',
59   'l',
60   'h',
61   'ixl',
62   'ixh',
63   'iyl',
64   'iyh',
65   '(hl)',
66   '(ix+0x12)',
67   '(iy+0x12)',
68 }
69 byte_rvalue_modes = {
70   '0x12': 'cpu_z80_fetch_byte(self)',
71   '0x34': 'cpu_z80_fetch_byte(self)',
72   'a': 'self->regs.byte.a',
73   'b': 'self->regs.byte.b',
74   'c': 'self->regs.byte.c',
75   'd': 'self->regs.byte.d',
76   'e': 'self->regs.byte.e',
77   'l': 'self->regs.byte.l',
78   'h': 'self->regs.byte.h',
79   'ixl': 'self->regs.byte.ixl',
80   'ixh': 'self->regs.byte.ixh',
81   'iyl': 'self->regs.byte.iyl',
82   'iyh': 'self->regs.byte.iyh',
83   'i': 'self->regs.byte.i',
84   'r': 'self->regs.byte.r',
85   '(0x0012)': 'cpu_z80_in_byte(self, cpu_z80_port_word(self))',
86   '(c)': 'cpu_z80_in_byte(self, self->regs.word.bc)',
87 }
88 byte_lvalue_modes = {
89   'f': 'CPU_Z80_EA_F',
90   'a': 'CPU_Z80_EA_A',
91   'b': 'CPU_Z80_EA_B',
92   'c': 'CPU_Z80_EA_C',
93   'd': 'CPU_Z80_EA_D',
94   'e': 'CPU_Z80_EA_E',
95   'l': 'CPU_Z80_EA_L',
96   'h': 'CPU_Z80_EA_H',
97   'ixl': 'CPU_Z80_EA_IXL',
98   'ixh': 'CPU_Z80_EA_IXH',
99   'iyl': 'CPU_Z80_EA_IYL',
100   'iyh': 'CPU_Z80_EA_IYH',
101   'i': 'CPU_Z80_EA_I',
102   'r': 'CPU_Z80_EA_R',
103   'sink': 'CPU_Z80_EA_SINK',
104   '(0x3412)': 'cpu_z80_fetch_word(self)',
105   '(bc)': 'self->regs.word.bc',
106   '(de)': 'self->regs.word.de',
107   '(hl)': 'self->regs.word.hl',
108   '(ix+0x12)': 'cpu_z80_displacement(self, self->regs.word.ix)',
109   '(iy+0x12)': 'cpu_z80_displacement(self, self->regs.word.iy)',
110   '(0x0012)': 'cpu_z80_fetch_byte(self)',
111   '(c)': 'self->regs.word.bc',
112 }
113
114 # if it is in word_opcodes it is treated as word and has no suffix
115 # in this case the operands "c" and "(hl)" do not imply a byte opcode
116 word_opcodes = {
117   'jr',
118   'jp',
119   'call',
120   'ret',
121   'djnz',
122   'push',
123   'pop',
124   'ex',
125 }
126 # if any operand is in word_operands it is treated as word and has suffix
127 # in this case it is mandatory that no operand also be in byte_operands
128 word_operands = {
129   '0x3412',
130   'af',
131   'bc',
132   'de',
133   'hl',
134   'sp',
135   'ix',
136   'iy',
137 }
138 word_rvalue_modes = {
139   '0x0014': 'cpu_z80_relative(self)',
140   '0x0015': 'cpu_z80_relative(self)',
141   '0x3412': 'cpu_z80_fetch_word(self)',
142   'af': 'self->regs.word.af',
143   'bc': 'self->regs.word.bc',
144   'de': 'self->regs.word.de',
145   'hl': 'self->regs.word.hl',
146   'ix': 'self->regs.word.ix',
147   'iy': 'self->regs.word.iy',
148   'sp': 'self->regs.word.sp',
149 }
150 word_lvalue_modes = {
151   'z': 'self->regs.bit.zf',
152   'nz': '!self->regs.bit.zf',
153   'c': 'self->regs.bit.cf',
154   'nc': '!self->regs.bit.cf',
155   'm': 'self->regs.bit.sf',
156   'p': '!self->regs.bit.sf',
157   'pe': 'self->regs.bit.pvf',
158   'po': '!self->regs.bit.pvf',
159   'af': 'CPU_Z80_EA_AF',
160   'af\'': 'CPU_Z80_EA_AF_PRIME',
161   'bc': 'CPU_Z80_EA_BC',
162   'de': 'CPU_Z80_EA_DE',
163   'hl': 'CPU_Z80_EA_HL',
164   'ix': 'CPU_Z80_EA_IX',
165   'iy': 'CPU_Z80_EA_IY',
166   'sp': 'CPU_Z80_EA_SP',
167   '(0x3412)': 'cpu_z80_fetch_word(self)',
168   '(bc)': 'self->regs.word.bc',
169   '(de)': 'self->regs.word.de',
170   '(hl)': 'self->regs.word.hl',
171   '(ix)': 'self->regs.word.ix',
172   '(iy)': 'self->regs.word.iy',
173   '(sp)': 'self->regs.word.sp',
174 }
175
176 prefixes = [[], [0xcb], [0xdd], [0xdd, 0xcb], [0xed], [0xfd], [0xfd, 0xcb]]
177 for i in prefixes:
178   line = sys.stdin.readline().strip()
179   assert line == 'opcodes{0:s}'.format(''.join([f' 0x{j:02x}' for j in i]))
180
181   print(
182     'void cpu_z80_execute{0:s}(struct cpu_z80 *self) {{'.format(
183       ''.join([f'_{j:02x}' for j in i])
184     )
185   )
186   print('  switch (cpu_z80_fetch_byte(self)) {')
187
188   for j in range(0x100):
189     line = sys.stdin.readline().strip()
190
191     print(f'  case 0x{j:02x}:')
192     k = i + [j]
193     if k in prefixes:
194       print(
195         '    cpu_z80_execute{0:s}(self);'.format(
196           ''.join([f'_{k:02x}' for k in k])
197         )
198       )
199     else:
200       instr = line.split()
201       if len(instr) == 0:
202         instr = ['ill']
203       elif len(instr) >= 2:
204         instr[1:] = [l for k in instr[1:] for l in k.split(',')]
205       #print('xxx', instr)
206
207       # detect operation size (byte or word)
208       suffix = ''
209       if instr[0] not in byte_opcodes and instr[0] not in word_opcodes:
210         for k in instr[1:]:
211           if k in byte_operands:
212             assert suffix != '_word'
213             suffix = '_byte'
214           elif k in word_operands:
215             assert suffix != '_byte'
216             suffix = '_word'
217
218       # work out which operands are rvalue
219       k = len(instr) + rvalue_opcodes.get(instr[0], 0)
220
221       # translate operands
222       if suffix == '_byte' or instr[0] in byte_opcodes:
223         # operands [1, k) are lvalue
224         for l in range(1, k):
225           if instr[l] in byte_lvalue_modes:
226             instr[l] = byte_lvalue_modes[instr[l]]
227
228         # operands [k, n) are rvalue
229         for l in range(k, len(instr)):
230           if instr[l] in byte_rvalue_modes:
231             instr[l] = byte_rvalue_modes[instr[l]]
232           elif instr[l] in byte_lvalue_modes:
233             instr[l] = 'cpu_z80_read_byte(self, {0:s})'.format(
234               byte_lvalue_modes[instr[l]]
235             )
236       elif suffix == '_word' or instr[0] in word_opcodes:
237         # operands [1, k] are lvalue
238         for l in range(1, k):
239           if instr[l] in word_lvalue_modes:
240             instr[l] = word_lvalue_modes[instr[l]]
241
242         # operands [k, n) are rvalue
243         for l in range(k, len(instr)):
244           if instr[l] in word_rvalue_modes:
245             instr[l] = word_rvalue_modes[instr[l]]
246           elif instr[l] in word_lvalue_modes:
247             instr[l] = 'cpu_z80_read_word(self, {0:s})'.format(
248               word_lvalue_modes[instr[l]]
249             )
250
251       print(
252         '    cpu_z80_{0:s}{1:s}(self{2:s});'.format(
253           instr[0],
254           suffix,
255           ''.join([', ' + k for k in instr[1:]])
256         )
257       )
258     print('    break;')
259
260   line = sys.stdin.readline().strip()
261   assert len(line) == 0
262
263   print('  }')
264   print('}')
265   print()