From ca1b77e60160362e8733859e9f63f3df79522c6c Mon Sep 17 00:00:00 2001 From: kub Date: Tue, 11 May 2021 22:05:57 +0200 Subject: [PATCH] 32x, drc, fix saving SH2 SR in dma --- cpu/sh2/compiler.h | 5 +++-- cpu/sh2/sh2.h | 4 ++-- pico/32x/sh2soc.c | 4 ++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/cpu/sh2/compiler.h b/cpu/sh2/compiler.h index 8892b236..f0322743 100644 --- a/cpu/sh2/compiler.h +++ b/cpu/sh2/compiler.h @@ -70,12 +70,13 @@ extern void REGPARM(1) (*sh2_drc_restore_sr)(SH2 *sh2); #else #define DRC_DECLARE_SR register long _sh2_sr asm(DRC_SR_REG) #endif +// NB: save/load SR register only when DRC is executing and not in DMA access #define DRC_SAVE_SR(sh2) \ - if (likely(sh2->state & SH2_IN_DRC)) \ + if (likely((sh2->state & (SH2_IN_DRC|SH2_STATE_SLEEP)) == SH2_IN_DRC)) \ sh2->sr = (s32)_sh2_sr // sh2_drc_save_sr(sh2) #define DRC_RESTORE_SR(sh2) \ - if (likely(sh2->state & SH2_IN_DRC)) \ + if (likely((sh2->state & (SH2_IN_DRC|SH2_STATE_SLEEP)) == SH2_IN_DRC)) \ _sh2_sr = (s32)sh2->sr // sh2_drc_restore_sr(sh2) #else diff --git a/cpu/sh2/sh2.h b/cpu/sh2/sh2.h index c3ca1146..614e7de1 100644 --- a/cpu/sh2/sh2.h +++ b/cpu/sh2/sh2.h @@ -50,8 +50,8 @@ typedef struct SH2_ #define SH2_STATE_CPOLL (1 << 2) // polling comm regs #define SH2_STATE_VPOLL (1 << 3) // polling VDP #define SH2_STATE_RPOLL (1 << 4) // polling address in SDRAM -#define SH2_TIMER_RUN (1 << 7) // SOC WDT timer is running -#define SH2_IN_DRC (1 << 8) // DRC in use +#define SH2_TIMER_RUN (1 << 6) // SOC WDT timer is running +#define SH2_IN_DRC (1 << 7) // DRC in use unsigned int state; uint32_t poll_addr; int poll_cycles; diff --git a/pico/32x/sh2soc.c b/pico/32x/sh2soc.c index ae9474d2..f8bb4e79 100644 --- a/pico/32x/sh2soc.c +++ b/pico/32x/sh2soc.c @@ -480,10 +480,12 @@ void REGPARM(3) sh2_peripheral_write32(u32 a, u32 d, SH2 *sh2) if (!(dmac->dmaor & DMA_DME)) return; + DRC_SAVE_SR(sh2); if ((dmac->chan[0].chcr & (DMA_TE|DMA_DE)) == DMA_DE) dmac_trigger(sh2, &dmac->chan[0]); if ((dmac->chan[1].chcr & (DMA_TE|DMA_DE)) == DMA_DE) dmac_trigger(sh2, &dmac->chan[1]); + DRC_RESTORE_SR(sh2); break; } @@ -538,7 +540,9 @@ static void dreq1_do(SH2 *sh2, struct dma_chan *chan) if ((chan->dar & ~0xf) != 0x20004030) elprintf(EL_32XP|EL_ANOMALY, "dreq1: bad dar?: %08x\n", chan->dar); + sh2->state |= SH2_STATE_SLEEP; dmac_transfer_one(sh2, chan); + sh2->state &= ~SH2_STATE_SLEEP; if (chan->tcr == 0) dmac_transfer_complete(sh2, chan); } -- 2.39.2