31 #define XEMU_MEGA65_HDOS_H_ALLOWED
34 #include <sys/types.h>
45 static int resolver_ok = 0;
47 static char hypervisor_monout[0x10000];
48 static char *hypervisor_monout_p = hypervisor_monout;
50 static int hypervisor_serial_out_asciizer;
52 static int hypervisor_is_first_call;
53 static int execution_range_check_gate;
54 static int trap_current;
55 static int current_hdos_func = -1;
57 static int hypervisor_queued_trap = -1;
59 static char *debug_file_storage = NULL;
77 DEBUG(
"HYPERVISOR: no need to queue trap, can be executed now #$%02X" NL, trapno);
80 }
else if (hypervisor_queued_trap < 0) {
81 hypervisor_queued_trap = trapno;
82 DEBUG(
"HYPERVISOR: queueing trap #$%02X" NL, trapno);
85 DEBUGPRINT(
"HYPERVISOR: cannot queue trap #$%02X, already have a queued one #$%02X" NL, trapno, hypervisor_queued_trap);
98 static int do_warn = 1;
100 WARNING_WINDOW(
"DMA operation would trigger hypervisor trap.\nThis is totally ignored!\nThere will be no future warning before you restart Xemu");
105 static int do_nop_check = 1;
110 if (
XEMU_UNLIKELY(skipped_byte != 0xEA && skipped_byte != 0xB8)) {
112 snprintf(msg,
sizeof msg,
113 "Writing hypervisor trap $%02X must be followed by NOP/CLV\n"
114 "but found opcode $%02X at PC=$%04X\n\n"
115 "This will cause problems on a real MEGA65!"
117 0xD640 + trapno, skipped_byte, cpu65.pc
120 "Ignore now|Ignore all",
124 INFO_WINDOW(
"There will be no further warnings on this issue\nuntil you restart Xemu");
134 trap_current = trapno;
137 FATAL(
"FATAL: got invalid trap number %d", trapno);
139 FATAL(
"FATAL: already in hypervisor mode while calling hypervisor_enter()");
183 cpu65.pc = 0x8000 | (trapno << 2);
184 DEBUG(
"HYPERVISOR: entering into hypervisor mode, trap=$%02X (A=$%02X) @ $%04X -> $%04X" NL, trapno, cpu65.a,
D6XX_registers[0x48] | (
D6XX_registers[0x49] << 8), cpu65.pc);
186 current_hdos_func = cpu65.a & 0x7E;
189 current_hdos_func = -1;
194 DEBUGPRINT(
"HYPERVISOR: setting video standard change banning" NL);
221 static void extract_version_string (
char *target,
int target_max_size )
223 static const char marker[] =
"GIT: ";
228 if (a == 0x4000 - 0x10) {
229 strcpy(target,
"???");
240 if (l >= target_max_size)
241 l = target_max_size - 1;
250 static int init_done = 0;
257 hypervisor_queued_trap = -1;
258 hypervisor_is_first_call = 1;
259 execution_range_check_gate = 0;
266 static inline void first_leave (
void )
268 DEBUGPRINT(
"HYPERVISOR: first return after RESET, start of processing workarounds." NL);
269 execution_range_check_gate = 1;
275 DEBUGPRINT(
"ROM: force ROM re-apply policy, PC change: $%04X -> $%04X" NL, cpu65.pc, new_pc);
277 WARNING_WINDOW(
"ROM override has a suspect reset address! ($%04X)", new_pc);
283 DEBUGPRINT(
"ROM: no custom force-ROM policy, PC remains at $%04X" NL, cpu65.pc);
296 DEBUGPRINT(
"HYPERVISOR: first return after RESET, end of processing workarounds." NL);
303 DEBUGPRINT(
"HYPERVISOR: hypervisor-only reset was requested by Xemu." NL);
308 DEBUGPRINT(
"HYPERVISOR: hypervisor-only reset requested by Xemu **FAILED**: already in hypervisor mode!" NL);
317 FATAL(
"FATAL: not in hypervisor mode while calling hypervisor_leave()");
330 if (current_hdos_func >= 0)
365 hypervisor_is_first_call = 0;
368 DEBUGPRINT(
"HYPERVISOR: clearing video standard change banning" NL);
374 DEBUG(
"HYPERVISOR: processing queued trap on leaving hypervisor: trap #$%02X" NL, hypervisor_queued_trap);
376 hypervisor_queued_trap = -1;
383 if (hypervisor_monout_p >= hypervisor_monout - 1 +
sizeof hypervisor_monout)
385 int flush = (chr == 0x0A || chr == 0x0D || chr == 0x8A || chr == 0x8D);
386 if (hypervisor_monout_p == hypervisor_monout && flush)
389 *hypervisor_monout_p = 0;
390 if (hypervisor_serial_out_asciizer) {
391 unsigned char *p = (
unsigned char*)hypervisor_monout;
393 if (*p >= 0x61 && *p <= 0x7A)
395 else if (*p >= 0xC1 && *p <= 0xDA)
397 else if (*p < 0x20 || *p >= 0x80)
402 fprintf(stderr,
"Hypervisor serial output: \"%s\"." NL, hypervisor_monout);
403 DEBUG(
"MEGA65: Hypervisor serial output: \"%s\"." NL, hypervisor_monout);
404 hypervisor_monout_p = hypervisor_monout;
407 *(hypervisor_monout_p++) = (
char)chr;
413 DEBUGPRINT(
"HYPERVISOR: disabling debug ability: %s" NL, reason);
416 INFO_WINDOW(
"Hypervisor debug feature is asked to be disabled: %s", reason);
425 hypervisor_serial_out_asciizer = use_hypervisor_serial_out_asciizer;
426 if (debug_file_storage) {
427 free(debug_file_storage);
428 debug_file_storage = NULL;
435 DEBUG(
"HYPERDEBUG: feature is not enabled, null file name for list file" NL);
443 int ret =
xemu_load_file(
fn, NULL, 10, 4 << 20,
"Failed to load the REP file");
448 debug_file_storage[ret] =
'\0';
449 if (strlen(debug_file_storage) != ret) {
450 ERROR_WINDOW(
"The loaded REP file has NULL character inside, thus it's invalid!");
453 DEBUGPRINT(
"HYPERDEBUG: loaded REP file with %d bytes" NL, ret);
454 static const char unknown_source_name[] =
"<UNKNOWN_SRC>";
455 static const char unknown_line[] =
"<UNKNOWN_LINE>";
456 for (
int a = 0; a < 0x4000; a++) {
457 debug_info[a].
src_fn = unknown_source_name;
461 debug_info[a].
exec = 0;
462 debug_info[a].
line = unknown_line;
465 static const char valid_label_characters[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
466 const char *current_source_file_name = unknown_source_name, *unresolved_symbol = NULL;
467 int total_symbols = 0, source_lines = 0, sym_cols = 0;
468 for (
char *
r = debug_file_storage ;*
r ;) {
472 while (*nl && *nl !=
'\r' && *nl !=
'\n')
476 while (*nl ==
'\r' || *nl ==
'\n')
480 char *p = strchr(
r,
':');
485 char *q = p + strlen(p) - 1;
487 while (q >= p && *q !=
'/' && *q !=
'\\')
489 current_source_file_name = q > p ? q + 1 : p;
491 DEBUGPRINT(
"HYPERDEBUG: unknown acme-comment line: %s" NL,
r);
497 int line_number,
addr;
503 switch (sscanf(
r,
"%d %x", &line_number, &
addr)) {
510 if (addr < 0x8000 || addr >= 0xC000) {
511 ERROR_WINDOW(
"Bad REP file contains address outside of $8000...$BFFF area!");
517 FATAL(
"%s(): impossible sscanf() result", __func__);
520 while (*
r && *
r <= 0x20)
524 while (strchr(valid_label_characters, *l))
530 if (unresolved_symbol) {
531 DEBUG(
"HYPERDEBUG: warning: multiple unresolved syms collide ignoring %s in favour of %s" NL,
r, unresolved_symbol);
534 unresolved_symbol =
r;
541 debug_info[
addr].
src_fn = current_source_file_name;
544 if (unresolved_symbol) {
547 unresolved_symbol = NULL;
549 while (*
r && *
r <= 0x20)
557 DEBUGPRINT(
"HYPERDEBUG: imported %d symbols (%d collisions) and %d source lines" NL, total_symbols, sym_cols, source_lines);
561 static const char first_fake_label[] =
"<HYPPO_BASE>";
562 debug_info[0].
sym_name = first_fake_label;
564 for (
int a = 0, last_symi = 0; a < 0x4000; a++) {
567 debug_info[a].
sym_offs = a - last_symi;
576 if (debug_file_storage) {
577 free(debug_file_storage);
578 debug_file_storage = NULL;
604 DEBUG(
"HYPERDEBUG: allowed to run outside of hypervisor memory, no debug info, PC = $%04X" NL, cpu65.pc);
607 static const unsigned int io_mode_xlat[4] = {2, 3, 0, 4};
608 static Uint16 prev_sp = 0xBEFF;
609 static int prev_pc = 0;
610 static int do_execution_range_check = 1;
611 static int previous_within_hypervisor_ram = 1;
612 const int within_hypervisor_ram = (cpu65.pc >= 0x8000 && cpu65.pc < 0xC000);
613 if (
XEMU_UNLIKELY(previous_within_hypervisor_ram != within_hypervisor_ram)) {
614 DEBUG(
"HYPERDEBUG: execution %s hypervisor RAM at PC=$%04X (PC before=$%04X)" NL, within_hypervisor_ram ?
"RETURNS to" :
"LEAVES", cpu65.pc, prev_pc);
615 if (within_hypervisor_ram && cpu65.sphi != 0x0100)
616 DEBUG(
"HYPERDEBUG: warning, execution in hypervisor mode leaves the hypervisor RAM with SPHI != $01 but $%02X" NL, cpu65.sphi >> 8);
617 if (within_hypervisor_ram && cpu65.bphi != 0x0000)
618 DEBUG(
"HYPERDEBUG: warning, execution in hypervisor mode leaves the hypervisor RAM with BPHI != $00 but $%02X" NL, cpu65.bphi >> 8);
619 previous_within_hypervisor_ram = within_hypervisor_ram;
623 DEBUG(
"HYPERDEBUG: warning, execution in hypervisor memory without SPHI == $BE but $%02X" NL, cpu65.sphi >> 8);
625 DEBUG(
"HYPERDEBUG: warning, execution in hypervisor memory without BPHI == $BF but $%02X" NL, cpu65.bphi >> 8);
627 DEBUG(
"HYPERDEBUG: warning, execution in hypervisor memory with VIC I/O mode of %d" NL, io_mode_xlat[
vic_iomode]);
629 const Uint16 now_sp = cpu65.sphi | cpu65.s;
630 int sp_diff = (int)prev_sp - (
int)now_sp;
637 if (sp_diff > 2 && sp_diff < 0x100)
638 DEBUG(
"HYPERVISOR: warning, possible underflow of stack! SP has changed: $%04X -> $%04X @ PC=$%04X", prev_sp, now_sp, cpu65.pc);
642 if (
XEMU_UNLIKELY(!within_hypervisor_ram && do_execution_range_check && execution_range_check_gate)) {
643 DEBUG(
"HYPERDEBUG: execution outside of the hypervisor memory, PC = $%04X" NL, cpu65.pc);
645 sprintf(msg,
"Hypervisor fatal error: execution outside of the hypervisor memory, PC=$%04X SP=$%04X", cpu65.pc, cpu65.sphi | cpu65.s);
646 switch (
QUESTION_WINDOW(
"Reset|Exit Xemu|Ignore now|Ingore all", msg)) {
656 do_execution_range_check = 0;
665 if (
XEMU_UNLIKELY(within_hypervisor_ram && !debug_info[cpu65.pc - 0x8000].
exec && !cpu65.prefix)) {
666 DEBUG(
"HYPERDEBUG: execution address not found in list file (out-of-order code?), PC = $%04X" NL, cpu65.pc);
667 FATAL(
"Hypervisor fatal error: execution address not found in list file (out-of-order code?), PC = $%04X", cpu65.pc);
675 "HYPERDEBUG: PC=%04X SP=%04X B=%02X A=%02X X=%02X Y=%02X Z=%02X P=%c%c%c%c%c%c%c%c IO=%u @ %s:%d %s+$%X | %s" NL,
676 cpu65.pc, now_sp, cpu65.bphi >> 8, cpu65.a, cpu65.x, cpu65.y, cpu65.z,
686 within_hypervisor_ram ? debug_info[cpu65.pc - 0x8000].
src_fn :
"<NOT>",
687 within_hypervisor_ram ? debug_info[cpu65.pc - 0x8000].
src_ln : 0,
688 within_hypervisor_ram ? debug_info[cpu65.pc - 0x8000].
sym_name :
"<NOT>",
689 within_hypervisor_ram ? debug_info[cpu65.pc - 0x8000].
sym_offs : 0,
690 within_hypervisor_ram ? debug_info[cpu65.pc - 0x8000].
line : (cpu65.prefix ?
"<PREFIXED-OP>" :
"?")