Make rasterirq handler more resilient for timing glitches

This commit is contained in:
drmortalwombat 2025-06-11 09:34:21 +02:00
parent 5470db3a5f
commit 35a0b36a0d
4 changed files with 224 additions and 193 deletions

View File

@ -5,16 +5,16 @@
#include <c64/asm6502.h> #include <c64/asm6502.h>
#include <stdlib.h> #include <stdlib.h>
volatile char npos = 1, tpos = 0;
volatile byte rirq_count; volatile byte rirq_count;
static byte rirq_pcount;
byte rasterIRQRows[NUM_IRQS + 1]; byte rasterIRQRows[NUM_IRQS + 1];
byte rasterIRQIndex[NUM_IRQS + 1]; byte rasterIRQIndex[NUM_IRQS + 1]; // Sort order of interrupt index, offset by one
#ifdef ZPAGE_IRQS #ifdef ZPAGE_IRQS
__zeropage __zeropage
#endif #endif
byte rasterIRQNext[NUM_IRQS + 1]; byte rasterIRQNext[NUM_IRQS + 1]; // Rasterline of interrupt, terminated by 0xff
byte rasterIRQLow[NUM_IRQS]; byte rasterIRQLow[NUM_IRQS]; // Address of interrupt code
byte rasterIRQHigh[NUM_IRQS]; byte rasterIRQHigh[NUM_IRQS];
#ifdef ZPAGE_IRQS #ifdef ZPAGE_IRQS
@ -22,26 +22,25 @@ __zeropage
#endif #endif
byte nextIRQ; byte nextIRQ;
__asm irq0 // nextIRQ is the index of the next expected IRQ, or $ff if no IRQ is scheduled
__asm rirq_isr_ram_io
{ {
sta plra + 1
stx plrx + 1 stx plrx + 1
sty plry + 1
kentry:
asl $d019
ldx nextIRQ ldx nextIRQ
bmi exi
sta plra + 1
sty plry + 1
l1: l1:
lda rasterIRQNext, x lda rasterIRQNext, x
cmp #$ff
beq e1
ldy rasterIRQIndex + 1, x ldy rasterIRQIndex + 1, x
tax ldx rasterIRQLow, y
lda rasterIRQLow, y stx ji + 1
sta ji + 1 ldx rasterIRQHigh, y
lda rasterIRQHigh, y stx ji + 2
sta ji + 2
ji: ji:
jsr $0000 jsr $0000
@ -49,48 +48,105 @@ ji:
inc nextIRQ inc nextIRQ
ldx nextIRQ ldx nextIRQ
lda rasterIRQNext, x ldy rasterIRQNext, x
cmp #$ff
asl $d019
cpy #$ff
beq e2 beq e2
// carry is cleared at this point
tay
sbc #2
cmp $d012
bcc l1
exd:
dey dey
ex:
sty $d012 sty $d012
dey
cpy $d012
bcc l1
plry: plry:
ldy #0 ldy #0
plrx:
ldx #0
plra: plra:
lda #0 lda #0
plrx:
ldx #0
rti rti
exi:
asl $d019
jmp plrx
// No more interrupts to service
e2: e2:
ldx npos
stx tpos
inc rirq_count inc rirq_count
tay
bit $d011 ldy rasterIRQNext
bpl ex dey
sty $d012
e1:
ldx #0 ldx #0
stx nextIRQ stx nextIRQ
ldy rasterIRQNext beq plry
jmp exd
} }
__asm irq2 __asm rirq_isr_io
{
pha
txa
pha
tya
pha
kentry:
ldx nextIRQ
bmi exi
l1:
lda rasterIRQNext, x
ldy rasterIRQIndex + 1, x
ldx rasterIRQLow, y
stx ji + 1
ldx rasterIRQHigh, y
stx ji + 2
ji:
jsr $0000
inc nextIRQ
ldx nextIRQ
ldy rasterIRQNext, x
asl $d019
cpy #$ff
beq e2
dey
sty $d012
dey
cpy $d012
bcc l1
exd:
pla
tay
pla
tax
pla
rti
exi:
asl $d019
jmp exd
e2:
inc rirq_count
ldy rasterIRQNext
dey
sty $d012
ldx #0
stx nextIRQ
beq exd
}
__asm rirq_isr_noio
{ {
pha pha
txa txa
@ -104,20 +160,15 @@ kentry:
lda #$35 lda #$35
sta $01 sta $01
asl $d019
ldx nextIRQ ldx nextIRQ
bmi exi
l1: l1:
lda rasterIRQNext, x lda rasterIRQNext, x
cmp #$ff
beq e1
ldy rasterIRQIndex + 1, x ldy rasterIRQIndex + 1, x
tax ldx rasterIRQLow, y
lda rasterIRQLow, y stx ji + 1
sta ji + 1 ldx rasterIRQHigh, y
lda rasterIRQHigh, y stx ji + 2
sta ji + 2
ji: ji:
jsr $0000 jsr $0000
@ -125,21 +176,20 @@ ji:
inc nextIRQ inc nextIRQ
ldx nextIRQ ldx nextIRQ
lda rasterIRQNext, x ldy rasterIRQNext, x
cmp #$ff
beq e2 asl $d019
// carry is cleared at this point
cpy #$ff
beq e2
tay
dey dey
sbc #2 sty $d012
cmp $d012 dey
cpy $d012
bcc l1 bcc l1
sty $d012 exd:
ex:
pla pla
sta $01 sta $01
@ -150,45 +200,35 @@ ex:
pla pla
rti rti
e2: exi:
asl $d019
jmp exd
ldx npos e2:
stx tpos
inc rirq_count inc rirq_count
bit $d011
bmi e1
sta $d012
jmp ex
e1:
ldx #0
stx nextIRQ
ldy rasterIRQNext ldy rasterIRQNext
dey dey
sty $d012 sty $d012
jmp ex ldx #0
stx nextIRQ
beq exd
} }
__asm irq1 __asm rirq_isr_kernal_io
{ {
lda $d019 lda $d019
bpl ex2 bpl ex2
ldx nextIRQ ldx nextIRQ
bmi exi
l1: l1:
lda rasterIRQNext, x lda rasterIRQNext, x
cmp #$ff
beq e1
ldy rasterIRQIndex + 1, x ldy rasterIRQIndex + 1, x
tax ldx rasterIRQLow, y
lda rasterIRQLow, y stx ji + 1
sta ji + 1 ldx rasterIRQHigh, y
lda rasterIRQHigh, y stx ji + 2
sta ji + 2
ji: ji:
jsr $0000 jsr $0000
@ -197,45 +237,36 @@ jx:
inc nextIRQ inc nextIRQ
ldx nextIRQ ldx nextIRQ
lda rasterIRQNext, x ldy rasterIRQNext, x
cmp #$ff
beq e2
tay
sec
sbc #4
cmp $d012
bcc l1
dey
sty $d012
w1:
jmp ex
e2:
ldx npos
stx tpos
inc rirq_count
bit $d011
bmi e1
sta $d012
jmp ex
e1:
ldx #0
stx nextIRQ
lda rasterIRQNext, x
sec
sbc #1
sta $d012
ex:
asl $d019 asl $d019
cpy #$ff
beq e2
dey
dey
sty $d012
dey
cpy $d012
bcc l1
exd:
jmp $ea81
exi:
asl $d019
jmp $ea81
e2:
inc rirq_count
ldy rasterIRQNext
dey
dey
sty $d012
ldx #0
stx nextIRQ
jmp $ea81 jmp $ea81
ex2: ex2:
@ -244,7 +275,7 @@ ex2:
jmp $ea31 jmp $ea31
} }
__asm irq3 __asm rirq_isr_kernal_noio
{ {
lda $01 lda $01
pha pha
@ -255,17 +286,14 @@ __asm irq3
bpl ex2 bpl ex2
ldx nextIRQ ldx nextIRQ
bmi exi
l1: l1:
lda rasterIRQNext, x lda rasterIRQNext, x
cmp #$ff
beq e1
ldy rasterIRQIndex + 1, x ldy rasterIRQIndex + 1, x
tax ldx rasterIRQLow, y
lda rasterIRQLow, y stx ji + 1
sta ji + 1 ldx rasterIRQHigh, y
lda rasterIRQHigh, y stx ji + 2
sta ji + 2
ji: ji:
jsr $0000 jsr $0000
@ -274,49 +302,40 @@ jx:
inc nextIRQ inc nextIRQ
ldx nextIRQ ldx nextIRQ
lda rasterIRQNext, x ldy rasterIRQNext, x
cmp #$ff
asl $d019
cpy #$ff
beq e2 beq e2
tay dey
sec
sbc #4
cmp $d012
bcc l1
dey dey
sty $d012 sty $d012
w1: dey
jmp ex cpy $d012
bcc l1
e2: exd:
ldx npos
stx tpos
inc rirq_count
bit $d011
bmi e1
sta $d012
jmp ex
e1:
ldx #0
stx nextIRQ
lda rasterIRQNext, x
sec
sbc #1
sta $d012
ex:
asl $d019
pla pla
sta $01 sta $01
jmp $ea81 jmp $ea81
exi:
asl $d019
jmp exd
e2:
inc rirq_count
ldy rasterIRQNext
dey
dey
sty $d012
ldx #0
stx nextIRQ
beq exd
ex2: ex2:
LDA $DC0D LDA $DC0D
cli cli
@ -346,8 +365,8 @@ void rirq_build(RIRQCode * ic, byte size)
ic->size = size; ic->size = size;
asm_im(ic->code + 0, ASM_LDY, 0); asm_im(ic->code + 0, ASM_LDY, 0);
asm_im(ic->code + 2, ASM_LDA, 0); asm_im(ic->code + 2, ASM_LDX, 0);
asm_ab(ic->code + 4, ASM_CPX, 0xd012); asm_ab(ic->code + 4, ASM_CMP, 0xd012);
asm_rl(ic->code + 7, ASM_BCS, -5); asm_rl(ic->code + 7, ASM_BCS, -5);
asm_ab(ic->code + 9, ASM_STY, 0x0000); asm_ab(ic->code + 9, ASM_STY, 0x0000);
@ -361,7 +380,7 @@ void rirq_build(RIRQCode * ic, byte size)
} }
else else
{ {
asm_ab(ic->code + 12, ASM_STA, 0x0000); asm_ab(ic->code + 12, ASM_STX, 0x0000);
byte p = 15; byte p = 15;
for(byte i=2; i<size; i++) for(byte i=2; i<size; i++)
@ -481,7 +500,7 @@ void rirq_init_kernal(void)
sei sei
} }
*(void **)0x0314 = irq1; *(void **)0x0314 = rirq_isr_kernal_io;
vic.intr_enable = 1; vic.intr_enable = 1;
vic.ctrl1 &= 0x7f; vic.ctrl1 &= 0x7f;
@ -489,7 +508,7 @@ void rirq_init_kernal(void)
} }
void rirq_init_kernal_io(void) void rirq_init_kernal_noio(void)
{ {
rirq_init_tables(); rirq_init_tables();
@ -498,7 +517,7 @@ void rirq_init_kernal_io(void)
sei sei
} }
*(void **)0x0314 = irq3; *(void **)0x0314 = rirq_isr_kernal_noio;
vic.intr_enable = 1; vic.intr_enable = 1;
vic.ctrl1 &= 0x7f; vic.ctrl1 &= 0x7f;
@ -515,8 +534,8 @@ void rirq_init_crt(void)
sei sei
} }
*(void **)0x0314 = irq0.kentry; *(void **)0x0314 = rirq_isr_io.kentry;
*(void **)0xfffe = irq0; *(void **)0xfffe = rirq_isr_io;
vic.intr_enable = 1; vic.intr_enable = 1;
vic.ctrl1 &= 0x7f; vic.ctrl1 &= 0x7f;
@ -524,7 +543,7 @@ void rirq_init_crt(void)
} }
void rirq_init_crt_io(void) void rirq_init_crt_noio(void)
{ {
rirq_init_tables(); rirq_init_tables();
@ -533,8 +552,8 @@ void rirq_init_crt_io(void)
sei sei
} }
*(void **)0x0314 = irq2.kentry; *(void **)0x0314 = rirq_isr_noio.kentry;
*(void **)0xfffe = irq2; *(void **)0xfffe = rirq_isr_noio;
vic.intr_enable = 1; vic.intr_enable = 1;
vic.ctrl1 &= 0x7f; vic.ctrl1 &= 0x7f;
@ -551,7 +570,7 @@ void rirq_init_io(void)
sei sei
} }
*(void **)0xfffe = irq0; *(void **)0xfffe = rirq_isr_ram_io;
vic.intr_enable = 1; vic.intr_enable = 1;
vic.ctrl1 &= 0x7f; vic.ctrl1 &= 0x7f;
@ -568,7 +587,7 @@ void rirq_init_memmap(void)
sei sei
} }
*(void **)0xfffe = irq2; *(void **)0xfffe = rirq_isr_noio;
vic.intr_enable = 1; vic.intr_enable = 1;
vic.ctrl1 &= 0x7f; vic.ctrl1 &= 0x7f;
@ -586,12 +605,18 @@ void rirq_init(bool kernalIRQ)
void rirq_wait(void) void rirq_wait(void)
{ {
while (tpos != npos) ; char i0 = rirq_pcount;
npos++; char i1;
do {
i1 = rirq_count;
} while (i0 == i1);
rirq_pcount = i1;
} }
void rirq_sort(bool inirq) void rirq_sort(bool inirq)
{ {
// disable raster interrupts while sorting
nextIRQ = 0xff;
#if 1 #if 1
byte maxr = rasterIRQRows[rasterIRQIndex[1]]; byte maxr = rasterIRQRows[rasterIRQIndex[1]];
for(byte i = 2; i<NUM_IRQS + 1; i++) for(byte i = 2; i<NUM_IRQS + 1; i++)
@ -639,15 +664,17 @@ void rirq_sort(bool inirq)
} }
#endif #endif
npos++; rirq_pcount = rirq_count;
if (inirq) if (inirq)
nextIRQ = NUM_IRQS - 1; nextIRQ = NUM_IRQS - 1;
else else
{ {
nextIRQ = 0; byte yp = rasterIRQNext[0];
byte yp = rasterIRQNext[nextIRQ];
if (yp != 0xff) if (yp != 0xff)
{
vic.raster = yp - 1; vic.raster = yp - 1;
nextIRQ = 0;
}
} }
} }

