CIA latch/timer=0 special case update

This commit is contained in:
Toni Wilen 2023-07-25 20:56:03 +03:00
parent fe19d44193
commit 4f403c289a

89
cia.cpp
View File

@ -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)) {