Mercurial > repos > blastem
comparison genesis.c @ 2037:b0b0c31338c3
Implement TMSS VDP lock
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 07 Mar 2021 22:44:33 -0800 |
parents | 8b2ef428d1aa |
children | 3b8e29ef1145 |
comparison
equal
deleted
inserted
replaced
2036:45c4b74e7676 | 2037:b0b0c31338c3 |
---|---|
517 static m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) | 517 static m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) |
518 { | 518 { |
519 if (vdp_port & 0x2700E0) { | 519 if (vdp_port & 0x2700E0) { |
520 fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port); | 520 fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port); |
521 } | 521 } |
522 genesis_context * gen = context->system; | |
523 if (!gen->vdp_unlocked) { | |
524 fatal_error("machine freeze due to VDP write to %X without TMSS unlock\n", 0xC00000 | vdp_port); | |
525 } | |
522 vdp_port &= 0x1F; | 526 vdp_port &= 0x1F; |
523 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); | 527 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); |
524 #ifdef REFRESH_EMULATION | 528 #ifdef REFRESH_EMULATION |
525 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access | 529 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access |
526 refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle; | 530 refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle; |
527 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); | 531 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); |
528 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | 532 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); |
529 last_sync_cycle = context->current_cycle; | 533 last_sync_cycle = context->current_cycle; |
530 #endif | 534 #endif |
531 sync_components(context, 0); | 535 sync_components(context, 0); |
532 genesis_context * gen = context->system; | |
533 vdp_context *v_context = gen->vdp; | 536 vdp_context *v_context = gen->vdp; |
534 uint32_t before_cycle = v_context->cycles; | 537 uint32_t before_cycle = v_context->cycles; |
535 if (vdp_port < 0x10) { | 538 if (vdp_port < 0x10) { |
536 int blocked; | 539 int blocked; |
537 if (vdp_port < 4) { | 540 if (vdp_port < 4) { |
656 static uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) | 659 static uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) |
657 { | 660 { |
658 if (vdp_port & 0x2700E0) { | 661 if (vdp_port & 0x2700E0) { |
659 fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port); | 662 fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port); |
660 } | 663 } |
664 genesis_context *gen = context->system; | |
665 if (!gen->vdp_unlocked) { | |
666 fatal_error("machine freeze due to VDP read from %X without TMSS unlock\n", 0xC00000 | vdp_port); | |
667 } | |
661 vdp_port &= 0x1F; | 668 vdp_port &= 0x1F; |
662 uint16_t value; | 669 uint16_t value; |
663 #ifdef REFRESH_EMULATION | 670 #ifdef REFRESH_EMULATION |
664 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access | 671 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access |
665 refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle; | 672 refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle; |
666 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); | 673 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); |
667 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | 674 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); |
668 last_sync_cycle = context->current_cycle; | 675 last_sync_cycle = context->current_cycle; |
669 #endif | 676 #endif |
670 sync_components(context, 0); | 677 sync_components(context, 0); |
671 genesis_context *gen = context->system; | |
672 vdp_context * v_context = gen->vdp; | 678 vdp_context * v_context = gen->vdp; |
673 uint32_t before_cycle = v_context->cycles; | 679 uint32_t before_cycle = v_context->cycles; |
674 if (vdp_port < 0x10) { | 680 if (vdp_port < 0x10) { |
675 if (vdp_port < 4) { | 681 if (vdp_port < 4) { |
676 value = vdp_data_port_read(v_context); | 682 value = vdp_data_port_read(v_context); |
1166 } else { | 1172 } else { |
1167 return v >> 8; | 1173 return v >> 8; |
1168 } | 1174 } |
1169 } | 1175 } |
1170 | 1176 |
1177 static void check_tmss_lock(genesis_context *gen) | |
1178 { | |
1179 gen->vdp_unlocked = gen->tmss_lock[0] == 'SE' && gen->tmss_lock[1] == 'GA'; | |
1180 } | |
1181 | |
1171 static void *unused_write(uint32_t location, void *vcontext, uint16_t value) | 1182 static void *unused_write(uint32_t location, void *vcontext, uint16_t value) |
1172 { | 1183 { |
1173 m68k_context *context = vcontext; | 1184 m68k_context *context = vcontext; |
1174 genesis_context *gen = context->system; | 1185 genesis_context *gen = context->system; |
1175 uint8_t has_tmss = gen->version_reg & 0xF; | 1186 uint8_t has_tmss = gen->version_reg & 0xF; |
1176 if (has_tmss && (location == 0xA14000 || location == 0xA14002)) { | 1187 if (has_tmss && (location == 0xA14000 || location == 0xA14002)) { |
1177 gen->tmss_lock[location >> 1 & 1] = value; | 1188 gen->tmss_lock[location >> 1 & 1] = value; |
1189 check_tmss_lock(gen); | |
1178 } else if (has_tmss && location == 0xA14100) { | 1190 } else if (has_tmss && location == 0xA14100) { |
1179 value &= 1; | 1191 value &= 1; |
1180 if (gen->tmss != value) { | 1192 if (gen->tmss != value) { |
1181 gen->tmss = value; | 1193 gen->tmss = value; |
1182 for (int i = 0; i < NUM_MEM_AREAS; i++) | 1194 for (int i = 0; i < NUM_MEM_AREAS; i++) |
1207 gen->tmss_lock[offset] |= value; | 1219 gen->tmss_lock[offset] |= value; |
1208 } else { | 1220 } else { |
1209 gen->tmss_lock[offset] &= 0xFF; | 1221 gen->tmss_lock[offset] &= 0xFF; |
1210 gen->tmss_lock[offset] |= value << 8; | 1222 gen->tmss_lock[offset] |= value << 8; |
1211 } | 1223 } |
1224 check_tmss_lock(gen); | |
1212 } else if (has_tmss && (location == 0xA14100 || location == 0xA14101)) { | 1225 } else if (has_tmss && (location == 0xA14100 || location == 0xA14101)) { |
1213 if (location & 1) { | 1226 if (location & 1) { |
1214 value &= 1; | 1227 value &= 1; |
1215 if (gen->tmss != value) { | 1228 if (gen->tmss != value) { |
1216 gen->tmss = value; | 1229 gen->tmss = value; |
1735 set_region(gen, rom, force_region); | 1748 set_region(gen, rom, force_region); |
1736 tern_node *model = get_model(config, SYSTEM_GENESIS); | 1749 tern_node *model = get_model(config, SYSTEM_GENESIS); |
1737 uint8_t tmss = !strcmp(tern_find_ptr_default(model, "tmss", "off"), "on"); | 1750 uint8_t tmss = !strcmp(tern_find_ptr_default(model, "tmss", "off"), "on"); |
1738 if (tmss) { | 1751 if (tmss) { |
1739 gen->version_reg |= 1; | 1752 gen->version_reg |= 1; |
1753 } else { | |
1754 gen->vdp_unlocked = 1; | |
1740 } | 1755 } |
1741 | 1756 |
1742 uint8_t max_vsram = !strcmp(tern_find_ptr_default(model, "vsram", "40"), "64"); | 1757 uint8_t max_vsram = !strcmp(tern_find_ptr_default(model, "vsram", "40"), "64"); |
1743 gen->vdp = init_vdp_context(gen->version_reg & 0x40, max_vsram); | 1758 gen->vdp = init_vdp_context(gen->version_reg & 0x40, max_vsram); |
1744 gen->vdp->system = &gen->header; | 1759 gen->vdp->system = &gen->header; |