comparison z80_to_x86.c @ 213:4d4559b04c59

Make reset trigger debug exit to make it easier to test the same cases in blastem and musashi. Fix asl #1 overflow flag.
author Mike Pavone <pavone@retrodev.com>
date Tue, 16 Apr 2013 22:29:00 -0700
parents
children d9bf8e61c33c
comparison
equal deleted inserted replaced
212:e657a99b5abf 213:4d4559b04c59
1 #include "z80_to_x86.h"
2 #include "gen_x86.h"
3
4 #define MODE_UNUSED (MODE_IMMED-1)
5
6 #define ZCYCLES RBP
7 #define SCRATCH1 R13
8 #define SCRATCH2 R14
9
10 void z80_read_byte();
11 void z80_read_word();
12
13 uint8_t z80_size(z80_inst * inst)
14 {
15 uint8_t reg = (inst->reg & 0x1F);
16 if (reg != Z80_UNUSED &&) {
17 return reg < Z80_BC ? SZ_B : SZ_W;
18 }
19 //TODO: Handle any necessary special cases
20 return SZ_B;
21 }
22
23 uint8_t * zcylces(dst, uint32_t num_cycles)
24 {
25 return add_ir(dst, num_cycles, ZCYCLES, SZ_D);
26 }
27
28 uint8_t * translate_z80_reg(z80_inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_options * opts)
29 {
30 if (inst->reg == Z80_USE_IMMED) {
31 ea->mode = MODE_IMMED;
32 ea->disp = inst->immed;
33 } else if ((inst->reg & 0x1F) == Z80_UNUSED) {
34 ea->mode = MODE_UNUSED;
35 } else {
36 ea->mode = MODE_REG;
37 if (inst->reg == Z80_IYH) {
38 ea->base = opts->regs[Z80_IYL];
39 dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
40 } else {
41 ea->base = opts->regs[inst->reg]
42 }
43 }
44 return dst;
45 }
46
47 uint8_t * save_z80_reg(uint8_t * dst, z80_inst * inst, x86_z80_options * opts)
48 {
49 if (inst->reg == Z80_IYH) {
50 dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
51 }
52 return dst;
53 }
54
55 uint8_t * translate_z80_ea(z80_inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_options * opts, uint8_t read, uint8_t modify)
56 {
57 uint8_t size, reg, areg;
58 ea->mode = MODE_REG;
59 areg = read ? SCRATCH1 : SCRATCH2;
60 switch(inst->addr_mode & 0x1F)
61 {
62 case Z80_REG:
63 if (inst->ea_reg == Z80_IYH) {
64 ea->base = opts->regs[Z80_IYL];
65 dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
66 } else {
67 ea->base = opts->regs[inst->ea_reg];
68 }
69 break;
70 case Z80_REG_INDIRECT:
71 dst = mov_rr(dst, opts->regs[inst->ea_reg], areg, SZ_W);
72 size = z80_size(inst);
73 if (read) {
74 if (modify) {
75 dst = push_r(dst, SCRATCH1);
76 }
77 if (size == SZ_B) {
78 dst = call(dst, (uint8_t *)z80_read_byte);
79 } else {
80 dst = call(dst, (uint8_t *)z80_read_word);
81 }
82 if (modify) {
83 dst = pop_r(dst, SCRATCH2);
84 }
85 }
86 ea->base = SCRATCH1;
87 break;
88 case Z80_IMMED:
89 ea->mode = MODE_IMMED;
90 ea->disp = inst->immed;
91 break;
92 case Z80_IMMED_INDIRECT:
93 dst = mov_ir(dst, inst->immed, areg, SZ_W);
94 size = z80_size(inst);
95 if (read) {
96 if (modify) {
97 dst = push_r(dst, SCRATCH1);
98 }
99 if (size == SZ_B) {
100 dst = call(dst, (uint8_t *)z80_read_byte);
101 } else {
102 dst = call(dst, (uint8_t *)z80_read_word);
103 }
104 if (modify) {
105 dst = pop_r(dst, SCRATCH2);
106 }
107 }
108 ea->base = SCRATCH1;
109 break;
110 case Z80_IX_INDEXED:
111 case Z80_IY_INDEXED:
112 reg = opts->regs[inst->addr_mode == Z80_IX_INDEXED ? Z80_IX : Z80_IY];
113 dst = mov_rr(dst, reg, areg, SZ_W);
114 dst = add_ir(dst, inst->immed, areg, SZ_W);
115 size = z80_size(inst);
116 if (read) {
117 if (modify) {
118 dst = push_r(dst, SCRATCH1);
119 }
120 if (size == SZ_B) {
121 dst = call(dst, (uint8_t *)z80_read_byte);
122 } else {
123 dst = call(dst, (uint8_t *)z80_read_word);
124 }
125 if (modify) {
126 dst = pop_r(dst, SCRATCH2);
127 }
128 }
129 break;
130 case Z80_UNUSED:
131 ea->mode = MODE_UNUSED:
132 break;
133 default:
134 fprintf(stderr, "Unrecognized Z80 addressing mode %d\n", inst->addr_mode);
135 exit(1);
136 }
137 return dst;
138 }
139
140 uint8_t * z80_save_ea(uint8_t * dst, z80_inst * inst, x86_z80_options * opts)
141 {
142 if (inst->addr_mode == Z80_REG_DIRECT && inst->ea_reg == Z80_IYH) {
143 dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
144 }
145 return dst;
146 }
147
148 uint8_t * z80_save_result(uint8_t * dst, z80_inst * inst)
149 {
150 if (z80_size(inst). == SZ_B) {
151 dst = call(dst, (uint8_t *)z80_write_byte);
152 } else {
153 dst = call(dst, (uint8_t *)z80_write_word);
154 }
155 return dst;
156 }
157
158 enum {
159 DONT_READ=0,
160 READ
161 };
162
163 enum {
164 DONT_MODIFY=0,
165 MODIFY
166 };
167
168 uint8_t zf_off(uint8_t flag)
169 {
170 return offsetof(z80_context, flags) + flag;
171 }
172
173 uint8_t * translate_z80_inst(z80_inst * inst, uint8_t * dst, x86_z80_options * opts)
174 {
175 uint32_t cycles;
176 x86_ea src_op, dst_op;
177 switch(inst->op)
178 {
179 case Z80_LD:
180 if (inst->addr_mode & Z80_DIR) {
181 dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
182 dst = translate_z80_reg(inst, &dst_op, dst, opts);
183 } else {
184 dst = translate_z80_reg(inst, &src_op, dst, opts);
185 dst = translate_z80_ea(inst, &dst_op, dst, opts, DONT_READ, MODIFY);
186 }
187 if (ea_op.mode == MODE_REG_DIRECT) {
188 dst = mov_rr(dst, ea_op.base, reg_op.base, z80_size(inst));
189 } else {
190 dst = mov_ir(dst, ea_op.disp, reg_op.base, z80_size(inst));
191 }
192 dst = z80_save_reg(dst, inst, opts);
193 dst = z80_save_ea(dst, inst, opts);
194 if (!(inst->addr_mode & Z80_DIR)) {
195 dst = z80_save_result(dst, inst, opts);
196 }
197 break;
198 case Z80_PUSH:
199 dst = zcycles(dst, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5);
200 dst = sub_ir(dst, opts->regs[Z80_SP], SZ_W);
201 dst = translate_z80_reg(inst, &src_op, dst, opts);
202 dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_W);
203 dst = call(dst, z80_write_word);
204 break;
205 case Z80_POP:
206 dst = zcycles(dst, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4);
207 dst = sub_ir(dst, opts->regs[Z80_SP], SZ_W);
208 dst = translate_z80_reg(inst, &src_op, dst, opts);
209 dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_W);
210 dst = call(dst, z80_write_word);
211 break;
212 /*case Z80_EX:
213 case Z80_EXX:
214 case Z80_LDI:
215 case Z80_LDIR:
216 case Z80_LDD:
217 case Z80_LDDR:
218 case Z80_CPI:
219 case Z80_CPIR:
220 case Z80_CPD:
221 case Z80_CPDR:
222 break;*/
223 case Z80_ADD:
224 cycles = 4;
225 if (inst->addr_mode == Z80_IX_INDIRECT || inst->addr_mdoe == Z80_IY_INDIRECT) {
226 cycles += 12;
227 } else if(inst->addr_mode == Z80_IMMED) {
228 cycles += 3;
229 } else if(z80_size(inst) == SZ_W) {
230 cycles += 4;
231 }
232 dst = zcycles(dst, cycles);
233 dst = translate_z80_reg(inst, &dst_op, dst, opts);
234 dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
235 if (src_op.mode == MODE_REG_DIRECT) {
236 dst = add_rr(dst, src_op.base, dst_op.base, z80_size(inst));
237 } else {
238 dst = add_ir(dst, src_op.disp, dst_op.base, z80_size(inst));
239 }
240 dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
241 dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N));
242 //TODO: Implement half-carry flag
243 if (z80_size(inst) == SZ_B) {
244 dst = setcc_rdisp8(dst, CC_O, zf_off(ZF_PV));
245 dst = setcc_rdisp8(dst, CC_Z, zf_off(ZF_Z));
246 dst = setcc_rdisp8(dst, CC_S, zf_off(ZF_S));
247 }
248 dst = z80_save_reg(dst, inst, opts);
249 dst = z80_save_ea(dst, inst, opts);
250 break;
251 /*case Z80_ADC:
252 break;*/
253 case Z80_SUB:
254 cycles = 4;
255 if (inst->addr_mode == Z80_IX_INDIRECT || inst->addr_mdoe == Z80_IY_INDIRECT) {
256 cycles += 12;
257 } else if(inst->addr_mode == Z80_IMMED) {
258 cycles += 3;
259 }
260 dst = zcycles(dst, cycles);
261 dst = translate_z80_reg(inst, &dst_op, dst, opts);
262 dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
263 if (src_op.mode == MODE_REG_DIRECT) {
264 dst = sub_rr(dst, src_op.base, dst_op.base, z80_size(inst));
265 } else {
266 dst = sub_ir(dst, src_op.disp, dst_op.base, z80_size(inst));
267 }
268 dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
269 dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N));
270 dst = setcc_rdisp8(dst, CC_O, zf_off(ZF_PV));
271 //TODO: Implement half-carry flag
272 dst = setcc_rdisp8(dst, CC_Z, zf_off(ZF_Z));
273 dst = setcc_rdisp8(dst, CC_S, zf_off(ZF_S)
274 dst = z80_save_reg(dst, inst, opts);
275 dst = z80_save_ea(dst, inst, opts);
276 break;
277 /*case Z80_SBC:
278 case Z80_AND:
279 case Z80_OR:
280 case Z80_XOR:
281 case Z80_CP:*/
282 case Z80_INC:
283 cycles = 4;
284 if (inst->reg == Z80_IX || inst->reg == Z80_IY) {
285 cycles += 6;
286 } else if(z80_size(inst) == SZ_W) {
287 cycles += 2;
288 } else if(inst->reg == Z80_IXH || inst->reg == Z80_IXL || inst->reg == Z80_IYH || inst->reg == Z80_IYL || inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
289 cycles += 4;
290 }
291 dst = translate_z80_reg(inst, &dst_op, dst, opts);
292 if (dst_op.mode == MODE_UNUSED) {
293 dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY);
294 }
295 dst = add_ir(dst, 1, dst_op.base, z80_size(inst));
296 if (z80_size(inst) == SZ_B) {
297 dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N));
298 //TODO: Implement half-carry flag
299 dst = setcc_rdisp8(dst, CC_O, zf_off(ZF_PV));
300 dst = setcc_rdisp8(dst, CC_Z, zf_off(ZF_Z));
301 dst = setcc_rdisp8(dst, CC_S, zf_off(ZF_S));
302 }
303 dst = z80_save_reg(dst, inst, opts);
304 dst = z80_save_ea(dst, inst, opts);
305 break;
306 /*case Z80_DEC:
307 break;
308 case Z80_DAA:
309 case Z80_CPL:
310 case Z80_NEG:
311 case Z80_CCF:
312 case Z80_SCF:*/
313 case Z80_NOP:
314 if (inst->immed == 42) {
315 dst = call(dst, (uint8_t *)z80_save_context);
316 dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
317 dst = jmp(dst, (uint8_t *)z80_print_regs_exit);
318 } else {
319 dst = zcycles(dst, 4 * inst->immed);
320 }
321 break;
322 /*case Z80_HALT:
323 case Z80_DI:
324 case Z80_EI:
325 case Z80_IM:
326 case Z80_RLC:
327 case Z80_RL:
328 case Z80_RRC:
329 case Z80_RR:
330 case Z80_SLA:
331 case Z80_SRA:
332 case Z80_SLL:
333 case Z80_SRL:
334 case Z80_RLD:
335 case Z80_RRD:
336 case Z80_BIT:
337 case Z80_SET:
338 case Z80_RES:
339 case Z80_JP:
340 case Z80_JPCC:
341 case Z80_JR:
342 case Z80_JRCC:
343 case Z80_DJNZ:
344 case Z80_CALL:
345 case Z80_CALLCC:
346 case Z80_RET:
347 case Z80_RETCC:
348 case Z80_RETI:
349 case Z80_RETN:
350 case Z80_RST:
351 case Z80_IN:
352 case Z80_INI:
353 case Z80_INIR:
354 case Z80_IND:
355 case Z80_INDR:
356 case Z80_OUT:
357 case Z80_OUTI:
358 case Z80_OTIR:
359 case Z80_OUTD:
360 case Z80_OTDR:*/
361 default:
362 fprintf(stderr, "unimplemented instruction: %d\n", inst->op);
363 exit(1);
364 }
365 }
366
367 void translate_z80_stream(z80_context * context, uint16_t address)
368 {
369 }