Mercurial > repos > blastem
comparison genesis.c @ 2041:638eb2d25696 mame_interp
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 05 Aug 2021 09:29:33 -0700 |
parents | 0d5f88e53dca 3b8e29ef1145 |
children | 804954731e3f |
comparison
equal
deleted
inserted
replaced
1984:0d5f88e53dca | 2041:638eb2d25696 |
---|---|
102 start_section(buf, SECTION_SOUND_RAM); | 102 start_section(buf, SECTION_SOUND_RAM); |
103 save_int8(buf, Z80_RAM_BYTES / 1024); | 103 save_int8(buf, Z80_RAM_BYTES / 1024); |
104 save_buffer8(buf, gen->zram, Z80_RAM_BYTES); | 104 save_buffer8(buf, gen->zram, Z80_RAM_BYTES); |
105 end_section(buf); | 105 end_section(buf); |
106 | 106 |
107 if (gen->version_reg & 0xF) { | |
108 //only save TMSS info if it's present | |
109 //that will allow a state saved on a model lacking TMSS | |
110 //to be loaded on a model that has it | |
111 start_section(buf, SECTION_TMSS); | |
112 save_int8(buf, gen->tmss); | |
113 save_buffer16(buf, gen->tmss_lock, 2); | |
114 end_section(buf); | |
115 } | |
116 | |
107 cart_serialize(&gen->header, buf); | 117 cart_serialize(&gen->header, buf); |
108 } | 118 } |
109 } | 119 } |
110 | 120 |
111 static uint8_t *serialize(system_header *sys, size_t *size_out) | 121 static uint8_t *serialize(system_header *sys, size_t *size_out) |
171 gen->z80->reset = load_int8(buf); | 181 gen->z80->reset = load_int8(buf); |
172 gen->z80->busreq = load_int8(buf); | 182 gen->z80->busreq = load_int8(buf); |
173 gen->z80_bank_reg = load_int16(buf) & 0x1FF; | 183 gen->z80_bank_reg = load_int16(buf) & 0x1FF; |
174 } | 184 } |
175 | 185 |
186 static void tmss_deserialize(deserialize_buffer *buf, void *vgen) | |
187 { | |
188 genesis_context *gen = vgen; | |
189 gen->tmss = load_int8(buf); | |
190 load_buffer16(buf, gen->tmss_lock, 2); | |
191 } | |
192 | |
176 static void adjust_int_cycle(m68k_context * context, vdp_context * v_context); | 193 static void adjust_int_cycle(m68k_context * context, vdp_context * v_context); |
194 static void check_tmss_lock(genesis_context *gen); | |
195 static void toggle_tmss_rom(genesis_context *gen); | |
177 void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen) | 196 void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen) |
178 { | 197 { |
179 register_section_handler(buf, (section_handler){.fun = m68k_deserialize, .data = gen->m68k}, SECTION_68000); | 198 register_section_handler(buf, (section_handler){.fun = m68k_deserialize, .data = gen->m68k}, SECTION_68000); |
180 register_section_handler(buf, (section_handler){.fun = z80_deserialize, .data = gen->z80}, SECTION_Z80); | 199 register_section_handler(buf, (section_handler){.fun = z80_deserialize, .data = gen->z80}, SECTION_Z80); |
181 register_section_handler(buf, (section_handler){.fun = vdp_deserialize, .data = gen->vdp}, SECTION_VDP); | 200 register_section_handler(buf, (section_handler){.fun = vdp_deserialize, .data = gen->vdp}, SECTION_VDP); |
186 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 1}, SECTION_SEGA_IO_2); | 205 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 1}, SECTION_SEGA_IO_2); |
187 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 2}, SECTION_SEGA_IO_EXT); | 206 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 2}, SECTION_SEGA_IO_EXT); |
188 register_section_handler(buf, (section_handler){.fun = ram_deserialize, .data = gen}, SECTION_MAIN_RAM); | 207 register_section_handler(buf, (section_handler){.fun = ram_deserialize, .data = gen}, SECTION_MAIN_RAM); |
189 register_section_handler(buf, (section_handler){.fun = zram_deserialize, .data = gen}, SECTION_SOUND_RAM); | 208 register_section_handler(buf, (section_handler){.fun = zram_deserialize, .data = gen}, SECTION_SOUND_RAM); |
190 register_section_handler(buf, (section_handler){.fun = cart_deserialize, .data = gen}, SECTION_MAPPER); | 209 register_section_handler(buf, (section_handler){.fun = cart_deserialize, .data = gen}, SECTION_MAPPER); |
210 register_section_handler(buf, (section_handler){.fun = tmss_deserialize, .data = gen}, SECTION_TMSS); | |
211 uint8_t tmss_old = gen->tmss; | |
212 gen->tmss = 0xFF; | |
191 while (buf->cur_pos < buf->size) | 213 while (buf->cur_pos < buf->size) |
192 { | 214 { |
193 load_section(buf); | 215 load_section(buf); |
216 } | |
217 if (gen->version_reg & 0xF) { | |
218 if (gen->tmss == 0xFF) { | |
219 //state lacked a TMSS section, assume that the game ROM is mapped in | |
220 //and that the VDP is unlocked | |
221 gen->tmss_lock[0] = 0x5345; | |
222 gen->tmss_lock[1] = 0x4741; | |
223 gen->tmss = 1; | |
224 } | |
225 if (gen->tmss != tmss_old) { | |
226 toggle_tmss_rom(gen); | |
227 } | |
228 check_tmss_lock(gen); | |
194 } | 229 } |
195 update_z80_bank_pointer(gen); | 230 update_z80_bank_pointer(gen); |
196 adjust_int_cycle(gen->m68k, gen->vdp); | 231 adjust_int_cycle(gen->m68k, gen->vdp); |
197 free(buf->handlers); | 232 free(buf->handlers); |
198 buf->handlers = NULL; | 233 buf->handlers = NULL; |
240 genesis_context *gen = context->system; | 275 genesis_context *gen = context->system; |
241 if (context->sync_cycle - context->current_cycle > gen->max_cycles) { | 276 if (context->sync_cycle - context->current_cycle > gen->max_cycles) { |
242 context->sync_cycle = context->current_cycle + gen->max_cycles; | 277 context->sync_cycle = context->current_cycle + gen->max_cycles; |
243 } | 278 } |
244 context->int_cycle = CYCLE_NEVER; | 279 context->int_cycle = CYCLE_NEVER; |
245 if ((context->status & 0x7) < 6) { | 280 uint8_t mask = context->status & 0x7; |
281 if (mask < 6) { | |
246 uint32_t next_vint = vdp_next_vint(v_context); | 282 uint32_t next_vint = vdp_next_vint(v_context); |
247 if (next_vint != CYCLE_NEVER) { | 283 if (next_vint != CYCLE_NEVER) { |
248 context->int_cycle = next_vint; | 284 context->int_cycle = next_vint; |
249 context->int_num = 6; | 285 context->int_num = 6; |
250 } | 286 } |
251 if ((context->status & 0x7) < 4) { | 287 if (mask < 4) { |
252 uint32_t next_hint = vdp_next_hint(v_context); | 288 uint32_t next_hint = vdp_next_hint(v_context); |
253 if (next_hint != CYCLE_NEVER) { | 289 if (next_hint != CYCLE_NEVER) { |
254 next_hint = next_hint < context->current_cycle ? context->current_cycle : next_hint; | 290 next_hint = next_hint < context->current_cycle ? context->current_cycle : next_hint; |
255 if (next_hint < context->int_cycle) { | 291 if (next_hint < context->int_cycle) { |
256 context->int_cycle = next_hint; | 292 context->int_cycle = next_hint; |
257 context->int_num = 4; | 293 context->int_num = 4; |
258 | 294 |
295 } | |
296 } | |
297 if (mask < 2 && (v_context->regs[REG_MODE_3] & BIT_EINT_EN)) { | |
298 uint32_t next_eint_port0 = io_next_interrupt(gen->io.ports, context->current_cycle); | |
299 uint32_t next_eint_port1 = io_next_interrupt(gen->io.ports + 1, context->current_cycle); | |
300 uint32_t next_eint_port2 = io_next_interrupt(gen->io.ports + 2, context->current_cycle); | |
301 uint32_t next_eint = next_eint_port0 < next_eint_port1 | |
302 ? (next_eint_port0 < next_eint_port2 ? next_eint_port0 : next_eint_port2) | |
303 : (next_eint_port1 < next_eint_port2 ? next_eint_port1 : next_eint_port2); | |
304 if (next_eint != CYCLE_NEVER) { | |
305 next_eint = next_eint < context->current_cycle ? context->current_cycle : next_eint; | |
306 if (next_eint < context->int_cycle) { | |
307 context->int_cycle = next_eint; | |
308 context->int_num = 2; | |
309 } | |
259 } | 310 } |
260 } | 311 } |
261 } | 312 } |
262 } | 313 } |
263 if (context->int_cycle > context->current_cycle && context->int_pending == INT_PENDING_SR_CHANGE) { | 314 if (context->int_cycle > context->current_cycle && context->int_pending == INT_PENDING_SR_CHANGE) { |
272 context->target_cycle = context->current_cycle; | 323 context->target_cycle = context->current_cycle; |
273 return; | 324 return; |
274 } | 325 } |
275 | 326 |
276 context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle; | 327 context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle; |
277 if (context->should_return) { | 328 if (context->should_return || gen->header.enter_debugger) { |
278 context->target_cycle = context->current_cycle; | 329 context->target_cycle = context->current_cycle; |
279 } else if (context->target_cycle < context->current_cycle) { | 330 } else if (context->target_cycle < context->current_cycle) { |
280 //Changes to SR can result in an interrupt cycle that's in the past | 331 //Changes to SR can result in an interrupt cycle that's in the past |
281 //This can cause issues with the implementation of STOP though | 332 //This can cause issues with the implementation of STOP though |
282 context->target_cycle = context->current_cycle; | 333 context->target_cycle = context->current_cycle; |
387 | 438 |
388 uint32_t mclks = context->current_cycle; | 439 uint32_t mclks = context->current_cycle; |
389 sync_z80(z_context, mclks); | 440 sync_z80(z_context, mclks); |
390 sync_sound(gen, mclks); | 441 sync_sound(gen, mclks); |
391 vdp_run_context(v_context, mclks); | 442 vdp_run_context(v_context, mclks); |
443 io_run(gen->io.ports, mclks); | |
444 io_run(gen->io.ports + 1, mclks); | |
445 io_run(gen->io.ports + 2, mclks); | |
392 if (mclks >= gen->reset_cycle) { | 446 if (mclks >= gen->reset_cycle) { |
393 gen->reset_requested = 1; | 447 gen->reset_requested = 1; |
394 context->should_return = 1; | 448 context->should_return = 1; |
395 gen->reset_cycle = CYCLE_NEVER; | 449 gen->reset_cycle = CYCLE_NEVER; |
396 } | 450 } |
449 } | 503 } |
450 if (address) { | 504 if (address) { |
451 #ifndef NEW_CORE | 505 #ifndef NEW_CORE |
452 if (gen->header.enter_debugger) { | 506 if (gen->header.enter_debugger) { |
453 gen->header.enter_debugger = 0; | 507 gen->header.enter_debugger = 0; |
454 debugger(context, address); | 508 if (gen->header.debugger_type == DEBUGGER_NATIVE) { |
509 debugger(context, address); | |
510 } else { | |
511 gdb_debug_enter(context, address); | |
512 } | |
455 } | 513 } |
456 #endif | 514 #endif |
457 #ifdef NEW_CORE | 515 #ifdef NEW_CORE |
458 if (gen->header.save_state) { | 516 if (gen->header.save_state) { |
459 #else | 517 #else |
510 static m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) | 568 static m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) |
511 { | 569 { |
512 if (vdp_port & 0x2700E0) { | 570 if (vdp_port & 0x2700E0) { |
513 fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port); | 571 fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port); |
514 } | 572 } |
573 genesis_context * gen = context->system; | |
574 if (!gen->vdp_unlocked) { | |
575 fatal_error("machine freeze due to VDP write to %X without TMSS unlock\n", 0xC00000 | vdp_port); | |
576 } | |
515 vdp_port &= 0x1F; | 577 vdp_port &= 0x1F; |
516 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); | 578 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); |
517 #ifdef REFRESH_EMULATION | 579 #ifdef REFRESH_EMULATION |
518 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access | 580 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access |
519 if (context->current_cycle - 4*MCLKS_PER_68K > last_sync_cycle) { | 581 if (context->current_cycle - 4*MCLKS_PER_68K > last_sync_cycle) { |
522 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | 584 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); |
523 last_sync_cycle = context->current_cycle; | 585 last_sync_cycle = context->current_cycle; |
524 } | 586 } |
525 #endif | 587 #endif |
526 sync_components(context, 0); | 588 sync_components(context, 0); |
527 genesis_context * gen = context->system; | |
528 vdp_context *v_context = gen->vdp; | 589 vdp_context *v_context = gen->vdp; |
529 uint32_t before_cycle = v_context->cycles; | 590 uint32_t before_cycle = v_context->cycles; |
530 if (vdp_port < 0x10) { | 591 if (vdp_port < 0x10) { |
531 int blocked; | 592 int blocked; |
532 if (vdp_port < 4) { | 593 if (vdp_port < 4) { |
599 psg_write(gen->psg, value); | 660 psg_write(gen->psg, value); |
600 } else { | 661 } else { |
601 vdp_test_port_write(gen->vdp, value); | 662 vdp_test_port_write(gen->vdp, value); |
602 } | 663 } |
603 #ifdef REFRESH_EMULATION | 664 #ifdef REFRESH_EMULATION |
604 last_sync_cycle -= 4; | 665 last_sync_cycle -= 4 * MCLKS_PER_68K; |
605 //refresh may have happened while we were waiting on the VDP, | 666 //refresh may have happened while we were waiting on the VDP, |
606 //so advance refresh_counter but don't add any delays | 667 //so advance refresh_counter but don't add any delays |
607 if (vdp_port >= 4 && vdp_port < 8 && v_context->cycles != before_cycle) { | 668 if (vdp_port >= 4 && vdp_port < 8 && v_context->cycles != before_cycle) { |
608 refresh_counter = 0; | 669 refresh_counter = 0; |
609 } else { | 670 } else { |
651 static uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) | 712 static uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) |
652 { | 713 { |
653 if (vdp_port & 0x2700E0) { | 714 if (vdp_port & 0x2700E0) { |
654 fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port); | 715 fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port); |
655 } | 716 } |
717 genesis_context *gen = context->system; | |
718 if (!gen->vdp_unlocked) { | |
719 fatal_error("machine freeze due to VDP read from %X without TMSS unlock\n", 0xC00000 | vdp_port); | |
720 } | |
656 vdp_port &= 0x1F; | 721 vdp_port &= 0x1F; |
657 uint16_t value; | 722 uint16_t value; |
658 #ifdef REFRESH_EMULATION | 723 #ifdef REFRESH_EMULATION |
659 if (context->current_cycle - 4*MCLKS_PER_68K > last_sync_cycle) { | 724 if (context->current_cycle - 4*MCLKS_PER_68K > last_sync_cycle) { |
660 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access | 725 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access |
662 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); | 727 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); |
663 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | 728 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); |
664 last_sync_cycle = context->current_cycle; | 729 last_sync_cycle = context->current_cycle; |
665 } | 730 } |
666 #endif | 731 #endif |
667 genesis_context *gen = context->system; | 732 sync_components(context, 0); |
668 vdp_context * v_context = gen->vdp; | 733 vdp_context * v_context = gen->vdp; |
734 uint32_t before_cycle = v_context->cycles; | |
669 if (vdp_port < 0x10) { | 735 if (vdp_port < 0x10) { |
670 if (vdp_port < 4) { | 736 if (vdp_port < 4) { |
671 sync_components(context, 0); | |
672 uint32_t before_cycle = v_context->cycles; | |
673 value = vdp_data_port_read(v_context); | 737 value = vdp_data_port_read(v_context); |
674 if (v_context->cycles != before_cycle) { | |
675 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); | |
676 context->current_cycle = v_context->cycles; | |
677 //Lock the Z80 out of the bus until the VDP access is complete | |
678 genesis_context *gen = context->system; | |
679 gen->bus_busy = 1; | |
680 sync_z80(gen->z80, v_context->cycles); | |
681 gen->bus_busy = 0; | |
682 } | |
683 } else if(vdp_port < 8) { | 738 } else if(vdp_port < 8) { |
684 vdp_run_context(v_context, context->current_cycle); | |
685 value = vdp_control_port_read(v_context); | 739 value = vdp_control_port_read(v_context); |
686 } else { | 740 } else { |
687 vdp_run_context(v_context, context->current_cycle); | |
688 value = vdp_hv_counter_read(v_context); | 741 value = vdp_hv_counter_read(v_context); |
689 //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles); | 742 //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles); |
690 } | 743 } |
691 } else if (vdp_port < 0x18){ | 744 } else if (vdp_port < 0x18){ |
692 fatal_error("Illegal read from PSG port %X\n", vdp_port); | 745 fatal_error("Illegal read from PSG port %X\n", vdp_port); |
693 } else { | 746 } else { |
694 value = get_open_bus_value(&gen->header); | 747 value = get_open_bus_value(&gen->header); |
695 } | 748 } |
749 if (v_context->cycles != before_cycle) { | |
750 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); | |
751 context->current_cycle = v_context->cycles; | |
752 //Lock the Z80 out of the bus until the VDP access is complete | |
753 genesis_context *gen = context->system; | |
754 gen->bus_busy = 1; | |
755 sync_z80(gen->z80, v_context->cycles); | |
756 gen->bus_busy = 0; | |
757 } | |
696 #ifdef REFRESH_EMULATION | 758 #ifdef REFRESH_EMULATION |
697 last_sync_cycle -= 4; | 759 last_sync_cycle -= 4 * MCLKS_PER_68K; |
698 //refresh may have happened while we were waiting on the VDP, | 760 //refresh may have happened while we were waiting on the VDP, |
699 //so advance refresh_counter but don't add any delays | 761 //so advance refresh_counter but don't add any delays |
700 refresh_counter += (context->current_cycle - last_sync_cycle); | 762 refresh_counter += (context->current_cycle - last_sync_cycle); |
701 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | 763 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); |
702 last_sync_cycle = context->current_cycle; | 764 last_sync_cycle = context->current_cycle; |
753 static uint32_t zram_counter = 0; | 815 static uint32_t zram_counter = 0; |
754 | 816 |
755 static m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value) | 817 static m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value) |
756 { | 818 { |
757 genesis_context * gen = context->system; | 819 genesis_context * gen = context->system; |
820 #ifdef REFRESH_EMULATION | |
821 //do refresh check here so we can avoid adding a penalty for a refresh that happens during an IO area access | |
822 refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle; | |
823 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); | |
824 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | |
825 last_sync_cycle = context->current_cycle - 4*MCLKS_PER_68K; | |
826 #endif | |
758 if (location < 0x10000) { | 827 if (location < 0x10000) { |
759 //Access to Z80 memory incurs a one 68K cycle wait state | 828 //Access to Z80 memory incurs a one 68K cycle wait state |
760 context->current_cycle += MCLKS_PER_68K; | 829 context->current_cycle += MCLKS_PER_68K; |
761 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) { | 830 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) { |
762 location &= 0x7FFF; | 831 location &= 0x7FFF; |
806 break; | 875 break; |
807 case 0x6: | 876 case 0x6: |
808 io_control_write(gen->io.ports+2, value, context->current_cycle); | 877 io_control_write(gen->io.ports+2, value, context->current_cycle); |
809 break; | 878 break; |
810 case 0x7: | 879 case 0x7: |
811 gen->io.ports[0].serial_out = value; | 880 io_tx_write(gen->io.ports, value, context->current_cycle); |
812 break; | 881 break; |
813 case 0x8: | 882 case 0x8: |
814 case 0xB: | 883 case 0xB: |
815 case 0xE: | 884 case 0xE: |
816 //serial input port is not writeable | 885 //serial input port is not writeable |
817 break; | 886 break; |
818 case 0x9: | 887 case 0x9: |
888 io_sctrl_write(gen->io.ports, value, context->current_cycle); | |
819 gen->io.ports[0].serial_ctrl = value; | 889 gen->io.ports[0].serial_ctrl = value; |
820 break; | 890 break; |
821 case 0xA: | 891 case 0xA: |
822 gen->io.ports[1].serial_out = value; | 892 io_tx_write(gen->io.ports + 1, value, context->current_cycle); |
823 break; | 893 break; |
824 case 0xC: | 894 case 0xC: |
825 gen->io.ports[1].serial_ctrl = value; | 895 io_sctrl_write(gen->io.ports + 1, value, context->current_cycle); |
826 break; | 896 break; |
827 case 0xD: | 897 case 0xD: |
828 gen->io.ports[2].serial_out = value; | 898 io_tx_write(gen->io.ports + 2, value, context->current_cycle); |
829 break; | 899 break; |
830 case 0xF: | 900 case 0xF: |
831 gen->io.ports[2].serial_ctrl = value; | 901 io_sctrl_write(gen->io.ports + 2, value, context->current_cycle); |
832 break; | 902 break; |
833 } | 903 } |
834 } else { | 904 } else { |
835 uint32_t masked = location & 0xFFF00; | 905 uint32_t masked = location & 0xFFF00; |
836 if (masked == 0x11100) { | 906 if (masked == 0x11100) { |
877 } else if (masked != 0x11300 && masked != 0x11000) { | 947 } else if (masked != 0x11300 && masked != 0x11000) { |
878 fatal_error("Machine freeze due to unmapped write to address %X\n", location | 0xA00000); | 948 fatal_error("Machine freeze due to unmapped write to address %X\n", location | 0xA00000); |
879 } | 949 } |
880 } | 950 } |
881 } | 951 } |
952 #ifdef REFRESH_EMULATION | |
953 //no refresh delays during IO access | |
954 refresh_counter += context->current_cycle - last_sync_cycle; | |
955 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | |
956 #endif | |
882 return context; | 957 return context; |
883 } | 958 } |
884 | 959 |
885 static m68k_context * io_write_w(uint32_t location, m68k_context * context, uint16_t value) | 960 static m68k_context * io_write_w(uint32_t location, m68k_context * context, uint16_t value) |
886 { | 961 { |
900 | 975 |
901 static uint8_t io_read(uint32_t location, m68k_context * context) | 976 static uint8_t io_read(uint32_t location, m68k_context * context) |
902 { | 977 { |
903 uint8_t value; | 978 uint8_t value; |
904 genesis_context *gen = context->system; | 979 genesis_context *gen = context->system; |
980 #ifdef REFRESH_EMULATION | |
981 //do refresh check here so we can avoid adding a penalty for a refresh that happens during an IO area access | |
982 refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle; | |
983 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); | |
984 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | |
985 last_sync_cycle = context->current_cycle - 4*MCLKS_PER_68K; | |
986 #endif | |
905 if (location < 0x10000) { | 987 if (location < 0x10000) { |
906 //Access to Z80 memory incurs a one 68K cycle wait state | 988 //Access to Z80 memory incurs a one 68K cycle wait state |
907 context->current_cycle += MCLKS_PER_68K; | 989 context->current_cycle += MCLKS_PER_68K; |
908 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) { | 990 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) { |
909 location &= 0x7FFF; | 991 location &= 0x7FFF; |
950 break; | 1032 break; |
951 case 0x7: | 1033 case 0x7: |
952 value = gen->io.ports[0].serial_out; | 1034 value = gen->io.ports[0].serial_out; |
953 break; | 1035 break; |
954 case 0x8: | 1036 case 0x8: |
955 value = gen->io.ports[0].serial_in; | 1037 value = io_rx_read(gen->io.ports, context->current_cycle); |
956 break; | 1038 break; |
957 case 0x9: | 1039 case 0x9: |
958 value = gen->io.ports[0].serial_ctrl; | 1040 value = io_sctrl_read(gen->io.ports, context->current_cycle); |
959 break; | 1041 break; |
960 case 0xA: | 1042 case 0xA: |
961 value = gen->io.ports[1].serial_out; | 1043 value = gen->io.ports[1].serial_out; |
962 break; | 1044 break; |
963 case 0xB: | 1045 case 0xB: |
964 value = gen->io.ports[1].serial_in; | 1046 value = io_rx_read(gen->io.ports + 1, context->current_cycle); |
965 break; | 1047 break; |
966 case 0xC: | 1048 case 0xC: |
967 value = gen->io.ports[1].serial_ctrl; | 1049 value = io_sctrl_read(gen->io.ports, context->current_cycle); |
968 break; | 1050 break; |
969 case 0xD: | 1051 case 0xD: |
970 value = gen->io.ports[2].serial_out; | 1052 value = gen->io.ports[2].serial_out; |
971 break; | 1053 break; |
972 case 0xE: | 1054 case 0xE: |
973 value = gen->io.ports[2].serial_in; | 1055 value = io_rx_read(gen->io.ports + 1, context->current_cycle); |
974 break; | 1056 break; |
975 case 0xF: | 1057 case 0xF: |
976 value = gen->io.ports[2].serial_ctrl; | 1058 value = io_sctrl_read(gen->io.ports, context->current_cycle); |
977 break; | 1059 break; |
978 default: | 1060 default: |
979 value = get_open_bus_value(&gen->header) >> 8; | 1061 value = get_open_bus_value(&gen->header) >> 8; |
980 } | 1062 } |
981 } else { | 1063 } else { |
995 fatal_error("Machine freeze due to read of unmapped IO location %X\n", location); | 1077 fatal_error("Machine freeze due to read of unmapped IO location %X\n", location); |
996 value = 0xFF; | 1078 value = 0xFF; |
997 } | 1079 } |
998 } | 1080 } |
999 } | 1081 } |
1082 #ifdef REFRESH_EMULATION | |
1083 //no refresh delays during IO access | |
1084 refresh_counter += context->current_cycle - last_sync_cycle; | |
1085 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | |
1086 #endif | |
1000 return value; | 1087 return value; |
1001 } | 1088 } |
1002 | 1089 |
1003 static uint16_t io_read_w(uint32_t location, m68k_context * context) | 1090 static uint16_t io_read_w(uint32_t location, m68k_context * context) |
1004 { | 1091 { |
1107 | 1194 |
1108 static uint16_t unused_read(uint32_t location, void *vcontext) | 1195 static uint16_t unused_read(uint32_t location, void *vcontext) |
1109 { | 1196 { |
1110 m68k_context *context = vcontext; | 1197 m68k_context *context = vcontext; |
1111 genesis_context *gen = context->system; | 1198 genesis_context *gen = context->system; |
1112 if ((location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { | 1199 if (location < 0x800000 || (location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { |
1113 //Only called if the cart/exp doesn't have a more specific handler for this region | 1200 //Only called if the cart/exp doesn't have a more specific handler for this region |
1114 return get_open_bus_value(&gen->header); | 1201 return get_open_bus_value(&gen->header); |
1115 } else if (location == 0xA14000 || location == 0xA14002) { | 1202 } else if (location == 0xA14000 || location == 0xA14002) { |
1116 if (gen->version_reg & 0xF) { | 1203 if (gen->version_reg & 0xF) { |
1117 return gen->tmss_lock[location >> 1 & 1]; | 1204 return gen->tmss_lock[location >> 1 & 1]; |
1140 } else { | 1227 } else { |
1141 return v >> 8; | 1228 return v >> 8; |
1142 } | 1229 } |
1143 } | 1230 } |
1144 | 1231 |
1232 static void check_tmss_lock(genesis_context *gen) | |
1233 { | |
1234 gen->vdp_unlocked = gen->tmss_lock[0] == 0x5345 && gen->tmss_lock[1] == 0x4741; | |
1235 } | |
1236 | |
1237 static void toggle_tmss_rom(genesis_context *gen) | |
1238 { | |
1239 m68k_context *context = gen->m68k; | |
1240 for (int i = 0; i < NUM_MEM_AREAS; i++) | |
1241 { | |
1242 uint16_t *tmp = context->mem_pointers[i]; | |
1243 context->mem_pointers[i] = gen->tmss_pointers[i]; | |
1244 gen->tmss_pointers[i] = tmp; | |
1245 } | |
1246 m68k_invalidate_code_range(context, 0, 0x400000); | |
1247 } | |
1248 | |
1145 static void *unused_write(uint32_t location, void *vcontext, uint16_t value) | 1249 static void *unused_write(uint32_t location, void *vcontext, uint16_t value) |
1146 { | 1250 { |
1147 m68k_context *context = vcontext; | 1251 m68k_context *context = vcontext; |
1148 genesis_context *gen = context->system; | 1252 genesis_context *gen = context->system; |
1149 uint8_t has_tmss = gen->version_reg & 0xF; | 1253 uint8_t has_tmss = gen->version_reg & 0xF; |
1150 if (has_tmss && (location == 0xA14000 || location == 0xA14002)) { | 1254 if (has_tmss && (location == 0xA14000 || location == 0xA14002)) { |
1151 gen->tmss_lock[location >> 1 & 1] = value; | 1255 gen->tmss_lock[location >> 1 & 1] = value; |
1256 check_tmss_lock(gen); | |
1152 } else if (has_tmss && location == 0xA14100) { | 1257 } else if (has_tmss && location == 0xA14100) { |
1153 //TODO: implement TMSS control register | 1258 value &= 1; |
1154 } else if (location < 0xA12000 || location >= 0xA13100 || (location >= 0xA12100 && location < 0xA13000)) { | 1259 if (gen->tmss != value) { |
1260 gen->tmss = value; | |
1261 toggle_tmss_rom(gen); | |
1262 } | |
1263 } else if (location < 0x800000 || (location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { | |
1264 //these writes are ignored when no relevant hardware is present | |
1265 } else { | |
1155 fatal_error("Machine freeze due to unmapped write to %X\n", location); | 1266 fatal_error("Machine freeze due to unmapped write to %X\n", location); |
1156 } | 1267 } |
1157 return vcontext; | 1268 return vcontext; |
1158 } | 1269 } |
1159 | 1270 |
1169 gen->tmss_lock[offset] |= value; | 1280 gen->tmss_lock[offset] |= value; |
1170 } else { | 1281 } else { |
1171 gen->tmss_lock[offset] &= 0xFF; | 1282 gen->tmss_lock[offset] &= 0xFF; |
1172 gen->tmss_lock[offset] |= value << 8; | 1283 gen->tmss_lock[offset] |= value << 8; |
1173 } | 1284 } |
1285 check_tmss_lock(gen); | |
1174 } else if (has_tmss && (location == 0xA14100 || location == 0xA14101)) { | 1286 } else if (has_tmss && (location == 0xA14100 || location == 0xA14101)) { |
1175 //TODO: implement TMSS control register | 1287 if (location & 1) { |
1176 } else if (location < 0xA12000 || location >= 0xA13100 || (location >= 0xA12100 && location < 0xA13000)) { | 1288 value &= 1; |
1289 if (gen->tmss != value) { | |
1290 gen->tmss = value; | |
1291 toggle_tmss_rom(gen); | |
1292 } | |
1293 } | |
1294 } else if (location < 0x800000 || (location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { | |
1295 //these writes are ignored when no relevant hardware is present | |
1296 } else { | |
1177 fatal_error("Machine freeze due to unmapped byte write to %X\n", location); | 1297 fatal_error("Machine freeze due to unmapped byte write to %X\n", location); |
1178 } | 1298 } |
1179 return vcontext; | 1299 return vcontext; |
1180 } | 1300 } |
1181 | 1301 |
1524 puts("Stopped VGM log"); | 1644 puts("Stopped VGM log"); |
1525 genesis_context *gen = (genesis_context *)system; | 1645 genesis_context *gen = (genesis_context *)system; |
1526 vgm_close(gen->ym->vgm); | 1646 vgm_close(gen->ym->vgm); |
1527 gen->ym->vgm = gen->psg->vgm = NULL; | 1647 gen->ym->vgm = gen->psg->vgm = NULL; |
1528 gen->header.vgm_logging = 0; | 1648 gen->header.vgm_logging = 0; |
1649 } | |
1650 | |
1651 static void *tmss_rom_write_16(uint32_t address, void *context, uint16_t value) | |
1652 { | |
1653 m68k_context *m68k = context; | |
1654 genesis_context *gen = m68k->system; | |
1655 if (gen->tmss) { | |
1656 return gen->tmss_write_16(address, context, value); | |
1657 } | |
1658 | |
1659 return context; | |
1660 } | |
1661 | |
1662 static void *tmss_rom_write_8(uint32_t address, void *context, uint8_t value) | |
1663 { | |
1664 m68k_context *m68k = context; | |
1665 genesis_context *gen = m68k->system; | |
1666 if (gen->tmss) { | |
1667 return gen->tmss_write_8(address, context, value); | |
1668 } | |
1669 | |
1670 return context; | |
1671 } | |
1672 | |
1673 static uint16_t tmss_rom_read_16(uint32_t address, void *context) | |
1674 { | |
1675 m68k_context *m68k = context; | |
1676 genesis_context *gen = m68k->system; | |
1677 if (gen->tmss) { | |
1678 return gen->tmss_read_16(address, context); | |
1679 } | |
1680 return ((uint16_t *)gen->tmss_buffer)[address >> 1]; | |
1681 } | |
1682 | |
1683 static uint8_t tmss_rom_read_8(uint32_t address, void *context) | |
1684 { | |
1685 m68k_context *m68k = context; | |
1686 genesis_context *gen = m68k->system; | |
1687 if (gen->tmss) { | |
1688 return gen->tmss_read_8(address, context); | |
1689 } | |
1690 #ifdef BLASTEM_BIG_ENDIAN | |
1691 return gen->tmss_buffer[address]; | |
1692 #else | |
1693 return gen->tmss_buffer[address ^ 1]; | |
1694 #endif | |
1695 } | |
1696 | |
1697 static void *tmss_word_write_16(uint32_t address, void *context, uint16_t value) | |
1698 { | |
1699 m68k_context *m68k = context; | |
1700 genesis_context *gen = m68k->system; | |
1701 if (gen->tmss) { | |
1702 address += gen->tmss_write_offset; | |
1703 uint16_t *dest = get_native_pointer(address, (void **)m68k->mem_pointers, &m68k->options->gen); | |
1704 *dest = value; | |
1705 m68k_handle_code_write(address, m68k); | |
1706 } | |
1707 | |
1708 return context; | |
1709 } | |
1710 | |
1711 static void *tmss_word_write_8(uint32_t address, void *context, uint8_t value) | |
1712 { | |
1713 m68k_context *m68k = context; | |
1714 genesis_context *gen = m68k->system; | |
1715 if (gen->tmss) { | |
1716 address += gen->tmss_write_offset; | |
1717 uint8_t *dest = get_native_pointer(address & ~1, (void **)m68k->mem_pointers, &m68k->options->gen); | |
1718 #ifdef BLASTEM_BIG_ENDIAN | |
1719 dest[address & 1] = value; | |
1720 #else | |
1721 dest[address & 1 ^ 1] = value; | |
1722 #endif | |
1723 m68k_handle_code_write(address & ~1, m68k); | |
1724 } | |
1725 | |
1726 return context; | |
1727 } | |
1728 | |
1729 static void *tmss_odd_write_16(uint32_t address, void *context, uint16_t value) | |
1730 { | |
1731 m68k_context *m68k = context; | |
1732 genesis_context *gen = m68k->system; | |
1733 if (gen->tmss) { | |
1734 memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); | |
1735 address >>= 1; | |
1736 uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; | |
1737 base[address] = value; | |
1738 } | |
1739 return context; | |
1740 } | |
1741 | |
1742 static void *tmss_odd_write_8(uint32_t address, void *context, uint8_t value) | |
1743 { | |
1744 m68k_context *m68k = context; | |
1745 genesis_context *gen = m68k->system; | |
1746 if (gen->tmss && (address & 1)) { | |
1747 memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); | |
1748 address >>= 1; | |
1749 uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; | |
1750 base[address] = value; | |
1751 } | |
1752 return context; | |
1753 } | |
1754 | |
1755 static void *tmss_even_write_16(uint32_t address, void *context, uint16_t value) | |
1756 { | |
1757 m68k_context *m68k = context; | |
1758 genesis_context *gen = m68k->system; | |
1759 if (gen->tmss) { | |
1760 memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); | |
1761 address >>= 1; | |
1762 uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; | |
1763 base[address] = value >> 8; | |
1764 } | |
1765 return context; | |
1766 } | |
1767 | |
1768 static void *tmss_even_write_8(uint32_t address, void *context, uint8_t value) | |
1769 { | |
1770 m68k_context *m68k = context; | |
1771 genesis_context *gen = m68k->system; | |
1772 if (gen->tmss && !(address & 1)) { | |
1773 memmap_chunk const *chunk = find_map_chunk(address + gen->tmss_write_offset, &m68k->options->gen, 0, NULL); | |
1774 address >>= 1; | |
1775 uint8_t *base = (uint8_t *)m68k->mem_pointers[chunk->ptr_index]; | |
1776 base[address] = value; | |
1777 } | |
1778 return context; | |
1529 } | 1779 } |
1530 | 1780 |
1531 genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region) | 1781 genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region) |
1532 { | 1782 { |
1533 static memmap_chunk z80_map[] = { | 1783 static memmap_chunk z80_map[] = { |
1567 set_region(gen, rom, force_region); | 1817 set_region(gen, rom, force_region); |
1568 tern_node *model = get_model(config, SYSTEM_GENESIS); | 1818 tern_node *model = get_model(config, SYSTEM_GENESIS); |
1569 uint8_t tmss = !strcmp(tern_find_ptr_default(model, "tmss", "off"), "on"); | 1819 uint8_t tmss = !strcmp(tern_find_ptr_default(model, "tmss", "off"), "on"); |
1570 if (tmss) { | 1820 if (tmss) { |
1571 gen->version_reg |= 1; | 1821 gen->version_reg |= 1; |
1822 } else { | |
1823 gen->vdp_unlocked = 1; | |
1572 } | 1824 } |
1573 | 1825 |
1574 uint8_t max_vsram = !strcmp(tern_find_ptr_default(model, "vsram", "40"), "64"); | 1826 uint8_t max_vsram = !strcmp(tern_find_ptr_default(model, "vsram", "40"), "64"); |
1575 gen->vdp = init_vdp_context(gen->version_reg & 0x40, max_vsram); | 1827 gen->vdp = init_vdp_context(gen->version_reg & 0x40, max_vsram); |
1576 gen->vdp->system = &gen->header; | 1828 gen->vdp->system = &gen->header; |
1662 } | 1914 } |
1663 } else { | 1915 } else { |
1664 gen->save_storage = NULL; | 1916 gen->save_storage = NULL; |
1665 } | 1917 } |
1666 | 1918 |
1919 gen->mapper_start_index = rom->mapper_start_index; | |
1920 | |
1667 //This must happen before we generate memory access functions in init_m68k_opts | 1921 //This must happen before we generate memory access functions in init_m68k_opts |
1922 uint8_t next_ptr_index = 0; | |
1923 uint32_t tmss_min_alloc = 16 * 1024; | |
1668 for (int i = 0; i < rom->map_chunks; i++) | 1924 for (int i = 0; i < rom->map_chunks; i++) |
1669 { | 1925 { |
1670 if (rom->map[i].start == 0xE00000) { | 1926 if (rom->map[i].start == 0xE00000) { |
1671 rom->map[i].buffer = gen->work_ram; | 1927 rom->map[i].buffer = gen->work_ram; |
1672 break; | 1928 if (!tmss) { |
1673 } | 1929 break; |
1930 } | |
1931 } | |
1932 if (rom->map[i].flags & MMAP_PTR_IDX && rom->map[i].ptr_index >= next_ptr_index) { | |
1933 next_ptr_index = rom->map[i].ptr_index + 1; | |
1934 } | |
1935 if (rom->map[i].start < 0x400000 && rom->map[i].read_16 != unused_read) { | |
1936 uint32_t highest_offset = (rom->map[i].end & rom->map[i].mask) + 1; | |
1937 if (highest_offset > tmss_min_alloc) { | |
1938 tmss_min_alloc = highest_offset; | |
1939 } | |
1940 } | |
1941 } | |
1942 if (tmss) { | |
1943 char *tmss_path = tern_find_path_default(config, "system\0tmss_path\0", (tern_val){.ptrval = "tmss.md"}, TVAL_PTR).ptrval; | |
1944 uint8_t *buffer = malloc(tmss_min_alloc); | |
1945 uint32_t tmss_size; | |
1946 if (is_absolute_path(tmss_path)) { | |
1947 FILE *f = fopen(tmss_path, "rb"); | |
1948 if (!f) { | |
1949 fatal_error("Configured to use a model with TMSS, but failed to load the TMSS ROM from %s\n", tmss_path); | |
1950 } | |
1951 tmss_size = fread(buffer, 1, tmss_min_alloc, f); | |
1952 fclose(f); | |
1953 } else { | |
1954 char *tmp = read_bundled_file(tmss_path, &tmss_size); | |
1955 if (!tmp) { | |
1956 fatal_error("Configured to use a model with TMSS, but failed to load the TMSS ROM from %s\n", tmss_path); | |
1957 } | |
1958 memcpy(buffer, tmp, tmss_size); | |
1959 free(tmp); | |
1960 } | |
1961 for (uint32_t padded = nearest_pow2(tmss_size); tmss_size < padded; tmss_size++) | |
1962 { | |
1963 buffer[tmss_size] = 0xFF; | |
1964 } | |
1965 #ifndef BLASTEM_BIG_ENDIAN | |
1966 byteswap_rom(tmss_size, (uint16_t *)buffer); | |
1967 #endif | |
1968 //mirror TMSS ROM until we fill up to tmss_min_alloc | |
1969 for (uint32_t dst = tmss_size; dst < tmss_min_alloc; dst += tmss_size) | |
1970 { | |
1971 memcpy(buffer + dst, buffer, dst + tmss_size > tmss_min_alloc ? tmss_min_alloc - dst : tmss_size); | |
1972 } | |
1973 //modify mappings for ROM space to point to the TMSS ROM and fixup flags to allow switching back and forth | |
1974 //WARNING: This code makes some pretty big assumptions about the kinds of map chunks it will encounter | |
1975 for (int i = 0; i < rom->map_chunks; i++) | |
1976 { | |
1977 if (rom->map[i].start < 0x400000 && rom->map[i].read_16 != unused_read) { | |
1978 if (rom->map[i].flags == MMAP_READ) { | |
1979 //Normal ROM | |
1980 rom->map[i].flags |= MMAP_PTR_IDX | MMAP_CODE; | |
1981 rom->map[i].ptr_index = next_ptr_index++; | |
1982 if (rom->map[i].ptr_index >= NUM_MEM_AREAS) { | |
1983 fatal_error("Too many memmap chunks with MMAP_PTR_IDX after TMSS remap\n"); | |
1984 } | |
1985 gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; | |
1986 rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); | |
1987 } else if (rom->map[i].flags & MMAP_PTR_IDX) { | |
1988 //Sega mapper page or multi-game mapper | |
1989 gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; | |
1990 rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); | |
1991 if (rom->map[i].write_16) { | |
1992 if (!gen->tmss_write_16) { | |
1993 gen->tmss_write_16 = rom->map[i].write_16; | |
1994 gen->tmss_write_8 = rom->map[i].write_8; | |
1995 rom->map[i].write_16 = tmss_rom_write_16; | |
1996 rom->map[i].write_8 = tmss_rom_write_8; | |
1997 } else if (gen->tmss_write_16 == rom->map[i].write_16) { | |
1998 rom->map[i].write_16 = tmss_rom_write_16; | |
1999 rom->map[i].write_8 = tmss_rom_write_8; | |
2000 } else { | |
2001 warning("Chunk starting at %X has a write function, but we've already stored a different one for TMSS remap\n", rom->map[i].start); | |
2002 } | |
2003 } | |
2004 } else if ((rom->map[i].flags & (MMAP_READ | MMAP_WRITE)) == (MMAP_READ | MMAP_WRITE)) { | |
2005 //RAM or SRAM | |
2006 rom->map[i].flags |= MMAP_PTR_IDX; | |
2007 rom->map[i].ptr_index = next_ptr_index++; | |
2008 gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; | |
2009 rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); | |
2010 if (!gen->tmss_write_offset || gen->tmss_write_offset == rom->map[i].start) { | |
2011 gen->tmss_write_offset = rom->map[i].start; | |
2012 rom->map[i].flags &= ~MMAP_WRITE; | |
2013 if (rom->map[i].flags & MMAP_ONLY_ODD) { | |
2014 rom->map[i].write_16 = tmss_odd_write_16; | |
2015 rom->map[i].write_8 = tmss_odd_write_8; | |
2016 } else if (rom->map[i].flags & MMAP_ONLY_EVEN) { | |
2017 rom->map[i].write_16 = tmss_even_write_16; | |
2018 rom->map[i].write_8 = tmss_even_write_8; | |
2019 } else { | |
2020 rom->map[i].write_16 = tmss_word_write_16; | |
2021 rom->map[i].write_8 = tmss_word_write_8; | |
2022 } | |
2023 } else { | |
2024 warning("Could not remap writes for chunk starting at %X for TMSS because write_offset is %X\n", rom->map[i].start, gen->tmss_write_offset); | |
2025 } | |
2026 } else if (rom->map[i].flags & MMAP_READ_CODE) { | |
2027 //NOR flash | |
2028 rom->map[i].flags |= MMAP_PTR_IDX; | |
2029 rom->map[i].ptr_index = next_ptr_index++; | |
2030 if (rom->map[i].ptr_index >= NUM_MEM_AREAS) { | |
2031 fatal_error("Too many memmap chunks with MMAP_PTR_IDX after TMSS remap\n"); | |
2032 } | |
2033 gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; | |
2034 rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); | |
2035 if (!gen->tmss_write_16) { | |
2036 gen->tmss_write_16 = rom->map[i].write_16; | |
2037 gen->tmss_write_8 = rom->map[i].write_8; | |
2038 gen->tmss_read_16 = rom->map[i].read_16; | |
2039 gen->tmss_read_8 = rom->map[i].read_8; | |
2040 rom->map[i].write_16 = tmss_rom_write_16; | |
2041 rom->map[i].write_8 = tmss_rom_write_8; | |
2042 rom->map[i].read_16 = tmss_rom_read_16; | |
2043 rom->map[i].read_8 = tmss_rom_read_8; | |
2044 } else if (gen->tmss_write_16 == rom->map[i].write_16) { | |
2045 rom->map[i].write_16 = tmss_rom_write_16; | |
2046 rom->map[i].write_8 = tmss_rom_write_8; | |
2047 rom->map[i].read_16 = tmss_rom_read_16; | |
2048 rom->map[i].read_8 = tmss_rom_read_8; | |
2049 } else { | |
2050 warning("Chunk starting at %X has a write function, but we've already stored a different one for TMSS remap\n", rom->map[i].start); | |
2051 } | |
2052 } else { | |
2053 warning("Didn't remap chunk starting at %X for TMSS because it has flags %X\n", rom->map[i].start, rom->map[i].flags); | |
2054 } | |
2055 } | |
2056 } | |
2057 gen->tmss_buffer = buffer; | |
1674 } | 2058 } |
1675 | 2059 |
1676 m68k_options *opts = malloc(sizeof(m68k_options)); | 2060 m68k_options *opts = malloc(sizeof(m68k_options)); |
1677 init_m68k_opts(opts, rom->map, rom->map_chunks, MCLKS_PER_68K); | 2061 init_m68k_opts(opts, rom->map, rom->map_chunks, MCLKS_PER_68K); |
1678 if (!strcmp(tern_find_ptr_default(model, "tas", "broken"), "broken")) { | 2062 if (!strcmp(tern_find_ptr_default(model, "tas", "broken"), "broken")) { |