aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/psxetc/interrupts.c
diff options
context:
space:
mode:
authorspicyjpeg <thatspicyjpeg@gmail.com>2022-10-13 23:21:32 +0200
committerspicyjpeg <thatspicyjpeg@gmail.com>2022-10-13 23:21:32 +0200
commitb458ea70700739bf8a64217af369c7ace08fc954 (patch)
tree77281ebd18e5049fcb1c86718854ff3ce91e54c2 /libpsn00b/psxetc/interrupts.c
parent8e92156bc6a977651771d2cf91ac5800a0e9a913 (diff)
downloadpsn00bsdk-b458ea70700739bf8a64217af369c7ace08fc954.tar.gz
Fix dropped IRQs, clean up psxcd and psxetc logging
Diffstat (limited to 'libpsn00b/psxetc/interrupts.c')
-rw-r--r--libpsn00b/psxetc/interrupts.c50
1 files changed, 28 insertions, 22 deletions
diff --git a/libpsn00b/psxetc/interrupts.c b/libpsn00b/psxetc/interrupts.c
index 1b5ac32..cc9d12c 100644
--- a/libpsn00b/psxetc/interrupts.c
+++ b/libpsn00b/psxetc/interrupts.c
@@ -53,40 +53,46 @@ static const struct JMP_BUF _isr_jmp_buf = {
/* Internal IRQ and DMA handlers */
static void _global_isr(void) {
- uint16_t stat = IRQ_STAT, mask = IRQ_MASK;
+ uint16_t stat = IRQ_STAT & IRQ_MASK;
- // Clear all IRQ flags in one shot. This is not the "proper" way to do it
- // but it's much faster than clearing one flag at a time.
- IRQ_STAT = ~mask;
+ for (; stat; stat = IRQ_STAT & IRQ_MASK) {
+ //for (int i = 0; i < NUM_IRQ_CHANNELS; i++) {
+ for (int i = 0, mask = 1; stat; i++, stat >>= 1, mask <<= 1) {
+ if (!(stat & 1))
+ continue;
- //for (int i = 0; i < NUM_IRQ_CHANNELS; i++) {
- for (int i = 0; stat; i++, stat >>= 1) {
- if (!(stat & 1))
- continue;
+ // Acknowledge the current IRQ. Note that clearing all IRQ flags in one
+ // shot would result in hard-to-debug race conditions (been there, done
+ // that).
+ IRQ_STAT = (uint16_t) (mask ^ 0xffff);
- if (_irq_handlers[i])
- _irq_handlers[i]();
+ if (_irq_handlers[i])
+ _irq_handlers[i]();
+ }
}
ReturnFromException();
}
static void _global_dma_handler(void) {
- uint32_t stat = DMA_DICR;
+ uint32_t dicr = DMA_DICR;
+ uint32_t stat = (dicr >> 24) & 0x7f;
+
+ for (; stat; dicr = DMA_DICR, stat = (dicr >> 24) & 0x7f) {
+ uint32_t base = dicr & 0x00ffffff;
- // Clear all DMA IRQ flags in one shot (note that flags are cleared by
- // writing 1 to them rather than 0).
- stat &= 0x7fff0000;
- DMA_DICR = stat;
- stat >>= 24;
+ //for (int i = 0; i < NUM_DMA_CHANNELS; i++) {
+ for (int i = 0, mask = (1 << 24); stat; i++, stat >>= 1, mask <<= 1) {
+ if (!(stat & 1))
+ continue;
- //for (int i = 0; i < NUM_DMA_CHANNELS; i++) {
- for (int i = 0; stat; i++, stat >>= 1) {
- if (!(stat & 1))
- continue;
+ // Acknowledge the current DMA channel's IRQ. For whatever reason
+ // DMA IRQ flags are cleared by writing 1 to them rather than 0.
+ DMA_DICR = base | mask;
- if (_dma_handlers[i])
- _dma_handlers[i]();
+ if (_dma_handlers[i])
+ _dma_handlers[i]();
+ }
}
}