From 4f403c289adf3d9a0a632546f64b062b1df74d51 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Tue, 25 Jul 2023 20:56:03 +0300 Subject: [PATCH] CIA latch/timer=0 special case update --- cia.cpp | 89 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/cia.cpp b/cia.cpp index 49c01624..a29eb5fa 100644 --- 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)) { -- 2.47.3