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}