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;