mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-25 18:05:12 -04:00
Fix encoded CD-ROM interrupt mask matching
Adapt the CD interrupt mask/status comparison from kem0x PR #14 and centralize it in a tested helper. The HC05 exposes numeric INT1..INT5 reasons but gates the line with a direct mask/status AND, so the common 0x07 mask must also pass INT4 and INT5. Source: https://github.com/mstan/psxrecomp/pull/14 Source-commit: https://github.com/mstan/psxrecomp/commit/dd9e5c65073dd41fbac2d965d2f945a866ec59e2 Co-authored-by: Kareem Olim <kareemolim@gmail.com>
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
# kem0x PR 14: encoded CD-ROM interrupt matching
|
||||
|
||||
Evaluated and adapted on 2026-07-13.
|
||||
|
||||
## Provenance
|
||||
|
||||
The CD-ROM interrupt mask fix was rebuilt from Kareem Olim's
|
||||
[PSXrecomp PR 14](https://github.com/mstan/psxrecomp/pull/14), specifically
|
||||
commit
|
||||
[`dd9e5c65073dd41fbac2d965d2f945a866ec59e2`](https://github.com/mstan/psxrecomp/commit/dd9e5c65073dd41fbac2d965d2f945a866ec59e2)
|
||||
(`Deliver encoded CD interrupt reasons correctly`). The implementation here
|
||||
centralizes the mask/status comparison in a tested internal helper rather than
|
||||
copying the source patch verbatim.
|
||||
|
||||
The behavior follows the
|
||||
[PSX-SPX CD-ROM register documentation](https://psx-spx.consoledev.net/cdromdrive/#0x1f801803-read-banks-1-and-3-hintsts):
|
||||
HINTSTS bits 0..2 are an encoded HC05 interrupt reason, but the interrupt line
|
||||
is asserted whenever `HINTMSK & HINTSTS` is nonzero. Converting the reason to a
|
||||
one-hot bit before applying the mask is therefore incorrect. A common `0x07`
|
||||
mask must deliver encoded INT4 (DataEnd) and INT5 (DiskError) as well as
|
||||
INT1--INT3.
|
||||
|
||||
## Deliberately excluded
|
||||
|
||||
This branch does not import PR 14's WebAssembly/web frontend, Pepsiman-specific
|
||||
hooks or patches, CD-DA playback changes, SPU changes, raster/rendering changes,
|
||||
or any other runtime and build-system material. Those changes have different
|
||||
scope and review requirements and are not needed for encoded interrupt mask
|
||||
matching.
|
||||
+5
-3
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
#include "cdrom.h"
|
||||
#include "cdrom_irq.h"
|
||||
#include "dma.h"
|
||||
#include "spu.h"
|
||||
#include "event_ring.h"
|
||||
@@ -578,7 +579,8 @@ static void present_cdrom_irq(void) {
|
||||
* the guest's command/ack write — and thus from being lost to that ISR's
|
||||
* own trailing INTC ack. */
|
||||
if (cdrom_irq_present_delay > 0) return;
|
||||
if (irq_flag && (irq_enable & (1 << (irq_flag - 1))) && !cdrom_intc_request_latched) {
|
||||
if (cdrom_irq_mask_matches_reason(irq_enable, irq_flag) &&
|
||||
!cdrom_intc_request_latched) {
|
||||
psx_irq_raise(2, irq_flag); /* IRQ_CDROM; detail = CD response/IRQ type */
|
||||
cdrom_intc_request_latched = 1;
|
||||
cdrom_intc_latched_generation = cdrom_irq_generation;
|
||||
@@ -590,7 +592,7 @@ static void present_cdrom_irq(void) {
|
||||
/* Fire CDROM IRQ into the interrupt controller (explicit, per command/response).
|
||||
* Trace the masked case here only (low-frequency); refresh stays silent. */
|
||||
static void fire_cdrom_irq(void) {
|
||||
if (irq_flag && !(irq_enable & (1 << (irq_flag - 1)))) {
|
||||
if (irq_flag && !cdrom_irq_mask_matches_reason(irq_enable, irq_flag)) {
|
||||
trace_cdrom('f', 0, irq_flag, 0);
|
||||
}
|
||||
present_cdrom_irq();
|
||||
@@ -1841,7 +1843,7 @@ uint32_t cdrom_cycles_to_irq(uint32_t i_mask) {
|
||||
if (!(i_mask & (1u << 2))) return 0xFFFFFFFFu; /* IRQ_CDROM masked */
|
||||
uint32_t best = 0xFFFFFFFFu;
|
||||
/* Armed response awaiting presentation (will raise bit2 when delay hits 0). */
|
||||
if (irq_flag && (irq_enable & (1u << (irq_flag - 1)))) {
|
||||
if (cdrom_irq_mask_matches_reason(irq_enable, irq_flag)) {
|
||||
uint32_t d = cdrom_irq_present_delay > 0 ? (uint32_t)cdrom_irq_present_delay : 0u;
|
||||
if (d < best) best = d;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef PSXRECOMP_CDROM_IRQ_H
|
||||
#define PSXRECOMP_CDROM_IRQ_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* HINTSTS bits 0..2 contain an encoded interrupt reason (INT1..INT5), not
|
||||
* independent one-hot flags. The controller nevertheless gates its IRQ line
|
||||
* by directly ANDing HINTSTS with HINTMSK. In particular, mask 0x07 enables
|
||||
* all five encoded reasons, including INT4 and INT5. */
|
||||
static inline int cdrom_irq_mask_matches_reason(uint8_t irq_enable,
|
||||
uint8_t irq_reason) {
|
||||
return (irq_enable & irq_reason & 0x07u) != 0;
|
||||
}
|
||||
|
||||
#endif /* PSXRECOMP_CDROM_IRQ_H */
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Validate PS1 CD-ROM interrupt mask matching.
|
||||
*
|
||||
* Build:
|
||||
* cc -std=c99 -Wall -Wextra -Werror -I../src \
|
||||
* -o test_cdrom_irq_mask test_cdrom_irq_mask.c
|
||||
*/
|
||||
#include "cdrom_irq.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static int failures;
|
||||
|
||||
#define CHECK(expected, mask, reason, label) do { \
|
||||
int actual = cdrom_irq_mask_matches_reason((uint8_t)(mask), \
|
||||
(uint8_t)(reason)); \
|
||||
if (actual != (expected)) { \
|
||||
fprintf(stderr, "FAIL: %s (mask=0x%02X reason=%u expected=%d got=%d)\n",\
|
||||
(label), (unsigned)(mask), (unsigned)(reason), \
|
||||
(expected), actual); \
|
||||
failures++; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int main(void) {
|
||||
/* The conventional 0x07 mask must deliver every encoded HC05 reason. */
|
||||
for (uint8_t reason = 1; reason <= 5; reason++) {
|
||||
CHECK(1, 0x07, reason, "mask 0x07 enables INT1 through INT5");
|
||||
}
|
||||
|
||||
/* The mask/status comparison is bitwise, not a reason-to-one-hot lookup. */
|
||||
CHECK(0, 0x01, 2, "bit 0 does not match INT2");
|
||||
CHECK(1, 0x01, 3, "bit 0 matches encoded INT3");
|
||||
CHECK(0, 0x02, 4, "bit 1 does not match INT4");
|
||||
CHECK(1, 0x04, 4, "bit 2 matches encoded INT4");
|
||||
CHECK(1, 0x01, 5, "bit 0 matches encoded INT5");
|
||||
CHECK(1, 0x04, 5, "bit 2 matches encoded INT5");
|
||||
|
||||
CHECK(0, 0x00, 1, "zero mask suppresses an interrupt");
|
||||
CHECK(0, 0x07, 0, "reason zero means no interrupt");
|
||||
CHECK(0, 0x18, 5, "audio-buffer mask bits do not match an HC05 reason");
|
||||
|
||||
if (failures) {
|
||||
fprintf(stderr, "FAILED (%d)\n", failures);
|
||||
return 1;
|
||||
}
|
||||
puts("ALL PASS");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user