]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
CIA latch/timer=0 special case update
authorToni Wilen <twilen@winuae.net>
Tue, 25 Jul 2023 17:56:03 +0000 (20:56 +0300)
committerToni Wilen <twilen@winuae.net>
Tue, 25 Jul 2023 17:56:03 +0000 (20:56 +0300)
cia.cpp

diff --git a/cia.cpp b/cia.cpp
index 49c01624e8e8386062ad40470eee380ab24eabea..a29eb5faa7eff2797a80b536a4f6595e90dcc604 100644 (file)
--- a/cia.cpp
+++ b/cia.cpp
@@ -444,7 +444,7 @@ static uae_u8 cia_inmode_cnt(int num)
        return icr;
 }
 
-static int process_pipe(struct CIATimer *t, int cc, uae_u8 crmask, int *ovfl)
+static int process_pipe(struct CIATimer *t, int cc, uae_u8 crmask, int *ovfl, int loadednow)
 {
        int ccout = cc;
 
@@ -455,8 +455,8 @@ static int process_pipe(struct CIATimer *t, int cc, uae_u8 crmask, int *ovfl)
                        t->inputpipe |= CIA_PIPE_INPUT;
                }
                // interrupt 1 cycle early if timer is already zero
-               if (t->timer == 0 && (t->inputpipe & CIA_PIPE_OUTPUT)) {
-                       *ovfl = 1;
+               if (t->timer == 0 && t->latch == 0 && (t->inputpipe & CIA_PIPE_OUTPUT)) {
+                       *ovfl = loadednow ? 1 : 2;
                }
                return out;
        }
@@ -494,7 +494,7 @@ static void CIA_update_check(void)
        for (int num = 0; num < 2; num++) {
                struct CIA *c = &cia[num];
                int ovfl[2], sp;
-               bool loaded[2], loaded2[2];
+               bool loaded[2], loaded2[2], loaded3[3];
 
                c->icr1 |= c->icr2;
                c->icr2 = 0;
@@ -509,41 +509,45 @@ static void CIA_update_check(void)
                        
                        loaded[tn] = false;
                        loaded2[tn] = false;
+                       loaded3[tn] = false;
 
                        // CIA special cases
                        if (t->loaddelay) {
                                if (ciaclocks > 1) {
                                        abort();
                                }
-                               if (t->loaddelay & 1) {
+
+                               if (t->loaddelay & 0x00000001) {
                                        t->timer = t->latch;
                                        t->inputpipe &= ~CIA_PIPE_CLR1;
                                }
 
-                               if ((t->loaddelay & 0x0100) && t->timer != 0) {
-                                       loaded2[tn] = true;
+                               // timer=0 special cases. TODO: better way to do this..
+                               // delayed timer stop and interrupt (timer=0 condition)
+                               if ((t->loaddelay & 0x00010000)) {
+                                       t->cr &= ~CR_START;
+                                       ovfl[tn] = 2;
                                }
-                               if ((t->loaddelay & 0x010000)) {
-                                       if ((t->timer != 1 || t->latch != 1) && (t->inputpipe & CIA_PIPE_OUTPUT)) {
-                                               loaded2[tn] = true;
-                                       }
+                               // Do not set START=0 until timer has started (timer==0 special case)
+                               if ((t->loaddelay & 0x00000100) && t->timer == 0) {
+                                       loaded2[tn] = true;
                                }
                                if ((t->loaddelay & 0x01000000)) {
                                        loaded[tn] = true;
-                                       if (t->timer == 0) {
-                                               ovfl[tn] = true;
-                                       }
+                               }
+                               if ((t->loaddelay & 0x10000000)) {
+                                       loaded3[tn] = true;
                                }
 
                                t->loaddelay >>= 1;
-                               t->loaddelay &= 0x7f7f7f7f;
+                               t->loaddelay &= 0x77777777;
                        }
                }
 
                // Timer A
                int cc = 0;
                if ((c->t[0].cr & (CR_INMODE | CR_START)) == CR_START || c->t[0].inputpipe) {
-                       cc = process_pipe(&c->t[0], ciaclocks, CR_INMODE | CR_START, &ovfl[0]);
+                       cc = process_pipe(&c->t[0], ciaclocks, CR_INMODE | CR_START, &ovfl[0], loaded3[0]);
                }
                if (cc > 0) {
                        c->t[0].timer -= cc;
@@ -560,7 +564,7 @@ static void CIA_update_check(void)
                                                }
                                        }
                                }
-                               ovfl[0] = 1;
+                               ovfl[0] = 2;
                        }
                }
                assert(c->t[0].timer < 0x10000);
