Mercurial > repos > blastem
comparison m68k_core_x86.c @ 571:c90fc522e7e3
Refactor translat_m68k_src and translate_m68k_dst into a single function
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 02 Mar 2014 17:53:32 -0800 |
parents | 76bba9ffe351 |
children | 1594525e2157 |
comparison
equal
deleted
inserted
replaced
570:76bba9ffe351 | 571:c90fc522e7e3 |
---|---|
179 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->gen.scratch1, SZ_B); | 179 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->gen.scratch1, SZ_B); |
180 cmp_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B); | 180 cmp_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B); |
181 } | 181 } |
182 } | 182 } |
183 | 183 |
184 void translate_m68k_src(m68kinst * inst, x86_ea * ea, m68k_options * opts) | 184 void translate_m68k_op(m68kinst * inst, x86_ea * ea, m68k_options * opts, uint8_t dst) |
185 { | 185 { |
186 code_info *code = &opts->gen.code; | 186 code_info *code = &opts->gen.code; |
187 int8_t reg = native_reg(&(inst->src), opts); | 187 m68k_op_info *op = dst ? &inst->dst : &inst->src; |
188 int8_t reg = native_reg(op, opts); | |
188 uint8_t sec_reg; | 189 uint8_t sec_reg; |
189 int32_t dec_amount,inc_amount; | 190 int32_t dec_amount,inc_amount; |
190 if (reg >= 0) { | 191 if (reg >= 0) { |
191 ea->mode = MODE_REG_DIRECT; | 192 ea->mode = MODE_REG_DIRECT; |
192 if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { | 193 if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { |
193 movsx_rr(code, reg, opts->gen.scratch1, SZ_W, SZ_D); | 194 movsx_rr(code, reg, opts->gen.scratch1, SZ_W, SZ_D); |
194 ea->base = opts->gen.scratch1; | 195 ea->base = opts->gen.scratch1; |
195 } else { | 196 } else { |
196 ea->base = reg; | 197 ea->base = reg; |
197 } | 198 } |
198 return; | 199 return; |
199 } | 200 } |
200 switch (inst->src.addr_mode) | 201 switch (op->addr_mode) |
201 { | 202 { |
202 case MODE_REG: | 203 case MODE_REG: |
203 case MODE_AREG: | 204 case MODE_AREG: |
204 //We only get one memory parameter, so if the dst operand is a register in memory, | 205 //We only get one memory parameter, so if the dst operand is a register in memory, |
205 //we need to copy this to a temp register first | 206 //we need to copy this to a temp register first if we're translating the src operand |
206 reg = native_reg(&(inst->dst), opts); | 207 if (dst || native_reg(&(inst->dst), opts) >= 0 || inst->dst.addr_mode == MODE_UNUSED || !(inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) |
207 if (reg >= 0 || inst->dst.addr_mode == MODE_UNUSED || !(inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) | |
208 || inst->op == M68K_EXG) { | 208 || inst->op == M68K_EXG) { |
209 | 209 |
210 ea->mode = MODE_REG_DISPLACE8; | 210 ea->mode = MODE_REG_DISPLACE8; |
211 ea->base = opts->gen.context_reg; | 211 ea->base = opts->gen.context_reg; |
212 ea->disp = reg_offset(&(inst->src)); | 212 ea->disp = reg_offset(op); |
213 } else { | 213 } else { |
214 if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { | 214 if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { |
215 movsx_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_W, SZ_D); | 215 movsx_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, SZ_W, SZ_D); |
216 } else { | 216 } else { |
217 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, inst->extra.size); | 217 mov_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, inst->extra.size); |
218 } | 218 } |
219 ea->mode = MODE_REG_DIRECT; | 219 ea->mode = MODE_REG_DIRECT; |
220 ea->base = opts->gen.scratch1; | 220 ea->base = opts->gen.scratch1; |
221 //we're explicitly handling the areg dest here, so we exit immediately | 221 //we're explicitly handling the areg dest here, so we exit immediately |
222 return; | 222 return; |
223 } | 223 } |
224 break; | 224 break; |
225 case MODE_AREG_PREDEC: | 225 case MODE_AREG_PREDEC: |
226 dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->src.params.regs.pri == 7 ? 2 :1)); | 226 if (dst && inst->src.addr_mode == MODE_AREG_PREDEC) { |
227 cycles(&opts->gen, PREDEC_PENALTY); | 227 push_r(code, opts->gen.scratch1); |
228 if (opts->aregs[inst->src.params.regs.pri] >= 0) { | 228 } |
229 sub_ir(code, dec_amount, opts->aregs[inst->src.params.regs.pri], SZ_D); | 229 dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 :1)); |
230 } else { | 230 if (!dst) { |
231 sub_irdisp(code, dec_amount, opts->gen.context_reg, reg_offset(&(inst->src)), SZ_D); | 231 cycles(&opts->gen, PREDEC_PENALTY); |
232 } | |
233 if (opts->aregs[op->params.regs.pri] >= 0) { | |
234 sub_ir(code, dec_amount, opts->aregs[op->params.regs.pri], SZ_D); | |
235 } else { | |
236 sub_irdisp(code, dec_amount, opts->gen.context_reg, reg_offset(op), SZ_D); | |
232 } | 237 } |
233 case MODE_AREG_INDIRECT: | 238 case MODE_AREG_INDIRECT: |
234 case MODE_AREG_POSTINC: | 239 case MODE_AREG_POSTINC: |
235 if (opts->aregs[inst->src.params.regs.pri] >= 0) { | 240 if (opts->aregs[op->params.regs.pri] >= 0) { |
236 mov_rr(code, opts->aregs[inst->src.params.regs.pri], opts->gen.scratch1, SZ_D); | 241 mov_rr(code, opts->aregs[op->params.regs.pri], opts->gen.scratch1, SZ_D); |
237 } else { | 242 } else { |
238 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_D); | 243 mov_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, SZ_D); |
239 } | 244 } |
240 m68k_read_size(opts, inst->extra.size); | 245 m68k_read_size(opts, inst->extra.size); |
241 | 246 |
242 if (inst->src.addr_mode == MODE_AREG_POSTINC) { | 247 if (dst) { |
243 inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->src.params.regs.pri == 7 ? 2 : 1)); | 248 if (inst->src.addr_mode == MODE_AREG_PREDEC) { |
244 if (opts->aregs[inst->src.params.regs.pri] >= 0) { | 249 //restore src operand to opts->gen.scratch2 |
245 add_ir(code, inc_amount, opts->aregs[inst->src.params.regs.pri], SZ_D); | 250 pop_r(code, opts->gen.scratch2); |
246 } else { | 251 } else { |
247 add_irdisp(code, inc_amount, opts->gen.context_reg, reg_offset(&(inst->src)), SZ_D); | 252 //save reg value in opts->gen.scratch2 so we can use it to save the result in memory later |
253 if (opts->aregs[op->params.regs.pri] >= 0) { | |
254 mov_rr(code, opts->aregs[op->params.regs.pri], opts->gen.scratch2, SZ_D); | |
255 } else { | |
256 mov_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch2, SZ_D); | |
257 } | |
258 } | |
259 } | |
260 | |
261 if (op->addr_mode == MODE_AREG_POSTINC) { | |
262 inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 : 1)); | |
263 if (opts->aregs[op->params.regs.pri] >= 0) { | |
264 add_ir(code, inc_amount, opts->aregs[op->params.regs.pri], SZ_D); | |
265 } else { | |
266 add_irdisp(code, inc_amount, opts->gen.context_reg, reg_offset(op), SZ_D); | |
248 } | 267 } |
249 } | 268 } |
250 ea->mode = MODE_REG_DIRECT; | 269 ea->mode = MODE_REG_DIRECT; |
251 ea->base = (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) ? opts->gen.scratch2 : opts->gen.scratch1; | 270 ea->base = (!dst && inst->dst.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) ? opts->gen.scratch2 : opts->gen.scratch1; |
252 break; | 271 break; |
253 case MODE_AREG_DISPLACE: | 272 case MODE_AREG_DISPLACE: |
254 cycles(&opts->gen, BUS); | 273 cycles(&opts->gen, BUS); |
255 if (opts->aregs[inst->src.params.regs.pri] >= 0) { | 274 if (opts->aregs[op->params.regs.pri] >= 0) { |
256 mov_rr(code, opts->aregs[inst->src.params.regs.pri], opts->gen.scratch1, SZ_D); | 275 mov_rr(code, opts->aregs[op->params.regs.pri], opts->gen.scratch1, SZ_D); |
257 } else { | 276 } else { |
258 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_D); | 277 mov_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, SZ_D); |
259 } | 278 } |
260 add_ir(code, inst->src.params.regs.displacement, opts->gen.scratch1, SZ_D); | 279 add_ir(code, op->params.regs.displacement, opts->gen.scratch1, SZ_D); |
280 if (dst) { | |
281 push_r(code, opts->gen.scratch1); | |
282 } | |
261 m68k_read_size(opts, inst->extra.size); | 283 m68k_read_size(opts, inst->extra.size); |
284 if (dst) { | |
285 pop_r(code, opts->gen.scratch2); | |
286 } | |
262 | 287 |
263 ea->mode = MODE_REG_DIRECT; | 288 ea->mode = MODE_REG_DIRECT; |
264 ea->base = opts->gen.scratch1; | 289 ea->base = opts->gen.scratch1; |
265 break; | 290 break; |
266 case MODE_AREG_INDEX_DISP8: | 291 case MODE_AREG_INDEX_DISP8: |
267 cycles(&opts->gen, 6); | 292 cycles(&opts->gen, 6); |
268 if (opts->aregs[inst->src.params.regs.pri] >= 0) { | 293 if (opts->aregs[op->params.regs.pri] >= 0) { |
269 mov_rr(code, opts->aregs[inst->src.params.regs.pri], opts->gen.scratch1, SZ_D); | 294 mov_rr(code, opts->aregs[op->params.regs.pri], opts->gen.scratch1, SZ_D); |
270 } else { | 295 } else { |
271 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_D); | 296 mov_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, SZ_D); |
272 } | 297 } |
273 sec_reg = (inst->src.params.regs.sec >> 1) & 0x7; | 298 sec_reg = (op->params.regs.sec >> 1) & 0x7; |
274 if (inst->src.params.regs.sec & 1) { | 299 if (op->params.regs.sec & 1) { |
275 if (inst->src.params.regs.sec & 0x10) { | 300 if (op->params.regs.sec & 0x10) { |
276 if (opts->aregs[sec_reg] >= 0) { | 301 if (opts->aregs[sec_reg] >= 0) { |
277 add_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_D); | 302 add_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_D); |
278 } else { | 303 } else { |
279 add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D); | 304 add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D); |
280 } | 305 } |
284 } else { | 309 } else { |
285 add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D); | 310 add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D); |
286 } | 311 } |
287 } | 312 } |
288 } else { | 313 } else { |
289 if (inst->src.params.regs.sec & 0x10) { | 314 if (op->params.regs.sec & 0x10) { |
290 if (opts->aregs[sec_reg] >= 0) { | 315 if (opts->aregs[sec_reg] >= 0) { |
291 movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D); | 316 movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D); |
292 } else { | 317 } else { |
293 movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D); | 318 movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D); |
294 } | 319 } |
299 movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D); | 324 movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D); |
300 } | 325 } |
301 } | 326 } |
302 add_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D); | 327 add_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D); |
303 } | 328 } |
304 if (inst->src.params.regs.displacement) { | 329 if (op->params.regs.displacement) { |
305 add_ir(code, inst->src.params.regs.displacement, opts->gen.scratch1, SZ_D); | 330 add_ir(code, op->params.regs.displacement, opts->gen.scratch1, SZ_D); |
331 } | |
332 if (dst) { | |
333 push_r(code, opts->gen.scratch1); | |
306 } | 334 } |
307 m68k_read_size(opts, inst->extra.size); | 335 m68k_read_size(opts, inst->extra.size); |
336 if (dst) { | |
337 pop_r(code, opts->gen.scratch2); | |
338 } | |
308 | 339 |
309 ea->mode = MODE_REG_DIRECT; | 340 ea->mode = MODE_REG_DIRECT; |
310 ea->base = opts->gen.scratch1; | 341 ea->base = opts->gen.scratch1; |
311 break; | 342 break; |
312 case MODE_PC_DISPLACE: | 343 case MODE_PC_DISPLACE: |
313 cycles(&opts->gen, BUS); | 344 cycles(&opts->gen, BUS); |
314 mov_ir(code, inst->src.params.regs.displacement + inst->address+2, opts->gen.scratch1, SZ_D); | 345 mov_ir(code, op->params.regs.displacement + inst->address+2, opts->gen.scratch1, SZ_D); |
346 if (dst) { | |
347 push_r(code, opts->gen.scratch1); | |
348 } | |
315 m68k_read_size(opts, inst->extra.size); | 349 m68k_read_size(opts, inst->extra.size); |
350 if (dst) { | |
351 pop_r(code, opts->gen.scratch2); | |
352 } | |
316 | 353 |
317 ea->mode = MODE_REG_DIRECT; | 354 ea->mode = MODE_REG_DIRECT; |
318 ea->base = opts->gen.scratch1; | 355 ea->base = opts->gen.scratch1; |
319 break; | 356 break; |
320 case MODE_PC_INDEX_DISP8: | 357 case MODE_PC_INDEX_DISP8: |
321 cycles(&opts->gen, 6); | 358 cycles(&opts->gen, 6); |
322 mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D); | 359 mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D); |
323 sec_reg = (inst->src.params.regs.sec >> 1) & 0x7; | 360 sec_reg = (op->params.regs.sec >> 1) & 0x7; |
324 if (inst->src.params.regs.sec & 1) { | 361 if (op->params.regs.sec & 1) { |
325 if (inst->src.params.regs.sec & 0x10) { | 362 if (op->params.regs.sec & 0x10) { |
326 if (opts->aregs[sec_reg] >= 0) { | 363 if (opts->aregs[sec_reg] >= 0) { |
327 add_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_D); | 364 add_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_D); |
328 } else { | 365 } else { |
329 add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D); | 366 add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D); |
330 } | 367 } |
334 } else { | 371 } else { |
335 add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D); | 372 add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D); |
336 } | 373 } |
337 } | 374 } |
338 } else { | 375 } else { |
339 if (inst->src.params.regs.sec & 0x10) { | 376 if (op->params.regs.sec & 0x10) { |
340 if (opts->aregs[sec_reg] >= 0) { | 377 if (opts->aregs[sec_reg] >= 0) { |
341 movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D); | 378 movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D); |
342 } else { | 379 } else { |
343 movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D); | 380 movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D); |
344 } | 381 } |
349 movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D); | 386 movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D); |
350 } | 387 } |
351 } | 388 } |
352 add_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D); | 389 add_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D); |
353 } | 390 } |
354 if (inst->src.params.regs.displacement) { | 391 if (op->params.regs.displacement) { |
355 add_ir(code, inst->src.params.regs.displacement, opts->gen.scratch1, SZ_D); | 392 add_ir(code, op->params.regs.displacement, opts->gen.scratch1, SZ_D); |
393 } | |
394 if (dst) { | |
395 push_r(code, opts->gen.scratch1); | |
356 } | 396 } |
357 m68k_read_size(opts, inst->extra.size); | 397 m68k_read_size(opts, inst->extra.size); |
398 if (dst) { | |
399 pop_r(code, opts->gen.scratch2); | |
400 } | |
358 | 401 |
359 ea->mode = MODE_REG_DIRECT; | 402 ea->mode = MODE_REG_DIRECT; |
360 ea->base = opts->gen.scratch1; | 403 ea->base = opts->gen.scratch1; |
361 break; | 404 break; |
362 case MODE_ABSOLUTE: | 405 case MODE_ABSOLUTE: |
363 case MODE_ABSOLUTE_SHORT: | 406 case MODE_ABSOLUTE_SHORT: |
364 cycles(&opts->gen, inst->src.addr_mode == MODE_ABSOLUTE ? BUS*2 : BUS); | 407 cycles(&opts->gen, op->addr_mode == MODE_ABSOLUTE ? BUS*2 : BUS); |
365 mov_ir(code, inst->src.params.immed, opts->gen.scratch1, SZ_D); | 408 mov_ir(code, op->params.immed, opts->gen.scratch1, SZ_D); |
409 if (dst) { | |
410 push_r(code, opts->gen.scratch1); | |
411 } | |
366 m68k_read_size(opts, inst->extra.size); | 412 m68k_read_size(opts, inst->extra.size); |
413 if (dst) { | |
414 pop_r(code, opts->gen.scratch2); | |
415 } | |
367 | 416 |
368 ea->mode = MODE_REG_DIRECT; | 417 ea->mode = MODE_REG_DIRECT; |
369 ea->base = opts->gen.scratch1; | 418 ea->base = opts->gen.scratch1; |
370 break; | 419 break; |
371 case MODE_IMMEDIATE: | 420 case MODE_IMMEDIATE: |
372 case MODE_IMMEDIATE_WORD: | 421 case MODE_IMMEDIATE_WORD: |
373 if (inst->variant != VAR_QUICK) { | 422 if (inst->variant != VAR_QUICK) { |
374 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG && inst->src.addr_mode == MODE_IMMEDIATE) ? BUS*2 : BUS); | 423 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG && op->addr_mode == MODE_IMMEDIATE) ? BUS*2 : BUS); |
375 } | 424 } |
376 ea->mode = MODE_IMMED; | 425 ea->mode = MODE_IMMED; |
377 ea->disp = inst->src.params.immed; | 426 ea->disp = op->params.immed; |
427 //sign extend value when the destination is an address register | |
378 if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD && ea->disp & 0x8000) { | 428 if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD && ea->disp & 0x8000) { |
379 ea->disp |= 0xFFFF0000; | 429 ea->disp |= 0xFFFF0000; |
380 } | 430 } |
381 return; | 431 return; |
382 default: | 432 default: |
383 m68k_disasm(inst, disasm_buf); | 433 m68k_disasm(inst, disasm_buf); |
384 printf("%X: %s\naddress mode %d not implemented (src)\n", inst->address, disasm_buf, inst->src.addr_mode); | 434 printf("%X: %s\naddress mode %d not implemented (%s)\n", inst->address, disasm_buf, op->addr_mode, dst ? "dst" : "src"); |
385 exit(1); | 435 exit(1); |
386 } | 436 } |
387 if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { | 437 if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { |
388 if (ea->mode == MODE_REG_DIRECT) { | 438 if (ea->mode == MODE_REG_DIRECT) { |
389 movsx_rr(code, ea->base, opts->gen.scratch1, SZ_W, SZ_D); | 439 movsx_rr(code, ea->base, opts->gen.scratch1, SZ_W, SZ_D); |
390 } else { | 440 } else { |
391 movsx_rdispr(code, ea->base, ea->disp, opts->gen.scratch1, SZ_W, SZ_D); | 441 movsx_rdispr(code, ea->base, ea->disp, opts->gen.scratch1, SZ_W, SZ_D); |
392 ea->mode = MODE_REG_DIRECT; | 442 ea->mode = MODE_REG_DIRECT; |
393 } | 443 } |
394 ea->base = opts->gen.scratch1; | 444 ea->base = opts->gen.scratch1; |
395 } | |
396 } | |
397 | |
398 void translate_m68k_dst(m68kinst * inst, x86_ea * ea, m68k_options * opts, uint8_t fake_read) | |
399 { | |
400 code_info *code = &opts->gen.code; | |
401 int8_t reg = native_reg(&(inst->dst), opts), sec_reg; | |
402 int32_t dec_amount, inc_amount; | |
403 if (reg >= 0) { | |
404 ea->mode = MODE_REG_DIRECT; | |
405 ea->base = reg; | |
406 return; | |
407 } | |
408 switch (inst->dst.addr_mode) | |
409 { | |
410 case MODE_REG: | |
411 case MODE_AREG: | |
412 ea->mode = MODE_REG_DISPLACE8; | |
413 ea->base = opts->gen.context_reg; | |
414 ea->disp = reg_offset(&(inst->dst)); | |
415 break; | |
416 case MODE_AREG_PREDEC: | |
417 if (inst->src.addr_mode == MODE_AREG_PREDEC) { | |
418 push_r(code, opts->gen.scratch1); | |
419 } | |
420 dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1)); | |
421 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { | |
422 sub_ir(code, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); | |
423 } else { | |
424 sub_irdisp(code, dec_amount, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_D); | |
425 } | |
426 case MODE_AREG_INDIRECT: | |
427 case MODE_AREG_POSTINC: | |
428 if (fake_read) { | |
429 cycles(&opts->gen, inst->extra.size == OPSIZE_LONG ? 8 : 4); | |
430 } else { | |
431 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { | |
432 mov_rr(code, opts->aregs[inst->dst.params.regs.pri], opts->gen.scratch1, SZ_D); | |
433 } else { | |
434 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->dst)), opts->gen.scratch1, SZ_D); | |
435 } | |
436 m68k_read_size(opts, inst->extra.size); | |
437 } | |
438 if (inst->src.addr_mode == MODE_AREG_PREDEC) { | |
439 //restore src operand to opts->gen.scratch2 | |
440 pop_r(code, opts->gen.scratch2); | |
441 } else { | |
442 //save reg value in opts->gen.scratch2 so we can use it to save the result in memory later | |
443 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { | |
444 mov_rr(code, opts->aregs[inst->dst.params.regs.pri], opts->gen.scratch2, SZ_D); | |
445 } else { | |
446 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->dst)), opts->gen.scratch2, SZ_D); | |
447 } | |
448 } | |
449 | |
450 if (inst->dst.addr_mode == MODE_AREG_POSTINC) { | |
451 inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1)); | |
452 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { | |
453 add_ir(code, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); | |
454 } else { | |
455 add_irdisp(code, inc_amount, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_D); | |
456 } | |
457 } | |
458 ea->mode = MODE_REG_DIRECT; | |
459 ea->base = opts->gen.scratch1; | |
460 break; | |
461 case MODE_AREG_DISPLACE: | |
462 cycles(&opts->gen, fake_read ? BUS+(inst->extra.size == OPSIZE_LONG ? BUS*2 : BUS) : BUS); | |
463 reg = fake_read ? opts->gen.scratch2 : opts->gen.scratch1; | |
464 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { | |
465 mov_rr(code, opts->aregs[inst->dst.params.regs.pri], reg, SZ_D); | |
466 } else { | |
467 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->dst)), reg, SZ_D); | |
468 } | |
469 add_ir(code, inst->dst.params.regs.displacement, reg, SZ_D); | |
470 if (!fake_read) { | |
471 push_r(code, opts->gen.scratch1); | |
472 m68k_read_size(opts, inst->extra.size); | |
473 pop_r(code, opts->gen.scratch2); | |
474 } | |
475 ea->mode = MODE_REG_DIRECT; | |
476 ea->base = opts->gen.scratch1; | |
477 break; | |
478 case MODE_AREG_INDEX_DISP8: | |
479 cycles(&opts->gen, fake_read ? (6 + inst->extra.size == OPSIZE_LONG ? 8 : 4) : 6); | |
480 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { | |
481 mov_rr(code, opts->aregs[inst->dst.params.regs.pri], opts->gen.scratch1, SZ_D); | |
482 } else { | |
483 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->dst)), opts->gen.scratch1, SZ_D); | |
484 } | |
485 sec_reg = (inst->dst.params.regs.sec >> 1) & 0x7; | |
486 if (inst->dst.params.regs.sec & 1) { | |
487 if (inst->dst.params.regs.sec & 0x10) { | |
488 if (opts->aregs[sec_reg] >= 0) { | |
489 add_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_D); | |
490 } else { | |
491 add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D); | |
492 } | |
493 } else { | |
494 if (opts->dregs[sec_reg] >= 0) { | |
495 add_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_D); | |
496 } else { | |
497 add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D); | |
498 } | |
499 } | |
500 } else { | |
501 if (inst->dst.params.regs.sec & 0x10) { | |
502 if (opts->aregs[sec_reg] >= 0) { | |
503 movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D); | |
504 } else { | |
505 movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D); | |
506 } | |
507 } else { | |
508 if (opts->dregs[sec_reg] >= 0) { | |
509 movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D); | |
510 } else { | |
511 movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D); | |
512 } | |
513 } | |
514 add_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D); | |
515 } | |
516 if (inst->dst.params.regs.displacement) { | |
517 add_ir(code, inst->dst.params.regs.displacement, opts->gen.scratch1, SZ_D); | |
518 } | |
519 if (fake_read) { | |
520 mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_D); | |
521 } else { | |
522 push_r(code, opts->gen.scratch1); | |
523 m68k_read_size(opts, inst->extra.size); | |
524 pop_r(code, opts->gen.scratch2); | |
525 } | |
526 ea->mode = MODE_REG_DIRECT; | |
527 ea->base = opts->gen.scratch1; | |
528 break; | |
529 case MODE_PC_DISPLACE: | |
530 cycles(&opts->gen, fake_read ? BUS+(inst->extra.size == OPSIZE_LONG ? BUS*2 : BUS) : BUS); | |
531 mov_ir(code, inst->dst.params.regs.displacement + inst->address+2, fake_read ? opts->gen.scratch2 : opts->gen.scratch1, SZ_D); | |
532 if (!fake_read) { | |
533 push_r(code, opts->gen.scratch1); | |
534 m68k_read_size(opts, inst->extra.size); | |
535 pop_r(code, opts->gen.scratch2); | |
536 } | |
537 ea->mode = MODE_REG_DIRECT; | |
538 ea->base = opts->gen.scratch1; | |
539 break; | |
540 case MODE_PC_INDEX_DISP8: | |
541 cycles(&opts->gen, fake_read ? (6 + inst->extra.size == OPSIZE_LONG ? 8 : 4) : 6); | |
542 mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D); | |
543 sec_reg = (inst->dst.params.regs.sec >> 1) & 0x7; | |
544 if (inst->dst.params.regs.sec & 1) { | |
545 if (inst->dst.params.regs.sec & 0x10) { | |
546 if (opts->aregs[sec_reg] >= 0) { | |
547 add_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_D); | |
548 } else { | |
549 add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D); | |
550 } | |
551 } else { | |
552 if (opts->dregs[sec_reg] >= 0) { | |
553 add_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_D); | |
554 } else { | |
555 add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D); | |
556 } | |
557 } | |
558 } else { | |
559 if (inst->dst.params.regs.sec & 0x10) { | |
560 if (opts->aregs[sec_reg] >= 0) { | |
561 movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D); | |
562 } else { | |
563 movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D); | |
564 } | |
565 } else { | |
566 if (opts->dregs[sec_reg] >= 0) { | |
567 movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D); | |
568 } else { | |
569 movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D); | |
570 } | |
571 } | |
572 add_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D); | |
573 } | |
574 if (inst->dst.params.regs.displacement) { | |
575 add_ir(code, inst->dst.params.regs.displacement, opts->gen.scratch1, SZ_D); | |
576 } | |
577 if (fake_read) { | |
578 mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_D); | |
579 } else { | |
580 push_r(code, opts->gen.scratch1); | |
581 m68k_read_size(opts, inst->extra.size); | |
582 pop_r(code, opts->gen.scratch2); | |
583 } | |
584 ea->mode = MODE_REG_DIRECT; | |
585 ea->base = opts->gen.scratch1; | |
586 break; | |
587 case MODE_ABSOLUTE: | |
588 case MODE_ABSOLUTE_SHORT: | |
589 //Add cycles for reading address from instruction stream | |
590 cycles(&opts->gen, (inst->dst.addr_mode == MODE_ABSOLUTE ? BUS*2 : BUS) + (fake_read ? (inst->extra.size == OPSIZE_LONG ? BUS*2 : BUS) : 0)); | |
591 mov_ir(code, inst->dst.params.immed, fake_read ? opts->gen.scratch2 : opts->gen.scratch1, SZ_D); | |
592 if (!fake_read) { | |
593 push_r(code, opts->gen.scratch1); | |
594 m68k_read_size(opts, inst->extra.size); | |
595 pop_r(code, opts->gen.scratch2); | |
596 } | |
597 ea->mode = MODE_REG_DIRECT; | |
598 ea->base = opts->gen.scratch1; | |
599 break; | |
600 default: | |
601 m68k_disasm(inst, disasm_buf); | |
602 printf("%X: %s\naddress mode %d not implemented (dst)\n", inst->address, disasm_buf, inst->dst.addr_mode); | |
603 exit(1); | |
604 } | 445 } |
605 } | 446 } |
606 | 447 |
607 void m68k_save_result(m68kinst * inst, m68k_options * opts) | 448 void m68k_save_result(m68kinst * inst, m68k_options * opts) |
608 { | 449 { |
636 int8_t reg, flags_reg, sec_reg; | 477 int8_t reg, flags_reg, sec_reg; |
637 uint8_t dir = 0; | 478 uint8_t dir = 0; |
638 int32_t offset; | 479 int32_t offset; |
639 int32_t inc_amount, dec_amount; | 480 int32_t inc_amount, dec_amount; |
640 x86_ea src; | 481 x86_ea src; |
641 translate_m68k_src(inst, &src, opts); | 482 translate_m68k_op(inst, &src, opts, 0); |
642 reg = native_reg(&(inst->dst), opts); | 483 reg = native_reg(&(inst->dst), opts); |
643 if (inst->dst.addr_mode != MODE_AREG) { | 484 if (inst->dst.addr_mode != MODE_AREG) { |
644 //update statically set flags | 485 //update statically set flags |
645 set_flag(opts, 0, FLAG_V); | 486 set_flag(opts, 0, FLAG_V); |
646 set_flag(opts, 0, FLAG_C); | 487 set_flag(opts, 0, FLAG_C); |
1266 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 6 : 4)); | 1107 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 6 : 4)); |
1267 xor_rr(code, reg, reg, inst->extra.size); | 1108 xor_rr(code, reg, reg, inst->extra.size); |
1268 return; | 1109 return; |
1269 } | 1110 } |
1270 x86_ea dst_op; | 1111 x86_ea dst_op; |
1271 translate_m68k_dst(inst, &dst_op, opts, 1); | 1112 translate_m68k_op(inst, &dst_op, opts, 1); |
1272 if (dst_op.mode == MODE_REG_DIRECT) { | 1113 if (dst_op.mode == MODE_REG_DIRECT) { |
1273 xor_rr(code, dst_op.base, dst_op.base, inst->extra.size); | 1114 xor_rr(code, dst_op.base, dst_op.base, inst->extra.size); |
1274 } else { | 1115 } else { |
1275 mov_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size); | 1116 mov_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size); |
1276 } | 1117 } |
1281 { | 1122 { |
1282 code_info *code = &opts->gen.code; | 1123 code_info *code = &opts->gen.code; |
1283 x86_ea dst_op; | 1124 x86_ea dst_op; |
1284 uint8_t dst_size = inst->extra.size; | 1125 uint8_t dst_size = inst->extra.size; |
1285 inst->extra.size--; | 1126 inst->extra.size--; |
1286 translate_m68k_dst(inst, &dst_op, opts, 0); | 1127 translate_m68k_op(inst, &dst_op, opts, 1); |
1287 if (dst_op.mode == MODE_REG_DIRECT) { | 1128 if (dst_op.mode == MODE_REG_DIRECT) { |
1288 movsx_rr(code, dst_op.base, dst_op.base, inst->extra.size, dst_size); | 1129 movsx_rr(code, dst_op.base, dst_op.base, inst->extra.size, dst_size); |
1289 cmp_ir(code, 0, dst_op.base, dst_size); | 1130 cmp_ir(code, 0, dst_op.base, dst_size); |
1290 } else { | 1131 } else { |
1291 movsx_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, inst->extra.size, dst_size); | 1132 movsx_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, inst->extra.size, dst_size); |
1640 { | 1481 { |
1641 code_info *code = &opts->gen.code; | 1482 code_info *code = &opts->gen.code; |
1642 uint8_t cond = inst->extra.cond; | 1483 uint8_t cond = inst->extra.cond; |
1643 x86_ea dst_op; | 1484 x86_ea dst_op; |
1644 inst->extra.size = OPSIZE_BYTE; | 1485 inst->extra.size = OPSIZE_BYTE; |
1645 translate_m68k_dst(inst, &dst_op, opts, 1); | 1486 translate_m68k_op(inst, &dst_op, opts, 1); |
1646 if (cond == COND_TRUE || cond == COND_FALSE) { | 1487 if (cond == COND_TRUE || cond == COND_FALSE) { |
1647 if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && inst->extra.cond == COND_TRUE) { | 1488 if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && inst->extra.cond == COND_TRUE) { |
1648 cycles(&opts->gen, 6); | 1489 cycles(&opts->gen, 6); |
1649 } else { | 1490 } else { |
1650 cycles(&opts->gen, BUS); | 1491 cycles(&opts->gen, BUS); |
2064 void translate_m68k_cmp(m68k_options * opts, m68kinst * inst) | 1905 void translate_m68k_cmp(m68k_options * opts, m68kinst * inst) |
2065 { | 1906 { |
2066 code_info *code = &opts->gen.code; | 1907 code_info *code = &opts->gen.code; |
2067 uint8_t size = inst->extra.size; | 1908 uint8_t size = inst->extra.size; |
2068 x86_ea src_op, dst_op; | 1909 x86_ea src_op, dst_op; |
2069 translate_m68k_src(inst, &src_op, opts); | 1910 translate_m68k_op(inst, &src_op, opts, 0); |
2070 if (inst->dst.addr_mode == MODE_AREG_POSTINC) { | 1911 if (inst->dst.addr_mode == MODE_AREG_POSTINC) { |
2071 push_r(code, opts->gen.scratch1); | 1912 push_r(code, opts->gen.scratch1); |
2072 translate_m68k_dst(inst, &dst_op, opts, 0); | 1913 translate_m68k_op(inst, &dst_op, opts, 1); |
2073 pop_r(code, opts->gen.scratch2); | 1914 pop_r(code, opts->gen.scratch2); |
2074 src_op.base = opts->gen.scratch2; | 1915 src_op.base = opts->gen.scratch2; |
2075 } else { | 1916 } else { |
2076 translate_m68k_dst(inst, &dst_op, opts, 0); | 1917 translate_m68k_op(inst, &dst_op, opts, 1); |
2077 if (inst->dst.addr_mode == MODE_AREG && size == OPSIZE_WORD) { | 1918 if (inst->dst.addr_mode == MODE_AREG && size == OPSIZE_WORD) { |
2078 size = OPSIZE_LONG; | 1919 size = OPSIZE_LONG; |
2079 } | 1920 } |
2080 } | 1921 } |
2081 cycles(&opts->gen, BUS); | 1922 cycles(&opts->gen, BUS); |
2318 } else if(inst->op == M68K_CMP) { | 2159 } else if(inst->op == M68K_CMP) { |
2319 return translate_m68k_cmp(opts, inst); | 2160 return translate_m68k_cmp(opts, inst); |
2320 } | 2161 } |
2321 x86_ea src_op, dst_op; | 2162 x86_ea src_op, dst_op; |
2322 if (inst->src.addr_mode != MODE_UNUSED) { | 2163 if (inst->src.addr_mode != MODE_UNUSED) { |
2323 translate_m68k_src(inst, &src_op, opts); | 2164 translate_m68k_op(inst, &src_op, opts, 0); |
2324 } | 2165 } |
2325 if (inst->dst.addr_mode != MODE_UNUSED) { | 2166 if (inst->dst.addr_mode != MODE_UNUSED) { |
2326 translate_m68k_dst(inst, &dst_op, opts, 0); | 2167 translate_m68k_op(inst, &dst_op, opts, 1); |
2327 } | 2168 } |
2328 uint8_t size; | 2169 uint8_t size; |
2329 switch(inst->op) | 2170 switch(inst->op) |
2330 { | 2171 { |
2331 case M68K_ABCD: | 2172 case M68K_ABCD: |