comparison m68k_core.c @ 574:1594525e2157

More 68K core refactoring to both reduce the amount of code and better split the host-cpu specific parts from the generic parts
author Michael Pavone <pavone@retrodev.com>
date Mon, 03 Mar 2014 22:17:20 -0800
parents 76bba9ffe351
children 9f40aa5243c2
comparison
equal deleted inserted replaced
573:29d99db6f55d 574:1594525e2157
11 #include <stdio.h> 11 #include <stdio.h>
12 #include <stddef.h> 12 #include <stddef.h>
13 #include <stdlib.h> 13 #include <stdlib.h>
14 #include <string.h> 14 #include <string.h>
15 15
16 char disasm_buf[1024];
17
16 int8_t native_reg(m68k_op_info * op, m68k_options * opts) 18 int8_t native_reg(m68k_op_info * op, m68k_options * opts)
17 { 19 {
18 if (op->addr_mode == MODE_REG) { 20 if (op->addr_mode == MODE_REG) {
19 return opts->dregs[op->params.regs.pri]; 21 return opts->dregs[op->params.regs.pri];
20 } 22 }
22 return opts->aregs[op->params.regs.pri]; 24 return opts->aregs[op->params.regs.pri];
23 } 25 }
24 return -1; 26 return -1;
25 } 27 }
26 28
29 size_t dreg_offset(uint8_t reg)
30 {
31 return offsetof(m68k_context, dregs) + sizeof(uint32_t) * reg;
32 }
33
34 size_t areg_offset(uint8_t reg)
35 {
36 return offsetof(m68k_context, aregs) + sizeof(uint32_t) * reg;
37 }
38
27 //must be called with an m68k_op_info that uses a register 39 //must be called with an m68k_op_info that uses a register
28 size_t reg_offset(m68k_op_info *op) 40 size_t reg_offset(m68k_op_info *op)
29 { 41 {
30 if (op->addr_mode == MODE_REG) { 42 return op->addr_mode == MODE_REG ? dreg_offset(op->params.regs.pri) : areg_offset(op->params.regs.pri);
31 return offsetof(m68k_context, dregs) + sizeof(uint32_t) * op->params.regs.pri;
32 }
33 return offsetof(m68k_context, aregs) + sizeof(uint32_t) * op->params.regs.pri;
34 } 43 }
35 44
36 void print_regs_exit(m68k_context * context) 45 void print_regs_exit(m68k_context * context)
37 { 46 {
38 printf("XNZVC\n%d%d%d%d%d\n", context->flags[0], context->flags[1], context->flags[2], context->flags[3], context->flags[4]); 47 printf("XNZVC\n%d%d%d%d%d\n", context->flags[0], context->flags[1], context->flags[2], context->flags[3], context->flags[4]);
73 break; 82 break;
74 case OPSIZE_LONG: 83 case OPSIZE_LONG:
75 call(&opts->gen.code, opts->write_32_highfirst); 84 call(&opts->gen.code, opts->write_32_highfirst);
76 break; 85 break;
77 } 86 }
87 }
88
89 void translate_m68k_lea(m68k_options * opts, m68kinst * inst)
90 {
91 code_info *code = &opts->gen.code;
92 int8_t dst_reg = native_reg(&(inst->dst), opts);
93 switch(inst->src.addr_mode)
94 {
95 case MODE_AREG_INDIRECT:
96 cycles(&opts->gen, BUS);
97 if (dst_reg >= 0) {
98 areg_to_native(opts, inst->src.params.regs.pri, dst_reg);
99 } else {
100 if (opts->aregs[inst->src.params.regs.pri] >= 0) {
101 native_to_areg(opts, opts->aregs[inst->src.params.regs.pri], inst->dst.params.regs.pri);
102 } else {
103 areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
104 native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
105 }
106 }
107 break;
108 case MODE_AREG_DISPLACE:
109 cycles(&opts->gen, 8);
110 calc_areg_displace(opts, &inst->src, dst_reg >= 0 ? dst_reg : opts->gen.scratch1);
111 if (dst_reg < 0) {
112 native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
113 }
114 break;
115 case MODE_AREG_INDEX_DISP8:
116 cycles(&opts->gen, 12);
117 if (dst_reg < 0 || inst->dst.params.regs.pri == inst->src.params.regs.pri || inst->dst.params.regs.pri == (inst->src.params.regs.sec >> 1 & 0x7)) {
118 dst_reg = opts->gen.scratch1;
119 }
120 calc_areg_index_disp8(opts, &inst->src, dst_reg);
121 if (dst_reg == opts->gen.scratch1) {
122 native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
123 }
124 break;
125 case MODE_PC_DISPLACE:
126 cycles(&opts->gen, 8);
127 ldi_areg(opts, inst->src.params.regs.displacement + inst->address+2, inst->dst.params.regs.pri);
128 break;
129 case MODE_PC_INDEX_DISP8:
130 cycles(&opts->gen, BUS*3);
131 if (dst_reg < 0 || inst->dst.params.regs.pri == (inst->src.params.regs.sec >> 1 & 0x7)) {
132 dst_reg = opts->gen.scratch1;
133 }
134 ldi_native(opts, inst->address+2, dst_reg);
135 calc_index_disp8(opts, &inst->src, dst_reg);
136 if (dst_reg == opts->gen.scratch1) {
137 native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
138 }
139 break;
140 case MODE_ABSOLUTE:
141 case MODE_ABSOLUTE_SHORT:
142 cycles(&opts->gen, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2);
143 ldi_areg(opts, inst->src.params.immed, inst->dst.params.regs.pri);
144 break;
145 default:
146 m68k_disasm(inst, disasm_buf);
147 printf("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode);
148 exit(1);
149 }
150 }
151
152 void translate_m68k_pea(m68k_options * opts, m68kinst * inst)
153 {
154 code_info *code = &opts->gen.code;
155 switch(inst->src.addr_mode)
156 {
157 case MODE_AREG_INDIRECT:
158 cycles(&opts->gen, BUS);
159 areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
160 break;
161 case MODE_AREG_DISPLACE:
162 cycles(&opts->gen, 8);
163 calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
164 break;
165 case MODE_AREG_INDEX_DISP8:
166 cycles(&opts->gen, 6);//TODO: Check to make sure this is correct
167 calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1);
168 break;
169 case MODE_PC_DISPLACE:
170 cycles(&opts->gen, 8);
171 ldi_native(opts, inst->src.params.regs.displacement + inst->address+2, opts->gen.scratch1);
172 break;
173 case MODE_PC_INDEX_DISP8:
174 cycles(&opts->gen, BUS*3);//TODO: Check to make sure this is correct
175 ldi_native(opts, inst->address+2, opts->gen.scratch1);
176 calc_index_disp8(opts, &inst->src, opts->gen.scratch1);
177 break;
178 case MODE_ABSOLUTE:
179 case MODE_ABSOLUTE_SHORT:
180 cycles(&opts->gen, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2);
181 ldi_native(opts, inst->src.params.immed, opts->gen.scratch1);
182 break;
183 default:
184 m68k_disasm(inst, disasm_buf);
185 printf("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode);
186 exit(1);
187 }
188 subi_areg(opts, 4, 7);
189 areg_to_native(opts, 7, opts->gen.scratch2);
190 call(code, opts->write_32_lowfirst);
191 }
192
193 void push_const(m68k_options *opts, int32_t value)
194 {
195 ldi_native(opts, value, opts->gen.scratch1);
196 subi_areg(opts, 4, 7);
197 areg_to_native(opts, 7, opts->gen.scratch2);
198 call(&opts->gen.code, opts->write_32_highfirst);
199 }
200
201 void jump_m68k_abs(m68k_options * opts, uint32_t address)
202 {
203 code_info *code = &opts->gen.code;
204 code_ptr dest_addr = get_native_address(opts->gen.native_code_map, address);
205 if (!dest_addr) {
206 opts->gen.deferred = defer_address(opts->gen.deferred, address, code->cur + 1);
207 //dummy address to be replaced later, make sure it generates a 4-byte displacement
208 dest_addr = code->cur + 256;
209 }
210 jmp(code, dest_addr);
211 //this used to call opts->native_addr for destinations in RAM, but that shouldn't be needed
212 //since instruction retranslation patches the original native instruction location
213 }
214
215 void translate_m68k_bsr(m68k_options * opts, m68kinst * inst)
216 {
217 code_info *code = &opts->gen.code;
218 int32_t disp = inst->src.params.immed;
219 uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : 4);
220 //TODO: Add cycles in the right place relative to pushing the return address on the stack
221 cycles(&opts->gen, 10);
222 push_const(opts, after);
223 jump_m68k_abs(opts, inst->address + 2 + disp);
224 }
225
226 void translate_m68k_jmp_jsr(m68k_options * opts, m68kinst * inst)
227 {
228 uint8_t is_jsr = inst->op == M68K_JSR;
229 code_info *code = &opts->gen.code;
230 code_ptr dest_addr;
231 uint8_t sec_reg;
232 uint32_t after;
233 uint32_t m68k_addr;
234 switch(inst->src.addr_mode)
235 {
236 case MODE_AREG_INDIRECT:
237 cycles(&opts->gen, BUS*2);
238 if (is_jsr) {
239 push_const(opts, inst->address+2);
240 }
241 areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
242 call(code, opts->native_addr);
243 jmp_r(code, opts->gen.scratch1);
244 break;
245 case MODE_AREG_DISPLACE:
246 cycles(&opts->gen, BUS*2);
247 if (is_jsr) {
248 push_const(opts, inst->address+4);
249 }
250 calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
251 call(code, opts->native_addr);
252 jmp_r(code, opts->gen.scratch1);
253 break;
254 case MODE_AREG_INDEX_DISP8:
255 cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct
256 if (is_jsr) {
257 push_const(opts, inst->address+4);
258 }
259 calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1);
260 call(code, opts->native_addr);
261 jmp_r(code, opts->gen.scratch1);
262 break;
263 case MODE_PC_DISPLACE:
264 //TODO: Add cycles in the right place relative to pushing the return address on the stack
265 cycles(&opts->gen, 10);
266 if (is_jsr) {
267 push_const(opts, inst->address+4);
268 }
269 jump_m68k_abs(opts, inst->src.params.regs.displacement + inst->address + 2);
270 break;
271 case MODE_PC_INDEX_DISP8:
272 cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct
273 if (is_jsr) {
274 push_const(opts, inst->address+4);
275 }
276 ldi_native(opts, inst->address+2, opts->gen.scratch1);
277 calc_index_disp8(opts, &inst->src, opts->gen.scratch1);
278 call(code, opts->native_addr);
279 jmp_r(code, opts->gen.scratch1);
280 break;
281 case MODE_ABSOLUTE:
282 case MODE_ABSOLUTE_SHORT:
283 //TODO: Add cycles in the right place relative to pushing the return address on the stack
284 cycles(&opts->gen, inst->src.addr_mode == MODE_ABSOLUTE ? 12 : 10);
285 if (is_jsr) {
286 push_const(opts, inst->address + (inst->src.addr_mode == MODE_ABSOLUTE ? 6 : 4));
287 }
288 jump_m68k_abs(opts, inst->src.params.immed);
289 break;
290 default:
291 m68k_disasm(inst, disasm_buf);
292 printf("%s\naddress mode %d not yet supported (%s)\n", disasm_buf, inst->src.addr_mode, is_jsr ? "jsr" : "jmp");
293 exit(1);
294 }
295 }
296
297 void translate_m68k_unlk(m68k_options * opts, m68kinst * inst)
298 {
299 cycles(&opts->gen, BUS);
300 areg_to_native(opts, inst->dst.params.regs.pri, opts->aregs[7]);
301 areg_to_native(opts, 7, opts->gen.scratch1);
302 call(&opts->gen.code, opts->read_32);
303 native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
304 addi_areg(opts, 4, 7);
305 }
306
307 void translate_m68k_link(m68k_options * opts, m68kinst * inst)
308 {
309 //compensate for displacement word
310 cycles(&opts->gen, BUS);
311 subi_areg(opts, 4, 7);
312 areg_to_native(opts, 7, opts->gen.scratch2);
313 areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
314 call(&opts->gen.code, opts->write_32_highfirst);
315 native_to_areg(opts, opts->aregs[7], inst->src.params.regs.pri);
316 addi_areg(opts, inst->dst.params.immed, 7);
317 //prefetch
318 cycles(&opts->gen, BUS);
319 }
320
321 void translate_m68k_rts(m68k_options * opts, m68kinst * inst)
322 {
323 code_info *code = &opts->gen.code;
324 //TODO: Add cycles
325 areg_to_native(opts, 7, opts->gen.scratch1);
326 addi_areg(opts, 4, 7);
327 call(code, opts->read_32);
328 call(code, opts->native_addr);
329 jmp_r(code, opts->gen.scratch1);
330 }
331
332 void translate_m68k_rtr(m68k_options *opts, m68kinst * inst)
333 {
334 code_info *code = &opts->gen.code;
335 //Read saved CCR
336 areg_to_native(opts, 7, opts->gen.scratch1);
337 call(code, opts->read_16);
338 addi_areg(opts, 2, 7);
339 call(code, opts->set_ccr);
340 //Read saved PC
341 areg_to_native(opts, 7, opts->gen.scratch1);
342 call(code, opts->read_32);
343 addi_areg(opts, 4, 7);
344 //Get native address and jump to it
345 call(code, opts->native_addr);
346 jmp_r(code, opts->gen.scratch1);
347 }
348
349 void translate_m68k_trap(m68k_options *opts, m68kinst *inst)
350 {
351 code_info *code = &opts->gen.code;
352 ldi_native(opts, inst->src.params.immed + VECTOR_TRAP_0, opts->gen.scratch2);
353 ldi_native(opts, inst->address+2, opts->gen.scratch1);
354 jmp(code, opts->trap);
355 }
356
357 void swap_ssp_usp(m68k_options * opts)
358 {
359 areg_to_native(opts, 7, opts->gen.scratch2);
360 areg_to_native(opts, 8, opts->aregs[7]);
361 native_to_areg(opts, opts->gen.scratch2, 8);
78 } 362 }
79 363
80 code_ptr get_native_address(native_map_slot * native_code_map, uint32_t address) 364 code_ptr get_native_address(native_map_slot * native_code_map, uint32_t address)
81 { 365 {
82 address &= 0xFFFFFF; 366 address &= 0xFFFFFF;
276 context->aregs[7] = context->mem_pointers[0][0] << 16 | context->mem_pointers[0][1]; 560 context->aregs[7] = context->mem_pointers[0][0] << 16 | context->mem_pointers[0][1];
277 uint32_t address = context->mem_pointers[0][2] << 16 | context->mem_pointers[0][3]; 561 uint32_t address = context->mem_pointers[0][2] << 16 | context->mem_pointers[0][3];
278 start_68k_context(context, address); 562 start_68k_context(context, address);
279 } 563 }
280 564
565
566 void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts)
567 {
568 memset(context, 0, sizeof(m68k_context));
569 context->native_code_map = native_code_map;
570 context->options = opts;
571 context->int_cycle = 0xFFFFFFFF;
572 context->status = 0x27;
573 }