@@ -568,15 +572,15 @@ static void CIA_update_check(void)
                // Timer B
                cc = 0;
                if ((c->t[1].cr & (CR_INMODE | CR_INMODE1 | CR_START)) == CR_START || c->t[1].inputpipe) {
-                       cc = process_pipe(&c->t[1], ciaclocks, CR_INMODE | CR_INMODE1 | CR_START, &ovfl[1]);
+                       cc = process_pipe(&c->t[1], ciaclocks, CR_INMODE | CR_INMODE1 | CR_START, &ovfl[1], loaded3[1]);
                }
                if (cc > 0) {
                        if ((c->t[1].timer == 0 && (c->t[1].cr & (CR_INMODE | CR_INMODE1)))) {
-                               ovfl[1] = 1;
+                               ovfl[1] = 2;
                        } else {
                                c->t[1].timer -= cc;
                                if ((c->t[1].timer == 0 && !(c->t[1].cr & (CR_INMODE | CR_INMODE1)))) {
-                                       ovfl[1] = 1;
+                                       ovfl[1] = 2;
                                }
                        }
                }
@@ -591,18 +595,22 @@ static void CIA_update_check(void)
                        struct CIATimer *t = &c->t[tn];
 
                        if (ovfl[tn] || t->preovfl) {
-                               c->icr2 |= tn ? ICR_B : ICR_A;
-                               t->timer = t->latch;
+                               if (ovfl[tn]) {
+                                       if (ovfl[tn] > 1) {
+                                               c->icr2 |= tn ? ICR_B : ICR_A;
+                                               icr |= 1 << num;
+                                       }
+                                       t->timer = t->latch;
+                               }
                                if (!loaded[tn]) {
                                        if (t->cr & CR_RUNMODE) {
-                                               // if oneshot timer expires exactly when
-                                               // CR is written with START and ONESHOT set:
-                                               // timer does not stop.
-                                               if (!loaded2[tn]) {
+                                               if (loaded2[tn]) {
+                                                       t->loaddelay |= 0x00010000;
+                                               } else {
                                                        t->cr &= ~CR_START;
-                                                       if (!acc_mode()) {
-                                                               t->inputpipe = 0;
-                                                       }
+                                               }
+                                               if (!acc_mode()) {
+                                                       t->inputpipe = 0;
                                                }
                                                if (acc_mode()) {
                                                        t->inputpipe &= ~CIA_PIPE_CLR2;
@@ -613,7 +621,6 @@ static void CIA_update_check(void)
                                                }
                                        }
                                }
-                               icr |= 1 << num;
                                t->preovfl = false;
                        }
                }
@@ -1504,15 +1511,18 @@ static void CIA_thi_write(int num, int tnum, uae_u8 val)
                // if accurate mode: handle delays cycle-accurately
 
                if (!(t->cr & CR_START)) {
-                       t->loaddelay |= 1 << 1;
-                       t->loaddelay |= 1 << 2;
+                       t->loaddelay |= 0x00000001 << 1;
+                       t->loaddelay |= 0x00000001 << 2;
                }
 
                if (t->cr & CR_RUNMODE) {
                        t->cr |= CR_START;
+                       t->loaddelay |= 0x00000001 << 2;
+                       // timer=0 special case
                        t->loaddelay |= 0x01000000 << 1;
-                       t->loaddelay |= 1 << 2;
+                       t->loaddelay |= 0x10000000 << 1;
                }
+
        }
 }
 
@@ -1546,15 +1556,14 @@ static void CIA_cr_write(int num, int tnum, uae_u8 val)
 
                if (val & CR_LOAD) {
                        val &= ~CR_LOAD;
-                       t->loaddelay |= 0x0001 << 2;
-                       t->loaddelay |= 0x0100 << 0;
+                       t->loaddelay |= 0x00000001 << 2;
+                       t->loaddelay |= 0x00000100 << 0;
+                       t->loaddelay |= 0x00000100 << 1;
                        if (!(t->cr & CR_START)) {
-                               t->loaddelay |= 0x0001 << 1;
-                       }
-               } else {
-                       if ((val & CR_START)) {
-                               t->loaddelay |= 0x010000 << 0;
+                               t->loaddelay |= 0x00000001 << 1;
                        }
+                       // timer=0 special case
+                       t->loaddelay |= 0x10000000 << 1;
                }
 
                if (!(val & CR_START)) {