Mercurial > repos > blastem
comparison m68k_core.c @ 570:76bba9ffe351
Initial stab at separating the generic parts of the 68K core from the host-cpu specific parts.
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 02 Mar 2014 16:34:29 -0800 |
parents | |
children | 1594525e2157 |
comparison
equal
deleted
inserted
replaced
569:9b7fcf748be0 | 570:76bba9ffe351 |
---|---|
1 /* | |
2 Copyright 2014 Michael Pavone | |
3 This file is part of BlastEm. | |
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. | |
5 */ | |
6 #include "m68k_core.h" | |
7 #include "m68k_internal.h" | |
8 #include "68kinst.h" | |
9 #include "backend.h" | |
10 #include "gen.h" | |
11 #include <stdio.h> | |
12 #include <stddef.h> | |
13 #include <stdlib.h> | |
14 #include <string.h> | |
15 | |
16 int8_t native_reg(m68k_op_info * op, m68k_options * opts) | |
17 { | |
18 if (op->addr_mode == MODE_REG) { | |
19 return opts->dregs[op->params.regs.pri]; | |
20 } | |
21 if (op->addr_mode == MODE_AREG) { | |
22 return opts->aregs[op->params.regs.pri]; | |
23 } | |
24 return -1; | |
25 } | |
26 | |
27 //must be called with an m68k_op_info that uses a register | |
28 size_t reg_offset(m68k_op_info *op) | |
29 { | |
30 if (op->addr_mode == MODE_REG) { | |
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 } | |
35 | |
36 void print_regs_exit(m68k_context * context) | |
37 { | |
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]); | |
39 for (int i = 0; i < 8; i++) { | |
40 printf("d%d: %X\n", i, context->dregs[i]); | |
41 } | |
42 for (int i = 0; i < 8; i++) { | |
43 printf("a%d: %X\n", i, context->aregs[i]); | |
44 } | |
45 exit(0); | |
46 } | |
47 | |
48 void m68k_read_size(m68k_options *opts, uint8_t size) | |
49 { | |
50 switch (size) | |
51 { | |
52 case OPSIZE_BYTE: | |
53 call(&opts->gen.code, opts->read_8); | |
54 break; | |
55 case OPSIZE_WORD: | |
56 call(&opts->gen.code, opts->read_16); | |
57 break; | |
58 case OPSIZE_LONG: | |
59 call(&opts->gen.code, opts->read_32); | |
60 break; | |
61 } | |
62 } | |
63 | |
64 void m68k_write_size(m68k_options *opts, uint8_t size) | |
65 { | |
66 switch (size) | |
67 { | |
68 case OPSIZE_BYTE: | |
69 call(&opts->gen.code, opts->write_8); | |
70 break; | |
71 case OPSIZE_WORD: | |
72 call(&opts->gen.code, opts->write_16); | |
73 break; | |
74 case OPSIZE_LONG: | |
75 call(&opts->gen.code, opts->write_32_highfirst); | |
76 break; | |
77 } | |
78 } | |
79 | |
80 code_ptr get_native_address(native_map_slot * native_code_map, uint32_t address) | |
81 { | |
82 address &= 0xFFFFFF; | |
83 address /= 2; | |
84 uint32_t chunk = address / NATIVE_CHUNK_SIZE; | |
85 if (!native_code_map[chunk].base) { | |
86 return NULL; | |
87 } | |
88 uint32_t offset = address % NATIVE_CHUNK_SIZE; | |
89 if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET || native_code_map[chunk].offsets[offset] == EXTENSION_WORD) { | |
90 return NULL; | |
91 } | |
92 return native_code_map[chunk].base + native_code_map[chunk].offsets[offset]; | |
93 } | |
94 | |
95 code_ptr get_native_from_context(m68k_context * context, uint32_t address) | |
96 { | |
97 return get_native_address(context->native_code_map, address); | |
98 } | |
99 | |
100 uint32_t get_instruction_start(native_map_slot * native_code_map, uint32_t address) | |
101 { | |
102 address &= 0xFFFFFF; | |
103 address /= 2; | |
104 uint32_t chunk = address / NATIVE_CHUNK_SIZE; | |
105 if (!native_code_map[chunk].base) { | |
106 return 0; | |
107 } | |
108 uint32_t offset = address % NATIVE_CHUNK_SIZE; | |
109 if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) { | |
110 return 0; | |
111 } | |
112 while (native_code_map[chunk].offsets[offset] == EXTENSION_WORD) { | |
113 --address; | |
114 chunk = address / NATIVE_CHUNK_SIZE; | |
115 offset = address % NATIVE_CHUNK_SIZE; | |
116 } | |
117 return address*2; | |
118 } | |
119 | |
120 void map_native_address(m68k_context * context, uint32_t address, code_ptr native_addr, uint8_t size, uint8_t native_size) | |
121 { | |
122 native_map_slot * native_code_map = context->native_code_map; | |
123 m68k_options * opts = context->options; | |
124 address &= 0xFFFFFF; | |
125 if (address > 0xE00000) { | |
126 context->ram_code_flags[(address & 0xC000) >> 14] |= 1 << ((address & 0x3800) >> 11); | |
127 if (((address & 0x3FFF) + size) & 0xC000) { | |
128 context->ram_code_flags[((address+size) & 0xC000) >> 14] |= 1 << (((address+size) & 0x3800) >> 11); | |
129 } | |
130 uint32_t slot = (address & 0xFFFF)/1024; | |
131 if (!opts->gen.ram_inst_sizes[slot]) { | |
132 opts->gen.ram_inst_sizes[slot] = malloc(sizeof(uint8_t) * 512); | |
133 } | |
134 opts->gen.ram_inst_sizes[slot][((address & 0xFFFF)/2)%512] = native_size; | |
135 } | |
136 address/= 2; | |
137 uint32_t chunk = address / NATIVE_CHUNK_SIZE; | |
138 if (!native_code_map[chunk].base) { | |
139 native_code_map[chunk].base = native_addr; | |
140 native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE); | |
141 memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE); | |
142 } | |
143 uint32_t offset = address % NATIVE_CHUNK_SIZE; | |
144 native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base; | |
145 for(address++,size-=2; size; address++,size-=2) { | |
146 chunk = address / NATIVE_CHUNK_SIZE; | |
147 offset = address % NATIVE_CHUNK_SIZE; | |
148 if (!native_code_map[chunk].base) { | |
149 native_code_map[chunk].base = native_addr; | |
150 native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE); | |
151 memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE); | |
152 } | |
153 native_code_map[chunk].offsets[offset] = EXTENSION_WORD; | |
154 } | |
155 } | |
156 | |
157 uint8_t get_native_inst_size(m68k_options * opts, uint32_t address) | |
158 { | |
159 if (address < 0xE00000) { | |
160 return 0; | |
161 } | |
162 uint32_t slot = (address & 0xFFFF)/1024; | |
163 return opts->gen.ram_inst_sizes[slot][((address & 0xFFFF)/2)%512]; | |
164 } | |
165 | |
166 uint8_t m68k_is_terminal(m68kinst * inst) | |
167 { | |
168 return inst->op == M68K_RTS || inst->op == M68K_RTE || inst->op == M68K_RTR || inst->op == M68K_JMP | |
169 || inst->op == M68K_TRAP || inst->op == M68K_ILLEGAL || inst->op == M68K_INVALID || inst->op == M68K_RESET | |
170 || (inst->op == M68K_BCC && inst->extra.cond == COND_TRUE); | |
171 } | |
172 | |
173 void m68k_handle_deferred(m68k_context * context) | |
174 { | |
175 m68k_options * opts = context->options; | |
176 process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context); | |
177 if (opts->gen.deferred) { | |
178 translate_m68k_stream(opts->gen.deferred->address, context); | |
179 } | |
180 } | |
181 | |
182 void translate_m68k_stream(uint32_t address, m68k_context * context) | |
183 { | |
184 m68kinst instbuf; | |
185 m68k_options * opts = context->options; | |
186 code_info *code = &opts->gen.code; | |
187 address &= 0xFFFFFF; | |
188 if(get_native_address(opts->gen.native_code_map, address)) { | |
189 return; | |
190 } | |
191 char disbuf[1024]; | |
192 uint16_t *encoded, *next; | |
193 if ((address & 0xFFFFFF) < 0x400000) { | |
194 encoded = context->mem_pointers[0] + (address & 0xFFFFFF)/2; | |
195 } else if ((address & 0xFFFFFF) > 0xE00000) { | |
196 encoded = context->mem_pointers[1] + (address & 0xFFFF)/2; | |
197 } else { | |
198 printf("attempt to translate non-memory address: %X\n", address); | |
199 exit(1); | |
200 } | |
201 do { | |
202 if (opts->address_log) { | |
203 fprintf(opts->address_log, "%X\n", address); | |
204 } | |
205 do { | |
206 if (address >= 0x400000 && address < 0xE00000) { | |
207 translate_out_of_bounds(code); | |
208 break; | |
209 } | |
210 code_ptr existing = get_native_address(opts->gen.native_code_map, address); | |
211 if (existing) { | |
212 jmp(code, existing); | |
213 break; | |
214 } | |
215 next = m68k_decode(encoded, &instbuf, address); | |
216 if (instbuf.op == M68K_INVALID) { | |
217 instbuf.src.params.immed = *encoded; | |
218 } | |
219 uint16_t m68k_size = (next-encoded)*2; | |
220 address += m68k_size; | |
221 encoded = next; | |
222 //m68k_disasm(&instbuf, disbuf); | |
223 //printf("%X: %s\n", instbuf.address, disbuf); | |
224 | |
225 //make sure the beginning of the code for an instruction is contiguous | |
226 check_code_prologue(code); | |
227 code_ptr start = code->cur; | |
228 translate_m68k(opts, &instbuf); | |
229 code_ptr after = code->cur; | |
230 map_native_address(context, instbuf.address, start, m68k_size, after-start); | |
231 } while(!m68k_is_terminal(&instbuf)); | |
232 process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context); | |
233 if (opts->gen.deferred) { | |
234 address = opts->gen.deferred->address; | |
235 if ((address & 0xFFFFFF) < 0x400000) { | |
236 encoded = context->mem_pointers[0] + (address & 0xFFFFFF)/2; | |
237 } else if ((address & 0xFFFFFF) > 0xE00000) { | |
238 encoded = context->mem_pointers[1] + (address & 0xFFFF)/2; | |
239 } else { | |
240 printf("attempt to translate non-memory address: %X\n", address); | |
241 exit(1); | |
242 } | |
243 } else { | |
244 encoded = NULL; | |
245 } | |
246 } while(encoded != NULL); | |
247 } | |
248 | |
249 code_ptr get_native_address_trans(m68k_context * context, uint32_t address) | |
250 { | |
251 address &= 0xFFFFFF; | |
252 code_ptr ret = get_native_address(context->native_code_map, address); | |
253 if (!ret) { | |
254 translate_m68k_stream(address, context); | |
255 ret = get_native_address(context->native_code_map, address); | |
256 } | |
257 return ret; | |
258 } | |
259 | |
260 void remove_breakpoint(m68k_context * context, uint32_t address) | |
261 { | |
262 code_ptr native = get_native_address(context->native_code_map, address); | |
263 check_cycles_int(context->options, address); | |
264 } | |
265 | |
266 void start_68k_context(m68k_context * context, uint32_t address) | |
267 { | |
268 code_ptr addr = get_native_address_trans(context, address); | |
269 m68k_options * options = context->options; | |
270 options->start_context(addr, context); | |
271 } | |
272 | |
273 void m68k_reset(m68k_context * context) | |
274 { | |
275 //TODO: Make this actually use the normal read functions | |
276 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]; | |
278 start_68k_context(context, address); | |
279 } | |
280 |