mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
2d915c3fa9
Phase 1 of the cycle-budgeted precise interrupt-take-point fix (root cause: compiled blocks take IRQs only at block edges; HW + the dirty-RAM interpreter take them at the exact instruction — oracle-confirmed at the Tomba 2 logo Timer1 debounce). Design validated with ChatGPT; full spec in PRECISE_IRQ_SLICE.md. This commit lands the additive, no-behavior-change foundation (Task #2) plus the prior session's diagnostic take-PC capture, and a build-hygiene dedup: - cycles_to_next_event() (interrupts.c): single source of truth — min guest-cycle distance to the next DELIVERABLE interrupt (source raises its I_STAT bit AND that bit is unmasked in i_mask). Aggregates VBLANK + per-peripheral queries. - timers/cdrom/dma/sio _cycles_to_irq(i_mask): each peripheral owns its own next-IRQ-distance query; all conservative under-estimates (smaller => slice more => never run past an event). - debug_server: cycles_to_next_event command for live validation. - interrupts.c: take-PC capture into the IRQ_DELIVER event-ring aux (prior session's diagnostic; records the architectural take-PC for cross-backend diff). - overlay_loader.c: remove duplicate psx_native_bad_entry definition (HEAD had it twice; would not link cleanly). Live-validated at the logo: returns the VBLANK distance, correctly excludes the three free-running (unarmed/masked) timers and idle CD/DMA/SIO. Runtime-only, no regen. The two-tier executor (Task #3) that consumes this is next. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
120 lines
3.0 KiB
C
120 lines
3.0 KiB
C
/* dma.h — PS1 DMA controller simulation (Phase 3).
|
|
*
|
|
* 7 DMA channels:
|
|
* Ch0: MDEC in 0x1F801080
|
|
* Ch1: MDEC out 0x1F801090
|
|
* Ch2: GPU 0x1F8010A0
|
|
* Ch3: CDROM 0x1F8010B0
|
|
* Ch4: SPU 0x1F8010C0
|
|
* Ch5: PIO 0x1F8010D0
|
|
* Ch6: OTC 0x1F8010E0
|
|
*
|
|
* Global:
|
|
* DPCR: 0x1F8010F0 (DMA control — enable bits per channel)
|
|
* DICR: 0x1F8010F4 (DMA interrupt control)
|
|
*/
|
|
|
|
#ifndef PSXRECOMP_DMA_H
|
|
#define PSXRECOMP_DMA_H
|
|
|
|
#include <stdint.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
void dma_init(void);
|
|
uint32_t dma_read(uint32_t addr);
|
|
void dma_write(uint32_t addr, uint32_t val);
|
|
void dma_write_masked(uint32_t addr, uint32_t val, uint32_t mask);
|
|
void dma_advance(uint32_t cycles);
|
|
/* Cycle-budgeted precise event slicing: guest CPU cycles until a DELIVERABLE
|
|
* DMA IRQ (bit3 unmasked in i_mask). UINT32_MAX if none. */
|
|
uint32_t dma_cycles_to_irq(uint32_t i_mask);
|
|
uint32_t dma_get_dicr(void);
|
|
uint32_t dma_get_dpcr(void);
|
|
int dma_cdrom_transfer_active(void);
|
|
|
|
typedef struct DMAChannelDebugState {
|
|
uint32_t madr;
|
|
uint32_t bcr;
|
|
uint32_t chcr;
|
|
uint32_t active;
|
|
uint32_t remaining_words;
|
|
uint32_t cycles_accum;
|
|
} DMAChannelDebugState;
|
|
|
|
typedef struct DMADebugState {
|
|
uint32_t dpcr;
|
|
uint32_t dicr;
|
|
DMAChannelDebugState channels[7];
|
|
} DMADebugState;
|
|
|
|
typedef struct DMATraceEntry {
|
|
uint64_t seq;
|
|
uint32_t frame;
|
|
uint32_t kind;
|
|
uint32_t channel;
|
|
uint32_t total_words;
|
|
uint32_t addr;
|
|
uint32_t val;
|
|
uint32_t mask;
|
|
uint32_t madr;
|
|
uint32_t bcr;
|
|
uint32_t chcr;
|
|
uint32_t dpcr;
|
|
uint32_t dicr_before;
|
|
uint32_t dicr_after;
|
|
uint32_t i_stat_before;
|
|
uint32_t i_stat_after;
|
|
uint32_t func;
|
|
uint32_t pc;
|
|
} DMATraceEntry;
|
|
|
|
#define DMA_TRACE_CAP (1 << 14)
|
|
#define DMA_CDROM_HISTORY_CAP (1 << 13)
|
|
#define DMA_CDROM_HISTORY_WORDS 16
|
|
|
|
typedef struct DMACDROMHistoryEntry {
|
|
uint64_t seq;
|
|
uint32_t frame_start;
|
|
uint32_t frame_end;
|
|
uint32_t start_addr;
|
|
uint32_t final_addr;
|
|
uint32_t requested_words;
|
|
uint32_t moved_words;
|
|
uint32_t bcr;
|
|
uint32_t chcr;
|
|
uint32_t dpcr;
|
|
uint32_t dicr_start;
|
|
uint32_t dicr_end;
|
|
uint32_t i_stat_start;
|
|
uint32_t i_stat_end;
|
|
uint32_t func;
|
|
uint32_t pc;
|
|
int lba;
|
|
int sector_size;
|
|
int sector_read_pos_start;
|
|
int sector_read_pos_end;
|
|
uint8_t mode;
|
|
uint8_t sector_available_start;
|
|
uint8_t sector_available_end;
|
|
uint8_t completed;
|
|
uint8_t first_count;
|
|
uint8_t last_count;
|
|
uint32_t first_words[DMA_CDROM_HISTORY_WORDS];
|
|
uint32_t last_words[DMA_CDROM_HISTORY_WORDS];
|
|
} DMACDROMHistoryEntry;
|
|
|
|
uint64_t dma_debug_get_trace(const DMATraceEntry** out_entries);
|
|
void dma_debug_clear_trace(void);
|
|
void dma_debug_get_state(DMADebugState* out);
|
|
uint64_t dma_debug_get_cdrom_history(const DMACDROMHistoryEntry** out_entries);
|
|
void dma_debug_clear_cdrom_history(void);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* PSXRECOMP_DMA_H */
|