main
backend_x86.c
1#include "backend.h"
2#include "gen_x86.h"
3#include <string.h>
4
5void cycles(cpu_options *opts, uint32_t num)
6{
7 if (opts->limit < 0) {
8 sub_ir(&opts->code, num*opts->clock_divider, opts->cycles, SZ_D);
9 } else {
10 add_ir(&opts->code, num*opts->clock_divider, opts->cycles, SZ_D);
11 }
12}
13
14void check_cycles_int(cpu_options *opts, uint32_t address)
15{
16 code_info *code = &opts->code;
17 uint8_t cc;
18 if (opts->limit < 0) {
19 cmp_ir(code, 1, opts->cycles, SZ_D);
20 cc = CC_NS;
21 } else {
22 cmp_rr(code, opts->cycles, opts->limit, SZ_D);
23 cc = CC_A;
24 }
25 code_ptr jmp_off = code->cur+1;
26 jcc(code, cc, jmp_off+1);
27 mov_ir(code, address, opts->scratch1, SZ_D);
28 call(code, opts->handle_cycle_limit_int);
29 *jmp_off = code->cur - (jmp_off+1);
30}
31
32void retranslate_calc(cpu_options *opts)
33{
34 code_info *code = &opts->code;
35 code_info tmp = *code;
36 uint8_t cc;
37 if (opts->limit < 0) {
38 cmp_ir(code, 1, opts->cycles, SZ_D);
39 cc = CC_NS;
40 } else {
41 cmp_rr(code, opts->cycles, opts->limit, SZ_D);
42 cc = CC_A;
43 }
44 jcc(code, cc, code->cur+2);
45 opts->move_pc_off = code->cur - tmp.cur;
46 mov_ir(code, 0x1234, opts->scratch1, SZ_D);
47 opts->move_pc_size = code->cur - tmp.cur - opts->move_pc_off;
48 *code = tmp;
49}
50
51void patch_for_retranslate(cpu_options *opts, code_ptr native_address, code_ptr handler)
52{
53 if (!is_mov_ir(native_address)) {
54 //instruction is not already patched for either retranslation or a breakpoint
55 //copy original mov_ir instruction containing PC to beginning of native code area
56 memmove(native_address, native_address + opts->move_pc_off, opts->move_pc_size);
57 }
58 //jump to the retranslation handler
59 code_info tmp = {
60 .cur = native_address + opts->move_pc_size,
61 .last = native_address + 256,
62 .stack_off = 0
63 };
64 jmp(&tmp, handler);
65}
66
67void check_cycles(cpu_options * opts)
68{
69 code_info *code = &opts->code;
70 uint8_t cc;
71 if (opts->limit < 0) {
72 cmp_ir(code, 1, opts->cycles, SZ_D);
73 cc = CC_NS;
74 } else {
75 cmp_rr(code, opts->cycles, opts->limit, SZ_D);
76 cc = CC_A;
77 }
78 check_alloc_code(code, MAX_INST_LEN*2);
79 code_ptr jmp_off = code->cur+1;
80 jcc(code, cc, jmp_off+1);
81 call(code, opts->handle_cycle_limit);
82 *jmp_off = code->cur - (jmp_off+1);
83}
84
85void log_address(cpu_options *opts, uint32_t address, char * format)
86{
87 code_info *code = &opts->code;
88 call(code, opts->save_context);
89 push_r(code, opts->context_reg);
90 mov_rr(code, opts->cycles, RDX, SZ_D);
91 mov_ir(code, (int64_t)format, RDI, SZ_PTR);
92 mov_ir(code, address, RSI, SZ_D);
93 call_args_abi(code, (code_ptr)printf, 3, RDI, RSI, RDX);
94 pop_r(code, opts->context_reg);
95 call(code, opts->load_context);
96}
97
98void check_code_prologue(code_info *code)
99{
100 check_alloc_code(code, MAX_INST_LEN*4);
101}
102
103code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc)
104{
105 code_info *code = &opts->code;
106 code_ptr start = code->cur;
107 check_cycles(opts);
108 uint8_t is_write = fun_type == WRITE_16 || fun_type == WRITE_8;
109 uint8_t adr_reg = is_write ? opts->scratch2 : opts->scratch1;
110 uint8_t size = (fun_type == READ_16 || fun_type == WRITE_16) ? SZ_W : SZ_B;
111 if (size != SZ_B && opts->align_error_mask) {
112 test_ir(code, opts->align_error_mask, adr_reg, SZ_D);
113 jcc(code, CC_NZ, is_write ? opts->handle_align_error_write : opts->handle_align_error_read);
114 }
115 cycles(opts, opts->bus_cycles);
116 if (after_inc) {
117 *after_inc = code->cur;
118 }
119
120 if (opts->address_size == SZ_D && opts->address_mask != 0xFFFFFFFF) {
121 and_ir(code, opts->address_mask, adr_reg, SZ_D);
122 } else if (opts->address_size == SZ_W && opts->address_mask != 0xFFFF) {
123 and_ir(code, opts->address_mask, adr_reg, SZ_W);
124 }
125 code_ptr lb_jcc = NULL, ub_jcc = NULL;
126 uint16_t access_flag = is_write ? MMAP_WRITE : MMAP_READ;
127 uint32_t ram_flags_off = opts->ram_flags_off;
128 uint32_t min_address = 0;
129 uint32_t max_address = opts->max_address;
130 for (uint32_t chunk = 0; chunk < num_chunks; chunk++)
131 {
132 if (memmap[chunk].start > min_address) {
133 cmp_ir(code, memmap[chunk].start, adr_reg, opts->address_size);
134 lb_jcc = code->cur + 1;
135 jcc(code, CC_C, code->cur + 2);
136 } else {
137 min_address = memmap[chunk].end;
138 }
139 if (memmap[chunk].end < max_address) {
140 cmp_ir(code, memmap[chunk].end, adr_reg, opts->address_size);
141 ub_jcc = code->cur + 1;
142 jcc(code, CC_NC, code->cur + 2);
143 } else {
144 max_address = memmap[chunk].start;
145 }
146
147 if (memmap[chunk].mask != opts->address_mask) {
148 and_ir(code, memmap[chunk].mask, adr_reg, opts->address_size);
149 }
150 void * cfun;
151 switch (fun_type)
152 {
153 case READ_16:
154 cfun = memmap[chunk].read_16;
155 break;
156 case READ_8:
157 cfun = memmap[chunk].read_8;
158 break;
159 case WRITE_16:
160 cfun = memmap[chunk].write_16;
161 break;
162 case WRITE_8:
163 cfun = memmap[chunk].write_8;
164 break;
165 default:
166 cfun = NULL;
167 }
168 if(memmap[chunk].flags & access_flag) {
169 if (memmap[chunk].flags & MMAP_PTR_IDX) {
170 if (memmap[chunk].flags & MMAP_FUNC_NULL) {
171 cmp_irdisp(code, 0, opts->context_reg, opts->mem_ptr_off + sizeof(void*) * memmap[chunk].ptr_index, SZ_PTR);
172 code_ptr not_null = code->cur + 1;
173 jcc(code, CC_NZ, code->cur + 2);
174 call(code, opts->save_context);
175 if (is_write) {
176 call_args_abi(code, cfun, 3, opts->scratch2, opts->context_reg, opts->scratch1);
177 mov_rr(code, RAX, opts->context_reg, SZ_PTR);
178 } else {
179 push_r(code, opts->context_reg);
180 call_args_abi(code, cfun, 2, opts->scratch1, opts->context_reg);
181 pop_r(code, opts->context_reg);
182 mov_rr(code, RAX, opts->scratch1, size);
183 }
184 jmp(code, opts->load_context);
185
186 *not_null = code->cur - (not_null + 1);
187 }
188 if ((opts->byte_swap || memmap[chunk].flags & MMAP_BYTESWAP) && size == SZ_B) {
189 xor_ir(code, 1, adr_reg, opts->address_size);
190 }
191 if (opts->address_size != SZ_D) {
192 movzx_rr(code, adr_reg, adr_reg, opts->address_size, SZ_D);
193 }
194 if (is_write && (memmap[chunk].flags & MMAP_CODE)) {
195 push_r(code, adr_reg);
196 }
197 add_rdispr(code, opts->context_reg, opts->mem_ptr_off + sizeof(void*) * memmap[chunk].ptr_index, adr_reg, SZ_PTR);
198 if (is_write) {
199 mov_rrind(code, opts->scratch1, opts->scratch2, size);
200 if (memmap[chunk].flags & MMAP_CODE) {
201 pop_r(code, adr_reg);
202 }
203 } else {
204 mov_rindr(code, opts->scratch1, opts->scratch1, size);
205 }
206 } else {
207 uint8_t tmp_size = size;
208 if (size == SZ_B) {
209 if ((memmap[chunk].flags & MMAP_ONLY_ODD) || (memmap[chunk].flags & MMAP_ONLY_EVEN)) {
210 bt_ir(code, 0, adr_reg, opts->address_size);
211 code_ptr good_addr = code->cur + 1;
212 jcc(code, (memmap[chunk].flags & MMAP_ONLY_ODD) ? CC_C : CC_NC, code->cur + 2);
213 if (!is_write) {
214 mov_ir(code, 0xFF, opts->scratch1, SZ_B);
215 }
216 retn(code);
217 *good_addr = code->cur - (good_addr + 1);
218 shr_ir(code, 1, adr_reg, opts->address_size);
219 } else if (opts->byte_swap || memmap[chunk].flags & MMAP_BYTESWAP) {
220 xor_ir(code, 1, adr_reg, opts->address_size);
221 }
222 } else if ((memmap[chunk].flags & MMAP_ONLY_ODD) || (memmap[chunk].flags & MMAP_ONLY_EVEN)) {
223 tmp_size = SZ_B;
224 shr_ir(code, 1, adr_reg, opts->address_size);
225 if ((memmap[chunk].flags & MMAP_ONLY_EVEN) && is_write) {
226 shr_ir(code, 8, opts->scratch1, SZ_W);
227 }
228 }
229 if (opts->address_size != SZ_D) {
230 movzx_rr(code, adr_reg, adr_reg, opts->address_size, SZ_D);
231 }
232 if ((intptr_t)memmap[chunk].buffer <= 0x7FFFFFFF && (intptr_t)memmap[chunk].buffer >= -2147483648) {
233 if (is_write) {
234 mov_rrdisp(code, opts->scratch1, opts->scratch2, (intptr_t)memmap[chunk].buffer, tmp_size);
235 } else {
236 mov_rdispr(code, opts->scratch1, (intptr_t)memmap[chunk].buffer, opts->scratch1, tmp_size);
237 }
238 } else {
239 if (is_write) {
240 push_r(code, opts->scratch2);
241 mov_ir(code, (intptr_t)memmap[chunk].buffer, opts->scratch2, SZ_PTR);
242 add_rdispr(code, RSP, 0, opts->scratch2, SZ_PTR);
243 mov_rrind(code, opts->scratch1, opts->scratch2, tmp_size);
244 if (is_write && (memmap[chunk].flags & MMAP_CODE)) {
245 pop_r(code, opts->scratch2);
246 } else {
247 add_ir(code, sizeof(void*), RSP, SZ_PTR);
248 code->stack_off -= sizeof(void *);
249 }
250 } else {
251 push_r(code, opts->scratch2);
252 mov_ir(code, (intptr_t)memmap[chunk].buffer, opts->scratch2, SZ_PTR);
253 mov_rindexr(code, opts->scratch2, opts->scratch1, 1, opts->scratch1, tmp_size);
254 pop_r(code, opts->scratch2);
255 }
256 }
257 if (size != tmp_size && !is_write) {
258 if (memmap[chunk].flags & MMAP_ONLY_EVEN) {
259 shl_ir(code, 8, opts->scratch1, SZ_W);
260 mov_ir(code, 0xFF, opts->scratch1, SZ_B);
261 } else {
262 or_ir(code, 0xFF00, opts->scratch1, SZ_W);
263 }
264 }
265 }
266 if (is_write && (memmap[chunk].flags & MMAP_CODE)) {
267 mov_rr(code, opts->scratch2, opts->scratch1, opts->address_size);
268 shr_ir(code, opts->ram_flags_shift, opts->scratch1, opts->address_size);
269 bt_rrdisp(code, opts->scratch1, opts->context_reg, ram_flags_off, opts->address_size);
270 code_ptr not_code = code->cur + 1;
271 jcc(code, CC_NC, code->cur + 2);
272 if (memmap[chunk].mask != opts->address_mask) {
273 or_ir(code, memmap[chunk].start, opts->scratch2, opts->address_size);
274 }
275 call(code, opts->save_context);
276 call_args(code, opts->handle_code_write, 2, opts->scratch2, opts->context_reg);
277 mov_rr(code, RAX, opts->context_reg, SZ_PTR);
278 jmp(code, opts->load_context);
279 *not_code = code->cur - (not_code+1);
280 }
281 retn(code);
282 } else if (cfun) {
283 call(code, opts->save_context);
284 if (is_write) {
285 call_args_abi(code, cfun, 3, opts->scratch2, opts->context_reg, opts->scratch1);
286 mov_rr(code, RAX, opts->context_reg, SZ_PTR);
287 } else {
288 push_r(code, opts->context_reg);
289 call_args_abi(code, cfun, 2, opts->scratch1, opts->context_reg);
290 pop_r(code, opts->context_reg);
291 mov_rr(code, RAX, opts->scratch1, size);
292 }
293 jmp(code, opts->load_context);
294 } else {
295 //Not sure the best course of action here
296 if (!is_write) {
297 mov_ir(code, size == SZ_B ? 0xFF : 0xFFFF, opts->scratch1, size);
298 }
299 retn(code);
300 }
301 if (memmap[chunk].flags & MMAP_CODE) {
302 if (memmap[chunk].mask == opts->address_mask) {
303 ram_flags_off += (memmap[chunk].end - memmap[chunk].start) / (1 << opts->ram_flags_shift) / 8; ;
304 } else {
305 ram_flags_off += (memmap[chunk].mask + 1) / (1 << opts->ram_flags_shift) / 8;;
306 }
307 }
308 if (lb_jcc) {
309 *lb_jcc = code->cur - (lb_jcc+1);
310 lb_jcc = NULL;
311 }
312 if (ub_jcc) {
313 *ub_jcc = code->cur - (ub_jcc+1);
314 ub_jcc = NULL;
315 }
316 }
317 if (!is_write) {
318 mov_ir(code, size == SZ_B ? 0xFF : 0xFFFF, opts->scratch1, size);
319 }
320 retn(code);
321 return start;
322}