Implement NO$GBA debug registers. (#1110)

* Implement NO$GBA debug registers.

NO$GBA comes with 4 debug registers that allow a ROM to print text to
the emulator terminal and 2 other status registers, one with the name of the
emulator and the other with the clock cycles count. This commit
implements them for the ARMv5 processor.

Some small things to note:
 - `NocashPrint` was changed and now it takes an address to _the string_ instead of the flags before it (those
don't do anything anyways).
 - The "Emulation ID" register contains the string "melonDS " followed by version, _not_ "NO$GBA"

* Fix styling issue and improve comment regarding NO$GBA message flags
This commit is contained in:
Pedro 2021-05-27 07:15:16 -03:00 committed by GitHub
parent 308e5df426
commit f74387a8c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 50 additions and 6 deletions

View File

@ -661,7 +661,10 @@ void A_MOV_REG_LSL_IMM_DBG(ARM* cpu)
(cpu->NextInstr[0] & 0xFF000000) == 0xEA000000 && // branch
(cpu->NextInstr[1] & 0xFFFF) == 0x6464)
{
u32 addr = cpu->R[15] + 2;
// GBATek says the two bytes after the 2nd ID are _reserved_ for flags
// but since they serve no purpose ATTOW, we can skip them
u32 addr = cpu->R[15] + 4; // Skip 2nd ID and flags
// TODO: Pass flags to NocashPrint
NDS::NocashPrint(cpu->Num, addr);
}
}
@ -1527,7 +1530,10 @@ void T_MOV_HIREG(ARM* cpu)
(cpu->NextInstr[0] & 0xF800) == 0xE000 && // branch
(cpu->NextInstr[1] & 0xFFFF) == 0x6464)
{
u32 addr = cpu->R[15] + 2;
// GBATek says the two bytes after the 2nd ID are _reserved_ for flags
// but since they serve no purpose ATTOW, we can skip them
u32 addr = cpu->R[15] + 4; // Skip 2nd ID and flags
// TODO: Pass flags to NocashPrint
NDS::NocashPrint(cpu->Num, addr);
}
}

View File

@ -1415,10 +1415,7 @@ u64 GetSysClockCycles(int num)
void NocashPrint(u32 ncpu, u32 addr)
{
// addr: u16 flags (TODO: research? libnds doesn't use those)
// addr+2: debug string
addr += 2;
// addr: debug string
ARM* cpu = ncpu ? (ARM*)ARM7 : (ARM*)ARM9;
u8 (*readfn)(u32) = ncpu ? NDS::ARM7Read8 : NDS::ARM9Read8;
@ -2846,6 +2843,14 @@ u8 ARM9IORead8(u32 addr)
{
return GPU3D::Read8(addr);
}
// NO$GBA debug register "Emulation ID"
if(addr >= 0x04FFFA00 && addr < 0x04FFFA10)
{
// FIX: GBATek says this should be padded with spaces
static char const emuID[16] = "melonDS " MELONDS_VERSION;
auto idx = addr - 0x04FFFA00;
return (u8)(emuID[idx]);
}
printf("unknown ARM9 IO read8 %08X %08X\n", addr, ARM9->R[15]);
return 0;
@ -3104,6 +3109,11 @@ u32 ARM9IORead32(u32 addr)
case 0x04100010:
if (!(ExMemCnt[0] & (1<<11))) return NDSCart::ReadROMData();
return 0;
// NO$GBA debug register "Clock Cycles"
// Since it's a 64 bit reg. the CPU will access it in two parts:
case 0x04FFFA20: return (u32)(GetSysClockCycles(0) & 0xFFFFFFFF);
case 0x04FFFA24: return (u32)(GetSysClockCycles(0) >> 32);
}
if ((addr >= 0x04000000 && addr < 0x04000060) || (addr == 0x0400006C))
@ -3532,6 +3542,34 @@ void ARM9IOWrite32(u32 addr, u32 val)
case 0x04100010:
if (!(ExMemCnt[0] & (1<<11))) NDSCart::WriteROMData(val);
return;
// NO$GBA debug register "String Out (raw)"
case 0x04FFFA10:
{
char output[1024] = { 0 };
char ch = '.';
for (size_t i = 0; i < 1023 && ch != '\0'; i++)
{
ch = NDS::ARM9Read8(val + i);
output[i] = ch;
}
printf("%s", output);
return;
}
// NO$GBA debug registers "String Out (with parameters)" and "String Out (with parameters, plus linefeed)"
case 0x04FFFA14:
case 0x04FFFA18:
{
bool appendLF = 0x04FFFA18 == addr;
NocashPrint(0, val);
if(appendLF)
printf("\n");
return;
}
// NO$GBA debug register "Char Out"
case 0x04FFFA1C: printf("%lc", val); return;
}
if (addr >= 0x04000000 && addr < 0x04000060)