Skip to content

Commit 40f2792

Browse files
committed
MEGA65: MAP opcode behaviour change #427
As it turned out mega65-core modified the exact behaviour of the MAP opcode in hypervisor mode back in 2022 with this commit: MEGA65/mega65-core@34a930b See mega65-core issue: MEGA65/mega65-core#635 Though Xemu still used the old behaviour which can be problematic. So this is the intended fix to handle the problem. Thanks @gurcei to discover / report this anomaly.
1 parent 3317a40 commit 40f2792

File tree

2 files changed

+27
-17
lines changed

2 files changed

+27
-17
lines changed

targets/mega65/hypervisor.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,18 @@ void hypervisor_enter ( int trapno )
164164
//D6XX_registers[0x53] = 0; // GS $D653 - Hypervisor DMAgic source MB - *UNUSED*
165165
//D6XX_registers[0x54] = 0; // GS $D654 - Hypervisor DMAgic destination MB - *UNUSED*
166166
dma_get_list_addr_as_bytes(D6XX_registers + 0x55); // GS $D655-$D658 - Hypervisor DMAGic list address bits 27-0
167+
if (map_megabyte_low == 0xFF00000) { // !! map_megabyte_low uses << 20 ...
168+
// According to the VHDL: Make sure that a naughty person can't trick the hypervisor into modifying
169+
// itself, by having the Hypervisor address space mapped in the bottom 32KB of address space.
170+
map_megabyte_low = 0;
171+
DEBUGPRINT("HYPERVISOR: warning, low-MB would be mapped to $FF, countermeasure initiaited" NL);
172+
}
167173
// Now entering into hypervisor mode: we use memory_reconfigure() to set all the stuff needed + setting up "in_hypervisor" value as well
168174
memory_reconfigure(
169175
0, // D030 ROM banking turning off
170176
VIC4_IOMODE, // VIC4 I/O mode to be used (on MEGA65, in hypervisor mode it's always the case! the handler in vic4.c ensures, we cannot even modify this)
171177
0x3F, 0x35, // set CPU I/O port DDR+DATA: all-RAM + I/O config
172-
map_megabyte_low, map_offset_low, // low mapping is left as-is
178+
map_megabyte_low, map_offset_low, // low mapping is left as-is (however for map_megabyte_low, see the "if" above)
173179
0xFFU << 20, 0xF0000U, // high mapping though is being modified
174180
(map_mask & 0xFU) | 0x30U, // mapping: 0011XXXX (it seems low region map mask is not changed by hypervisor entry)
175181
true // this will sets in_hypervisor to TRUE!!!!

targets/mega65/memory_mapper.c

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* A work-in-progess MEGA65 (Commodore 65 clone origins) emulator
22
Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
3-
Copyright (C)2017-2024 LGB (Gábor Lénárt) <[email protected]>
3+
Copyright (C)2017-2025 LGB (Gábor Lénárt) <[email protected]>
44
55
This program is free software; you can redistribute it and/or modify
66
it under the terms of the GNU General Public License as published by
@@ -343,7 +343,7 @@ static const struct mem_map_st *mem_map_hints[MEM_HINT_SLOTS];
343343
// * Every areas (other than the first) must start on address which is the previous one's last one PLUS 1
344344
// * The first entry must start at address 0
345345
// * The last entry must be $10000000 - $FFFFFFFF with type MEM_SLOT_TYPE_IMPOSSIBLE as a safe-guard
346-
static struct mem_map_st mem_map[] = {
346+
static const struct mem_map_st mem_map[] = {
347347
{ 0x00000000U, 0x0001F7FFU, MEM_SLOT_TYPE_MAIN_RAM }, // OLD memory model used 0-FF as "ZP" to handle CPU I/O port. But now it's VIRTUAL and only exists in CPU's view not in mem-map!
348348
{ 0x0001F800U, 0x0001FFFFU, MEM_SLOT_TYPE_SHARED_RAM }, // "shared" area, 2K of coulour RAM [C65 legacy], b/c of performance, we must distribute between both of normal and colour RAM
349349
{ 0x00020000U, 0x0003FFFFU, MEM_SLOT_TYPE_ROM }, // though it's called ROM, it can be normal RAM, if "ROM write protection" is off
@@ -800,24 +800,28 @@ void cpu65_do_aug_callback ( void )
800800
| MAP | MAP | MAP | MAP | UPPER | UPPER | UPPER | UPPER | Z
801801
| BLK7 | BLK6 | BLK5 | BLK4 | OFF19 | OFF18 | OFF17 | OFF16 |
802802
+-------+-------+-------+-------+-------+-------+-------+-------+
803-
-- C65GS extension: Set the MegaByte register for low and high mobies
804-
-- so that we can address all 256MB of RAM.
805-
if reg_x = x"0f" then
806-
reg_mb_low <= reg_a;
807-
end if;
808-
if reg_z = x"0f" then
809-
reg_mb_high <= reg_y;
810-
end if; */
803+
*/
811804
cpu65.cpu_inhibit_interrupts = 1; // disable interrupts till the next "EOM" (ie: NOP) opcode
812805
DEBUG("CPU: MAP opcode, input A=$%02X X=$%02X Y=$%02X Z=$%02X" NL, cpu65.a, cpu65.x, cpu65.y, cpu65.z);
813-
map_offset_low = (cpu65.a << 8) | ((cpu65.x & 15) << 16); // offset of lower half (blocks 0-3)
814-
map_offset_high = (cpu65.y << 8) | ((cpu65.z & 15) << 16); // offset of higher half (blocks 4-7)
815-
map_mask = (cpu65.z & 0xF0) | ( cpu65.x >> 4); // "is mapped" mask for blocks (1 bit for each)
816-
// M65 specific "MB" (megabyte) selector "mode":
817-
if (cpu65.x == 0x0F)
806+
if (cpu65.x == 0x0F) {
818807
map_megabyte_low = (int)cpu65.a << 20;
819-
if (cpu65.z == 0x0F)
808+
} else {
809+
map_offset_low = (cpu65.a << 8) | ((cpu65.x & 15) << 16); // offset of lower half (blocks 0-3)
810+
map_mask = (map_mask & 0xF0) | (cpu65.x >> 4); // "is mapped" mask for the lower half
811+
}
812+
if (cpu65.z == 0x0F) {
820813
map_megabyte_high = (int)cpu65.y << 20;
814+
if (in_hypervisor) {
815+
DEBUG("MEM: warning, altering MB selection for upper 32K memory mapping in hypervisor mode at PC=$%04X" NL, cpu65.pc);
816+
}
817+
} else {
818+
if (!in_hypervisor) {
819+
map_offset_high = (cpu65.y << 8) | ((cpu65.z & 15) << 16); // offset of higher half (blocks 4-7)
820+
map_mask = (map_mask & 0x0F) | (cpu65.z & 0xF0); // "is mapped" mask for the upper half
821+
} else {
822+
DEBUG("MEM: avoiding to alter upper 32K memory mapping in hypervisor mode at PC=$%04X" NL, cpu65.pc);
823+
}
824+
}
821825
DEBUG("MEM: applying new memory configuration because of MAP CPU opcode" NL);
822826
DEBUG("LOW -OFFSET = $%03X, MB = $%02X" NL, map_offset_low , map_megabyte_low >> 20);
823827
DEBUG("HIGH-OFFSET = $%03X, MB = $%02X" NL, map_offset_high, map_megabyte_high >> 20);

0 commit comments

Comments
 (0)