Skip to content

Commit

Permalink
MEGA65: "read of unwritten memory" debug mode #405
Browse files Browse the repository at this point in the history
Rhialto had the feature request to have a mode, where Xemu/MEGA65 can warn you
on reading memory which was not written before, can be useful to find ROM bugs.

In this current form, it's quite minimal and simple:

1. Only works on the first 126K of physical RAM
2. Only works from command line, start emulation with paramter: -ramcheckread
3. You need to watch the output of the emulator, so on UNIX-like/Linux/Mac systems,
   emulator should be started from terminal window, on Windows, Xemu
   console must be open (start also with parameter: -syscon)
4. Check the output of the emulator, you can find lines like:
   MEM: DEBUG: main RAM at linear address $101A0 has been read without prior write; PC=$8613 [$20613]
   The PC value can be off by some bytes, because it may have been
   incremented already during opcode emulation. The [...] is the linear
   address for the mentioned CPU PC value.

Well, that's it.
  • Loading branch information
lgblgblgb committed Aug 6, 2024
1 parent 74e13c8 commit bd47ac9
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 1 deletion.
3 changes: 2 additions & 1 deletion targets/mega65/configdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ static const struct xemutools_configdef_switch_st switch_options[] = {
{ "fastboot", "Try to use sleepless emulation mode during booting", &configdb.fastboot },
{ "matrixstart", "Start with matrix-mode activated", &configdb.matrixstart },
{ "matrixdisable", "Disable the matrix hotkey", &configdb.matrixdisable },
{ "ramcheckread", "Enabled warnings on reading unwritten memory (first 126K only)", &configdb.ramcheckread },
{ NULL }
};

Expand Down Expand Up @@ -152,7 +153,7 @@ static const void *do_not_save_opts[] = {
&configdb.matrixstart,
&configdb.dumpmem, &configdb.dumpscreen, &configdb.screenshot_and_exit,
&configdb.testing, &configdb.hyperdebug, &configdb.hyperdebugfreezer, &configdb.usestubrom, &configdb.useinitrom, &configdb.useutilmenu,
&configdb.cartbin8000, &configdb.winpos,
&configdb.cartbin8000, &configdb.winpos, &configdb.ramcheckread,
NULL
};

Expand Down
1 change: 1 addition & 0 deletions targets/mega65/configdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ struct configdb_st {
int matrixstart;
int matrixdisable;
char *winpos;
int ramcheckread;
};

extern struct configdb_st configdb;
Expand Down
2 changes: 2 additions & 0 deletions targets/mega65/hypervisor.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ void hypervisor_start_machine ( void )
extract_version_string(hyppo_version_string, sizeof hyppo_version_string);
DEBUGPRINT("HYPERVISOR: HYPPO version \"%s\" (%s) starting with TRAP reset (#$%02X)" NL, hyppo_version_string, hickup_is_overriden ? "OVERRIDEN" : "built-in", TRAP_RESET);
hypervisor_enter(TRAP_RESET);
memory_reset_unwritten_debug_stat();
}


Expand Down Expand Up @@ -299,6 +300,7 @@ static inline void first_leave ( void )
hdos_notify_system_start_end();
xemu_sleepless_temporary_mode(0); // turn off temporary sleepless mode which may have been enabled before
vic_frame_counter_since_boot = 0;
//memory_reset_unwritten_debug_stat(); // FIXME/TODO: commented out since it generates a **tons** of warnings then with the "unwritten mem read" debug mode (-ramcheckread emu option)
DEBUGPRINT("HYPERVISOR: first return after RESET, end of processing workarounds." NL);
}

Expand Down
58 changes: 58 additions & 0 deletions targets/mega65/memory_mapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */

// 512K is the max "main" RAM. Currently only 384K is used by M65. We want to make sure, the _total_ size is power of 2, so we can protect accesses with simple bit masks as a last-resort-protection
Uint8 main_ram[512 << 10];
static Uint8 main_ram_written[0x1F800U];
// 32K of colour RAM. VIC-IV can see this as for colour information only. The first 2K can be seen at the last 2K of
// the chip-RAM. Also, the first 1 or 2K can be seen in the C64-style I/O area too, at $D800
Uint8 colour_ram[0x8000];
Expand Down Expand Up @@ -162,12 +163,38 @@ static Uint32 policy4k[0x10]; // memory policy with MAP taken account (the real
static Uint8 zero_page_reader ( const Uint32 addr32 );
static void zero_page_writer ( const Uint32 addr32, const Uint8 data );


