Skip to content

Commit

Permalink
implement hardware bug in timer
Browse files Browse the repository at this point in the history
fixes PCM samples in nintendo's games and some homebrew
  • Loading branch information
skyfloogle committed Dec 26, 2024
1 parent 3a7eaba commit c0cf27b
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 0 deletions.
2 changes: 2 additions & 0 deletions include/v810_mem.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ typedef struct {
BYTE CCSR; //Com Cnt Stat Reg, 0x02000004
BYTE CCR; //Com Controll Reg, 0x02000000
HWORD hwRead; //Hardware input read timer
uint8_t timerSkipState;
int8_t timerSkipTimer;
} V810_HREGDAT;

//Export some data structs...
Expand Down
1 change: 1 addition & 0 deletions source/common/v810_cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ int serviceInt(unsigned int cycles, WORD PC) {
tHReg.tCount += tHReg.tTHW + 1; //reset counter
tHReg.TCR |= 0x02; //Zero Status
}
tHReg.timerSkipState = 0;
tHReg.TLB = (tHReg.tCount&0xFF);
tHReg.THB = ((tHReg.tCount>>8)&0xFF);
}
Expand Down
16 changes: 16 additions & 0 deletions source/common/v810_mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,22 @@ void hcreg_wbyte(WORD addr, BYTE data) {
) zstat = 0; // Clear the ZStat Flag...

tHReg.TCR = (((data|0xE4)&0xFD)|zstat);

if (tHReg.tCount == tHReg.tTHW + 1) {
// Due to a hardware bug, when the timer is turned off then back on,
// it may reload early. The frequency with which it does this depends on
// the reload value. This seems to only happen on the 20 microsecond timer.
// The precise mechanism for this is unclear, as there seems to be a blip
// every 400-ish round-trips. However, this is close enough.
if ((data & 0x08) == 0 && tHReg.timerSkipState == 0) {
tHReg.timerSkipState = 1;
} else if ((data & 0x18) == 0x18 && tHReg.timerSkipState == 1) {
const u8 SKIPS[] = {0, 4, 2, 3, 1};
if (tHReg.timerSkipTimer > 0 || tHReg.tTHW % 5 == 0) tHReg.tCount--;
if (tHReg.timerSkipTimer <= 0) tHReg.timerSkipTimer = SKIPS[tHReg.tTHW % 5];
tHReg.timerSkipTimer--;
}
}
break;
case 0x02000024: //WCR
//~ dtprintf(3,ferr,"\nWrite BYTE HCREG WCR [%08x]:%02x ",addr,data);
Expand Down

0 comments on commit c0cf27b

Please sign in to comment.