comparison z80_to_x86.c @ 252:63b9a500a00b

Implement retranslating code when written to. Possibly broken, need to fix some other bugs before a proper test.
author Mike Pavone <pavone@retrodev.com>
date Mon, 29 Apr 2013 21:46:48 -0700
parents 5f1b68cecfc7
children 3b34deba4ca0
comparison
equal deleted inserted replaced
251:4a7ac10ac2d9 252:63b9a500a00b
12 #define ZCYCLES RBP 12 #define ZCYCLES RBP
13 #define ZLIMIT RDI 13 #define ZLIMIT RDI
14 #define SCRATCH1 R13 14 #define SCRATCH1 R13
15 #define SCRATCH2 R14 15 #define SCRATCH2 R14
16 #define CONTEXT RSI 16 #define CONTEXT RSI
17
18 //TODO: Find out the actual value for this
19 #define MAX_NATIVE_SIZE 128
20 17
21 void z80_read_byte(); 18 void z80_read_byte();
22 void z80_read_word(); 19 void z80_read_word();
23 void z80_write_byte(); 20 void z80_write_byte();
24 void z80_write_word_highfirst(); 21 void z80_write_word_highfirst();
25 void z80_write_word_lowfirst(); 22 void z80_write_word_lowfirst();
26 void z80_save_context(); 23 void z80_save_context();
27 void z80_native_addr(); 24 void z80_native_addr();
28 void z80_do_sync(); 25 void z80_do_sync();
29 void z80_handle_cycle_limit_int(); 26 void z80_handle_cycle_limit_int();
27 void z80_retrans_stub();
30 28
31 uint8_t z80_size(z80inst * inst) 29 uint8_t z80_size(z80inst * inst)
32 { 30 {
33 uint8_t reg = (inst->reg & 0x1F); 31 uint8_t reg = (inst->reg & 0x1F);
34 if (reg != Z80_UNUSED && reg != Z80_USE_IMMED) { 32 if (reg != Z80_UNUSED && reg != Z80_USE_IMMED) {
1165 if (address < 0x4000) { 1163 if (address < 0x4000) {
1166 address &= 0x1FFF; 1164 address &= 0x1FFF;
1167 map = context->static_code_map; 1165 map = context->static_code_map;
1168 } else if (address >= 0x8000) { 1166 } else if (address >= 0x8000) {
1169 address &= 0x7FFF; 1167 address &= 0x7FFF;
1170 map = context->banked_code_map + context->bank_reg; 1168 map = context->banked_code_map + (context->bank_reg << 15);
1171 } else { 1169 } else {
1172 return NULL; 1170 return NULL;
1173 } 1171 }
1174 if (!map->base || !map->offsets || map->offsets[address] == INVALID_OFFSET) { 1172 if (!map->base || !map->offsets || map->offsets[address] == INVALID_OFFSET) {
1175 return NULL; 1173 return NULL;
1176 } 1174 }
1177 return map->base + map->offsets[address]; 1175 return map->base + map->offsets[address];
1178 } 1176 }
1179 1177
1180 //TODO: Record z80 instruction size and code size for addresses to support modification of translated code 1178 uint8_t z80_get_native_inst_size(x86_z80_options * opts, uint32_t address)
1181 void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * native_address) 1179 {
1182 { 1180 if (address >= 0x4000) {
1181 return 0;
1182 }
1183 return opts->ram_inst_sizes[address & 0x1FFF];
1184 }
1185
1186 void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * native_address, uint8_t size, uint8_t native_size)
1187 {
1188 uint32_t orig_address = address;
1183 native_map_slot *map; 1189 native_map_slot *map;
1190 x86_z80_options * opts = context->options;
1184 if (address < 0x4000) { 1191 if (address < 0x4000) {
1185 address &= 0x1FFF; 1192 address &= 0x1FFF;
1186 map = context->static_code_map; 1193 map = context->static_code_map;
1194 opts->ram_inst_sizes[address] = native_size;
1195 context->ram_code_flags[(address & 0x1C00) >> 10] |= 1 << ((address & 0x380) >> 7);
1196 context->ram_code_flags[((address + size) & 0x1C00) >> 10] |= 1 << (((address + size) & 0x380) >> 7);
1187 } else if (address >= 0x8000) { 1197 } else if (address >= 0x8000) {
1188 address &= 0x7FFF; 1198 address &= 0x7FFF;
1189 map = context->banked_code_map + context->bank_reg; 1199 map = context->banked_code_map + (context->bank_reg << 15);
1190 if (!map->offsets) { 1200 if (!map->offsets) {
1191 map->offsets = malloc(sizeof(int32_t) * 0x8000); 1201 map->offsets = malloc(sizeof(int32_t) * 0x8000);
1192 memset(map->offsets, 0xFF, sizeof(int32_t) * 0x8000); 1202 memset(map->offsets, 0xFF, sizeof(int32_t) * 0x8000);
1193 } 1203 }
1194 } else { 1204 } else {
1196 } 1206 }
1197 if (!map->base) { 1207 if (!map->base) {
1198 map->base = native_address; 1208 map->base = native_address;
1199 } 1209 }
1200 map->offsets[address] = native_address - map->base; 1210 map->offsets[address] = native_address - map->base;
1211 for(--size; size; --size, orig_address++) {
1212 address = orig_address;
1213 if (address < 0x4000) {
1214 address &= 0x1FFF;
1215 map = context->static_code_map;
1216 } else if (address >= 0x8000) {
1217 address &= 0x7FFF;
1218 map = context->banked_code_map + (context->bank_reg << 15);
1219 } else {
1220 return;
1221 }
1222 if (!map->offsets) {
1223 map->offsets = malloc(sizeof(int32_t) * 0x8000);
1224 memset(map->offsets, 0xFF, sizeof(int32_t) * 0x8000);
1225 }
1226 map->offsets[address] = EXTENSION_WORD;
1227 }
1228 }
1229
1230 #define INVALID_INSTRUCTION_START 0xFEEDFEED
1231
1232 uint32_t z80_get_instruction_start(native_map_slot * static_code_map, uint32_t address)
1233 {
1234 if (!static_code_map->base || address >= 0x4000) {
1235 return INVALID_INSTRUCTION_START;
1236 }
1237 address &= 0x1FFF;
1238 if (static_code_map->offsets[address] == INVALID_OFFSET) {
1239 return INVALID_INSTRUCTION_START;
1240 }
1241 while (static_code_map->offsets[address] == EXTENSION_WORD) {
1242 --address;
1243 address &= 0x1FFF;
1244 }
1245 return address;
1246 }
1247
1248 z80_context * z80_handle_code_write(uint32_t address, z80_context * context)
1249 {
1250 uint32_t inst_start = z80_get_instruction_start(context->static_code_map, address);
1251 if (inst_start != INVALID_INSTRUCTION_START) {
1252 uint8_t * dst = z80_get_native_address(context, inst_start);
1253 dst = mov_ir(dst, inst_start, SCRATCH1, SZ_D);
1254 dst = jmp(dst, (uint8_t *)z80_retrans_stub);
1255 }
1256 return context;
1257 }
1258
1259 void * z80_retranslate_inst(uint32_t address, z80_context * context)
1260 {
1261 x86_z80_options * opts = context->options;
1262 uint8_t orig_size = z80_get_native_inst_size(opts, address);
1263 uint8_t * orig_start = z80_get_native_address(context, address);
1264 uint32_t orig = address;
1265 address &= 0x1FFF;
1266 uint8_t * dst = opts->cur_code;
1267 uint8_t * dst_end = opts->code_end;
1268 uint8_t *after, *inst = context->mem_pointers[0] + address;
1269 z80inst instbuf;
1270 after = z80_decode(inst, &instbuf);
1271 if (orig_size != ZMAX_NATIVE_SIZE) {
1272 if (dst_end - dst < ZMAX_NATIVE_SIZE) {
1273 size_t size = 1024*1024;
1274 dst = alloc_code(&size);
1275 opts->code_end = dst_end = dst + size;
1276 opts->cur_code = dst;
1277 }
1278 uint8_t * native_end = translate_z80inst(&instbuf, dst, context, address);
1279 if ((native_end - dst) <= orig_size) {
1280 native_end = translate_z80inst(&instbuf, orig_start, context, address);
1281 while (native_end < orig_start + orig_size) {
1282 *(native_end++) = 0x90; //NOP
1283 }
1284 return orig_start;
1285 } else {
1286 z80_map_native_address(context, address, dst, after-inst, ZMAX_NATIVE_SIZE);
1287 opts->code_end = dst+ZMAX_NATIVE_SIZE;
1288 if(!(instbuf.op == Z80_RET || instbuf.op == Z80_RETI || instbuf.op == Z80_RETN || instbuf.op == Z80_JP || (instbuf.op = Z80_NOP && instbuf.immed == 42))) {
1289 jmp(native_end, z80_get_native_address(context, address + after-inst));
1290 }
1291 return dst;
1292 }
1293 } else {
1294 dst = translate_z80inst(&instbuf, orig_start, context, address);
1295 if(!(instbuf.op == Z80_RET || instbuf.op == Z80_RETI || instbuf.op == Z80_RETN || instbuf.op == Z80_JP || (instbuf.op = Z80_NOP && instbuf.immed == 42))) {
1296 dst = jmp(dst, z80_get_native_address(context, address + after-inst));
1297 }
1298 return orig_start;
1299 }
1201 } 1300 }
1202 1301
1203 uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address) 1302 uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address)
1204 { 1303 {
1205 uint8_t * addr = z80_get_native_address(context, address); 1304 uint8_t * addr = z80_get_native_address(context, address);
1211 } 1310 }
1212 } 1311 }
1213 return addr; 1312 return addr;
1214 } 1313 }
1215 1314
1216 //uint32_t max_size = 0;
1217
1218 void translate_z80_stream(z80_context * context, uint32_t address) 1315 void translate_z80_stream(z80_context * context, uint32_t address)
1219 { 1316 {
1220 char disbuf[80]; 1317 char disbuf[80];
1221 if (z80_get_native_address(context, address)) { 1318 if (z80_get_native_address(context, address)) {
1222 return; 1319 return;
1231 while (encoded != NULL) 1328 while (encoded != NULL)
1232 { 1329 {
1233 z80inst inst; 1330 z80inst inst;
1234 printf("translating Z80 code at address %X\n", address); 1331 printf("translating Z80 code at address %X\n", address);
1235 do { 1332 do {
1236 if (opts->code_end-opts->cur_code < MAX_NATIVE_SIZE) { 1333 if (opts->code_end-opts->cur_code < ZMAX_NATIVE_SIZE) {
1237 if (opts->code_end-opts->cur_code < 5) { 1334 if (opts->code_end-opts->cur_code < 5) {
1238 puts("out of code memory, not enough space for jmp to next chunk"); 1335 puts("out of code memory, not enough space for jmp to next chunk");
1239 exit(1); 1336 exit(1);
1240 } 1337 }
1241 size_t size = 1024*1024; 1338 size_t size = 1024*1024;
1258 if (inst.op == Z80_NOP) { 1355 if (inst.op == Z80_NOP) {
1259 printf("%X\t%s(%d)\n", address, disbuf, inst.immed); 1356 printf("%X\t%s(%d)\n", address, disbuf, inst.immed);
1260 } else { 1357 } else {
1261 printf("%X\t%s\n", address, disbuf); 1358 printf("%X\t%s\n", address, disbuf);
1262 } 1359 }
1263 z80_map_native_address(context, address, opts->cur_code);
1264 uint8_t *after = translate_z80inst(&inst, opts->cur_code, context, address); 1360 uint8_t *after = translate_z80inst(&inst, opts->cur_code, context, address);
1265 //max_size = (after - opts->cur_code) > max_size ? (after - opts->cur_code) : max_size; 1361 z80_map_native_address(context, address, opts->cur_code, next-encoded, after - opts->cur_code);
1266 opts->cur_code = after; 1362 opts->cur_code = after;
1267 address += next-encoded; 1363 address += next-encoded;
1268 encoded = next; 1364 encoded = next;
1269 } while (!(inst.op == Z80_RET || inst.op == Z80_RETI || inst.op == Z80_RETN || inst.op == Z80_JP || (inst.op = Z80_NOP && inst.immed == 42))); 1365 } while (!(inst.op == Z80_RET || inst.op == Z80_RETI || inst.op == Z80_RETN || inst.op == Z80_JP || (inst.op = Z80_NOP && inst.immed == 42)));
1270 process_deferred(&opts->deferred, context, (native_addr_func)z80_get_native_address); 1366 process_deferred(&opts->deferred, context, (native_addr_func)z80_get_native_address);
1309 options->regs[Z80_IX] = RDX; 1405 options->regs[Z80_IX] = RDX;
1310 options->regs[Z80_IY] = R8; 1406 options->regs[Z80_IY] = R8;
1311 size_t size = 1024 * 1024; 1407 size_t size = 1024 * 1024;
1312 options->cur_code = alloc_code(&size); 1408 options->cur_code = alloc_code(&size);
1313 options->code_end = options->cur_code + size; 1409 options->code_end = options->cur_code + size;
1410 options->ram_inst_sizes = malloc(sizeof(uint8_t) * 0x2000);
1411 memset(options->ram_inst_sizes, 0, sizeof(uint8_t) * 0x2000);
1314 options->deferred = NULL; 1412 options->deferred = NULL;
1315 } 1413 }
1316 1414
1317 void init_z80_context(z80_context * context, x86_z80_options * options) 1415 void init_z80_context(z80_context * context, x86_z80_options * options)
1318 { 1416 {