View File

@ -154,7 +154,7 @@ void rirq_init_kernal(void);
// Raster IRQ through kernal, with IO range not always enabled // Raster IRQ through kernal, with IO range not always enabled
// calls kernal continuation // calls kernal continuation
void rirq_init_kernal_io(void); void rirq_init_kernal_noio(void);
// Raster IRQ through RAM and ROM vector, with ROM disabled or not and IO range always enabled // Raster IRQ through RAM and ROM vector, with ROM disabled or not and IO range always enabled
// does not call kernal continuation // does not call kernal continuation
@ -162,7 +162,7 @@ void rirq_init_crt(void);
// Raster IRQ through RAM and ROM vector, with ROM disabled or not and IO range not always enabled // Raster IRQ through RAM and ROM vector, with ROM disabled or not and IO range not always enabled
// does not call kernal continuation // does not call kernal continuation
void rirq_init_crt_io(void); void rirq_init_crt_noio(void);
// Raster IRQ through RAM vector, with ROM disabled and IO range always enabled // Raster IRQ through RAM vector, with ROM disabled and IO range always enabled
// does not call kernal continuation // does not call kernal continuation

View File

@ -22,7 +22,7 @@ __interrupt void doscroll(void)
vic.color_border++; vic.color_border++;
// Update raster IRQ for scroll line with new horizontal scroll offset // Update raster IRQ for scroll line with new horizontal scroll offset
rirq_data(&scroll, 0, 7 - (x & 7)); rirq_data(&scroll, 1, 7 - (x & 7));
// Copy scrolled version of text when switching over char border // Copy scrolled version of text when switching over char border
if ((x & 7) == 0) if ((x & 7) == 0)
memcpy((char *)0x0400 + 40 * 24, Text + ((x >> 3) & 255), 40); memcpy((char *)0x0400 + 40 * 24, Text + ((x >> 3) & 255), 40);
@ -37,11 +37,13 @@ int main(void)
rirq_init(true); rirq_init(true);
// Build switch to scroll line IRQ // Build switch to scroll line IRQ
rirq_build(&scroll, 1); rirq_build(&scroll, 2);
// Delay for one line to get to right border
rirq_delay(&scroll, 11);
// Change control register two with this IRQ // Change control register two with this IRQ
rirq_write(&scroll, 0, &vic.ctrl2, 0); rirq_write(&scroll, 1, &vic.ctrl2, 0);
// Put it onto the scroll line // Put it onto the scroll line
rirq_set(0, 50 + 24 * 8, &scroll); rirq_set(0, 49 + 24 * 8, &scroll);
// Build the switch to normal IRQ // Build the switch to normal IRQ
rirq_build(&restore, 2); rirq_build(&restore, 2);