static void checked_reader_warning ( const Uint32 addr32 )
{
DEBUGPRINT("MEM: DEBUG: main RAM at linear address $%X has been read without prior write; PC=$%04X [$%X]" NL, addr32, cpu65.pc, memory_cpu_addr_to_linear(cpu65.pc, NULL));
}


static Uint8 zero_page_checked_reader ( const Uint32 addr32 ) {
if (!main_ram_written[addr32])
checked_reader_warning(addr32);
return zero_page_reader(addr32);
}
static void zero_page_checked_writer ( const Uint32 addr32, const Uint8 data ) {
main_ram_written[addr32] = 1;
zero_page_writer(addr32, data);
}

static Uint8 main_ram_reader ( const Uint32 addr32 ) {
return main_ram[addr32];
}
static void main_ram_writer ( const Uint32 addr32, const Uint8 data ) {
main_ram[addr32] = data;
}
static Uint8 main_ram_checked_reader ( const Uint32 addr32 ) {
if (!main_ram_written[addr32])
checked_reader_warning(addr32);
return main_ram[addr32];
}
static void main_ram_checked_writer ( const Uint32 addr32, const Uint8 data ) {
main_ram_written[addr32] = 1;
main_ram[addr32] = data;
}
static void shared_main_ram_writer ( const Uint32 addr32, const Uint8 data ) {
main_ram[addr32] = data;
colour_ram[addr32 - 0x1F800U] = data;
Expand Down Expand Up @@ -348,6 +375,30 @@ static struct mem_map_st mem_map[] = {

static XEMU_INLINE void slot_assignment_postprocessing ( const Uint32 slot )
{
if (XEMU_UNLIKELY(configdb.ramcheckread && mem_slot_rd_addr32[slot] < 0x1F800U)) {
if (mem_slot_rd_func[slot] == main_ram_reader) {
#ifdef MEM_USE_DATA_POINTERS
mem_slot_rd_data[slot] = NULL;
#endif
mem_slot_rd_func[slot] = main_ram_checked_reader;
} else if (mem_slot_rd_func[slot] == zero_page_reader) {
#ifdef MEM_USE_DATA_POINTERS
mem_slot_rd_data[slot] = NULL;
#endif
mem_slot_rd_func[slot] = zero_page_checked_reader;
}
if (mem_slot_wr_func[slot] == main_ram_writer) {
#ifdef MEM_USE_DATA_POINTERS
mem_slot_wr_data[slot] = NULL;
#endif
mem_slot_wr_func[slot] = main_ram_checked_writer;
} else if (mem_slot_wr_func[slot] == zero_page_writer) {
#ifdef MEM_USE_DATA_POINTERS
mem_slot_wr_data[slot] = NULL;
#endif
mem_slot_wr_func[slot] = zero_page_checked_writer;
}
}
mem_slot_rd_func_real[slot] = mem_slot_rd_func[slot];
mem_slot_wr_func_real[slot] = mem_slot_wr_func[slot];
#ifdef MEM_WATCH_SUPPORT
Expand Down Expand Up @@ -934,6 +985,7 @@ void memory_init (void )
// Initiailize memory content with something ...
// NOTE: make sure the first 2K of colour_ram is the **SAME** as the 2K part of main_ram at offset $1F800
memset(main_ram, 0x00, sizeof main_ram);
memory_reset_unwritten_debug_stat();
memset(colour_ram, 0x00, sizeof colour_ram);
memset(attic_ram, 0xFF, sizeof attic_ram);
DEBUGPRINT("MEM: memory decoder initialized, %uK fast, %uK attic, %uK colour, %uK font RAM" NL,
Expand All @@ -945,6 +997,12 @@ void memory_init (void )
}


void memory_reset_unwritten_debug_stat ( void )
{
memset(main_ram_written, 0x00, sizeof main_ram_written);
}


// Warning: this overwrites ref_slot!
static XEMU_INLINE Uint32 cpu_get_flat_addressing_mode_address ( const Uint8 index )
{
Expand Down
1 change: 1 addition & 0 deletions targets/mega65/memory_mapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define XEMU_MEGA65_MEMORY_MAPPER_H_INCLUDED

extern void memory_init ( void );
extern void memory_reset_unwritten_debug_stat ( void );
extern void memory_set_rom_protection ( const bool protect );
extern void memory_reconfigure (
const Uint8 d030_value, const Uint8 new_io_mode, const Uint8 new_cpu_port0, const Uint8 new_cpu_port1,
Expand Down

0 comments on commit bd47ac9

Please sign in to comment.