Mercurial > repos > blastem
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 } |