View File

@ -20,11 +20,13 @@ int main(void)
rirq_init(true); rirq_init(true);
// Build switch to scroll line IRQ // Build switch to scroll line IRQ
rirq_build(&scroll, 1); rirq_build(&scroll, 2);
// Delay for one line to get to right border
rirq_delay(&scroll, 11);
// Change control register two with this IRQ // Change control register two with this IRQ
rirq_write(&scroll, 0, &vic.ctrl2, 0); rirq_write(&scroll, 1, &vic.ctrl2, 0);
// Put it onto the scroll line // Put it onto the scroll line
rirq_set(0, 50 + 24 * 8, &scroll); rirq_set(0, 49 + 24 * 8, &scroll);
// Build the switch to normal IRQ // Build the switch to normal IRQ
rirq_build(&bottom, 1); rirq_build(&bottom, 1);
@ -46,7 +48,7 @@ int main(void)
// wait for raster reaching bottom of screen // wait for raster reaching bottom of screen
rirq_wait(); rirq_wait();
// Update raster IRQ for scroll line with new horizontal scroll offset // Update raster IRQ for scroll line with new horizontal scroll offset
rirq_data(&scroll, 0, 7 - (x & 7)); rirq_data(&scroll, 1, 7 - (x & 7));
// Copy scrolled version of text when switching over char border // Copy scrolled version of text when switching over char border
if ((x & 7) == 0) if ((x & 7) == 0)
memcpy((char *)0x0400 + 40 * 24, Text + ((x >> 3) & 255), 40); memcpy((char *)0x0400 + 40 * 24, Text + ((x >> 3) & 255), 40);