32x, drc, fix saving SH2 SR in dma
authorkub <derkub@gmail.com>
Tue, 11 May 2021 20:05:57 +0000 (22:05 +0200)
committerkub <derkub@gmail.com>
Tue, 11 May 2021 20:05:57 +0000 (22:05 +0200)
cpu/sh2/compiler.h
cpu/sh2/sh2.h
pico/32x/sh2soc.c

index 8892b23..f032274 100644 (file)
@@ -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
index c3ca114..614e7de 100644 (file)
@@ -50,8 +50,8 @@ typedef struct SH2_
 #define SH2_STATE_CPOLL (1 << 2)       // polling comm regs\r
 #define SH2_STATE_VPOLL (1 << 3)       // polling VDP\r
 #define SH2_STATE_RPOLL (1 << 4)       // polling address in SDRAM\r
-#define SH2_TIMER_RUN   (1 << 7)       // SOC WDT timer is running\r
-#define SH2_IN_DRC      (1 << 8)       // DRC in use\r
+#define SH2_TIMER_RUN   (1 << 6)       // SOC WDT timer is running\r
+#define SH2_IN_DRC      (1 << 7)       // DRC in use\r
        unsigned int    state;\r
        uint32_t        poll_addr;\r
        int             poll_cycles;\r
index ae9474d..f8bb4e7 100644 (file)
@@ -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);
 }