mac_via: extend timer calibration hack to work with A/UX

The A/UX timer calibration loop runs continuously until 2 consecutive iterations
differ by at least 0x492 timer ticks. Modern hosts execute the timer calibration
loop so fast that this situation never occurs causing a hang on boot.

Use a similar method to Shoebill which is to randomly add 0x500 to the T2
counter value during calibration to enable it to eventually succeed.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Message-ID: <20231004083806.757242-21-mark.cave-ayland@ilande.co.uk>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
This commit is contained in:
Mark Cave-Ayland 2023-10-04 09:38:06 +01:00 committed by Laurent Vivier
parent 9d35c6ade5
commit b4d3a83b89
1 changed files with 56 additions and 0 deletions

View File

@ -983,6 +983,44 @@ static void via1_timer_calibration_hack(MOS6522Q800VIA1State *v1s, int addr,
/* Looks like there has been a reset? */
v1s->timer_hack_state = 1;
}
if (addr == VIA_REG_T2CL && val == 0xf0) {
/* VIA_REG_T2CL: low byte of counter (A/UX) */
v1s->timer_hack_state = 5;
}
break;
case 5:
if (addr == VIA_REG_T2CH && val == 0x3c) {
/*
* VIA_REG_T2CH: high byte of counter (A/UX). We are now extremely
* likely to be in the A/UX timer calibration routine, so move to
* the next state where we enable the calibration hack.
*/
v1s->timer_hack_state = 6;
} else if ((addr == VIA_REG_IER && val == 0x20) ||
addr == VIA_REG_T2CH) {
/* We're doing something else with the timer, not calibration */
v1s->timer_hack_state = 0;
}
break;
case 6:
if ((addr == VIA_REG_IER && val == 0x20) || addr == VIA_REG_T2CH) {
/* End of A/UX timer calibration routine, or another write */
v1s->timer_hack_state = 7;
} else {
v1s->timer_hack_state = 0;
}
break;
case 7:
/*
* This is the normal post-calibration timer state once both the
* MacOS toolbox and A/UX have been calibrated, until we see a write
* to VIA_REG_PCR to suggest a reset
*/
if (addr == VIA_REG_PCR && val == 0x22) {
/* Looks like there has been a reset? */
v1s->timer_hack_state = 1;
}
break;
default:
g_assert_not_reached();
@ -998,6 +1036,7 @@ static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size)
MOS6522Q800VIA1State *s = MOS6522_Q800_VIA1(opaque);
MOS6522State *ms = MOS6522(s);
uint64_t ret;
int64_t now;
addr = (addr >> 9) & 0xf;
ret = mos6522_read(ms, addr, size);
@ -1007,6 +1046,23 @@ static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size)
/* Quadra 800 Id */
ret = (ret & ~VIA1A_CPUID_MASK) | VIA1A_CPUID_Q800;
break;
case VIA_REG_T2CH:
if (s->timer_hack_state == 6) {
/*
* The A/UX timer calibration loop runs continuously until 2
* consecutive iterations differ by at least 0x492 timer ticks.
* Modern hosts execute the timer calibration loop so fast that
* this situation never occurs causing a hang on boot. Use a
* similar method to Shoebill which is to randomly add 0x500 to
* the T2 counter value during calibration to enable it to
* eventually succeed.
*/
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
if (now & 1) {
ret += 0x5;
}
}
break;
}
return ret;
}