Mercurial > repos > blastem
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 { |