Move raster interrupt into assembly file. Set as an interruptor to

bypass C stuff.
This commit is contained in:
Empathic Qubit 2021-10-09 20:39:59 +02:00
parent 689854ffab
commit 690f50c9f4
2 changed files with 282 additions and 214 deletions

View file

@ -8,8 +8,6 @@
#include "c64.h" #include "c64.h"
#include <errno.h> #include <errno.h>
#define IRQ_STACK_SIZE 128
extern void updatepalntsc(void); extern void updatepalntsc(void);
/* Check if system is PAL /* Check if system is PAL
@ -18,16 +16,9 @@ void pal_system(void) {
updatepalntsc(); updatepalntsc();
} }
unsigned char* irq_stack;
#define SCREEN_LAST_RASTER SCREEN_SPRITE_BORDER_Y_START + SCREEN_BITMAP_HEIGHT
#define SPRITE_BUFFER_LINE_COUNT 8
#define SPRITE_BUFFER_LINE_HEIGHT (SCREEN_BITMAP_HEIGHT / SPRITE_BUFFER_LINE_COUNT)
#define SCREEN_FIRST_RASTER SCREEN_SPRITE_BORDER_Y_START - SPRITE_BUFFER_LINE_HEIGHT
/** Disable the IO page /** Disable the IO page
*/ */
void __fastcall__ hide_io(void) { void hide_io(void) {
*(unsigned char *)CIA1_CRA &= ~CIA1_CR_START_STOP; *(unsigned char *)CIA1_CRA &= ~CIA1_CR_START_STOP;
*(unsigned char *)CPU_PORT &= ~CPU_PORT_BANK_IO_VISIBLE_CHARACTER_ROM_INVISIBLE; *(unsigned char *)CPU_PORT &= ~CPU_PORT_BANK_IO_VISIBLE_CHARACTER_ROM_INVISIBLE;
@ -35,7 +26,7 @@ void __fastcall__ hide_io(void) {
/** Enable the IO page /** Enable the IO page
*/ */
void __fastcall__ show_io(void) { void show_io(void) {
*(unsigned char *)CPU_PORT |= CPU_PORT_BANK_IO_VISIBLE_CHARACTER_ROM_INVISIBLE; *(unsigned char *)CPU_PORT |= CPU_PORT_BANK_IO_VISIBLE_CHARACTER_ROM_INVISIBLE;
*(unsigned char *)CIA1_CRA |= CIA1_CR_START_STOP; *(unsigned char *)CIA1_CRA |= CIA1_CR_START_STOP;
@ -71,7 +62,7 @@ void screen_init (bool clear) {
VIC.addr |= ((CHARACTER_START % VIC_BANK_SIZE) / VIC_VIDEO_ADR_CHAR_DIVISOR) << 1; VIC.addr |= ((CHARACTER_START % VIC_BANK_SIZE) / VIC_VIDEO_ADR_CHAR_DIVISOR) << 1;
// Fix HLINE IRQ // Fix HLINE IRQ
VIC.rasterline = SCREEN_FIRST_RASTER; VIC.rasterline = 0xff;
VIC.ctrl1 &= ~VIC_CTRL1_HLINE_MSB; VIC.ctrl1 &= ~VIC_CTRL1_HLINE_MSB;
// Switch off bitmap mode // Switch off bitmap mode
@ -95,20 +86,12 @@ void screen_init (bool clear) {
} }
bool is_pal = false; bool is_pal = false;
bool irq_setup_done = false;
unsigned char setup_irq_handler(unsigned char (*handler)(void)) { unsigned char setup_irq_handler(void) {
if(!irq_stack) { irq_setup_done = true;
if(!(irq_stack = malloc(IRQ_STACK_SIZE))) {
return EXIT_FAILURE;
}
}
set_irq(handler, irq_stack, IRQ_STACK_SIZE);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
unsigned char raster_clock = 0;
unsigned int game_clock = 0; unsigned int game_clock = 0;
unsigned int last_updated = 0; unsigned int last_updated = 0;
@ -237,25 +220,31 @@ void set_sprite_graphic(sprite_handle handle, unsigned char sheet_index) {
set_sprite_pointer(handle, ((unsigned int)(&s->sprites[sheet_index]) % VIC_BANK_SIZE) / VIC_SPR_SIZE); set_sprite_pointer(handle, ((unsigned int)(&s->sprites[sheet_index]) % VIC_BANK_SIZE) / VIC_SPR_SIZE);
} }
void set_sprite_position(sprite_handle a, unsigned int x, unsigned char y) { void set_sprite_x(sprite_handle a, unsigned int x) {
static sprite_handle *start_handle, *comp_handle, *current_handle; static sprite_handle arg;
static sprite_handle arg, comp;
static unsigned char index, last_index, hi_mask, comp_y, yarg;
static bool direction;
yarg = y;
arg = a; arg = a;
comp_y = arg->lo_y;
hi_mask = 1<<(index%VIC_SPR_COUNT);
if(x>>8) { if(x>>8) {
arg->hi_x = hi_mask; arg->hi_x = arg->ena;
} }
else { else {
arg->hi_x = 0; arg->hi_x = 0;
} }
arg->lo_x = (unsigned char)x; arg->lo_x = (unsigned char)x;
}
void set_sprite_y(sprite_handle a, unsigned char y) {
static sprite_handle *start_handle, *comp_handle, *current_handle;
static sprite_handle arg, comp;
static unsigned char index, last_index, hi_mask, comp_y, yarg;
static bool direction, is_last;
yarg = y;
arg = a;
comp_y = arg->lo_y;
if(yarg == comp_y) { if(yarg == comp_y) {
return; return;
} }
@ -288,19 +277,18 @@ void set_sprite_position(sprite_handle a, unsigned int x, unsigned char y) {
do { do {
if(direction) { if(direction) {
comp_handle = current_handle + 1; comp_handle = current_handle + 1;
comp = *comp_handle;
is_last = (yarg <= comp->lo_y
|| index == last_index);
} }
else { else {
comp_handle = current_handle - 1; comp_handle = current_handle - 1;
comp = *comp_handle;
is_last = (comp->lo_y <= yarg
|| index == 0);
} }
comp = *comp_handle;
if(( if(is_last) {
direction
? (yarg <= comp->lo_y
|| index == last_index)
: (comp->lo_y <= yarg
|| index == 0)
)
) {
if(current_handle == start_handle) { if(current_handle == start_handle) {
break; break;
} }
@ -326,7 +314,7 @@ void set_sprite_position(sprite_handle a, unsigned int x, unsigned char y) {
__asm__("sbc #%b", offsetof(struct sprite_data, multi)); __asm__("sbc #%b", offsetof(struct sprite_data, multi));
__asm__("bne loop"); __asm__("bne loop");
if(comp == arg) { if(is_last) {
*current_handle = comp; *current_handle = comp;
break; break;
} }
@ -336,33 +324,37 @@ void set_sprite_position(sprite_handle a, unsigned int x, unsigned char y) {
if(direction) { if(direction) {
index++; index++;
}
else {
index--;
}
if(direction) {
current_handle++; current_handle++;
} }
else { else {
index--;
current_handle--; current_handle--;
} }
} while (true); } while (true);
} }
void discard_sprite(sprite_handle handle) { void discard_sprite(sprite_handle handle) {
set_sprite_position(handle, 0xff, 0xff);
sprite_count--; sprite_count--;
_sprite_list[sprite_count] = NULL; _sprite_list[sprite_count] = NULL;
set_sprite_x(handle, 0xff);
set_sprite_y(handle, 0xff);
} }
sprite_handle new_sprite(bool dbl) { sprite_handle new_sprite(bool dbl) {
static sprite_handle handle; static sprite_handle handle;
static unsigned char hi_mask;
handle = &_sprite_pool[sprite_count]; handle = &_sprite_pool[sprite_count];
_sprite_list[sprite_count] = handle; _sprite_list[sprite_count] = handle;
handle->dbl = dbl<<(sprite_count%VIC_SPR_COUNT); hi_mask = 1<<(sprite_count%VIC_SPR_COUNT);
handle->ena = 1<<(sprite_count%VIC_SPR_COUNT); handle->ena = hi_mask;
if(dbl) {
handle->dbl = hi_mask;
}
else {
handle->dbl = 0;
}
handle->lo_x = 0xfe; handle->lo_x = 0xfe;
handle->lo_y = 0xfe; handle->lo_y = 0xfe;
sprite_count++; sprite_count++;
@ -370,150 +362,6 @@ sprite_handle new_sprite(bool dbl) {
return handle; return handle;
} }
#define SPR_POINTERS SCREEN_START + 0x3F8
unsigned char main_raster_irq(void) {
static unsigned char sprite_index = 0xff;
static unsigned char vic_sprite = 0;
static unsigned char current_y = 0;
static unsigned char new_y = 0;
static unsigned char hi_mask = 0;
static sprite_handle cs;
if(!(VIC.irr & VIC_IRQ_RASTER)) {
return IRQ_NOT_HANDLED;
}
VIC.irr |= VIC_IRQ_RASTER;
if(sprite_index == 0xff) {
sprite_index = 0;
vic_sprite = 0;
// NTSC frame skip
if(is_pal) {
game_clock++;
}
else if(++raster_clock < 6) {
game_clock++;
}
else {
raster_clock = 0;
}
}
cs = _sprite_list[sprite_index];
new_y = cs->lo_y;
do {
current_y = new_y;
hi_mask = ~(1<<vic_sprite);
#define himasker(dest) { \
__asm__("lda %w", dest); \
__asm__("and %v", hi_mask); \
__asm__("ora (ptr1),Y"); \
__asm__("sta %w", dest); \
}
__asm__("lda %v", cs);
__asm__("ldx %v+1", cs);
__asm__("sta ptr1");
__asm__("stx ptr1+1");
__asm__("ldy #%b", offsetof(struct sprite_data, color));
__asm__("ldx %v", vic_sprite);
__asm__("lda (ptr1),Y");
__asm__("sta %w,X", VIC_SPR0_COLOR);
__asm__("iny");
__asm__("lda (ptr1),Y");
__asm__("sta %w,X", SPR_POINTERS);
__asm__("txa");
__asm__("asl");
__asm__("tax");
__asm__("iny");
__asm__("lda (ptr1),Y");
__asm__("sta %w,X", VIC_SPR0_X);
__asm__("iny");
__asm__("lda (ptr1),Y");
__asm__("sta %w,X", VIC_SPR0_Y);
__asm__("tax");
__asm__("inx");
__asm__("stx %w", VIC_HLINE);
__asm__("iny");
himasker(VIC_SPR_ENA);
__asm__("iny");
himasker(VIC_SPR_HI_X);
__asm__("iny");
himasker(VIC_SPR_EXP_X);
__asm__("sta %w", VIC_SPR_EXP_Y);
__asm__("iny");
himasker(VIC_SPR_MCOLOR);
vic_sprite++;
if(vic_sprite >= VIC_SPR_COUNT) {
vic_sprite = 0;
}
// sprite_index++
__asm__("ldx %v", sprite_index);
__asm__("inx");
__asm__("txa");
// if(sprite_index == sprite_count)
__asm__("cmp %v", sprite_count);
// else
__asm__("bne moarcs");
// then
__asm__("lda #$ff");
__asm__("sta %v", sprite_index);
__asm__("sta %w", VIC_HLINE);
return IRQ_HANDLED;
// store the new sprite index
__asm__("moarcs:");
__asm__("sta %v", sprite_index);
__asm__("asl");
__asm__("tax");
// cs = _sprite_list[sprite_index]
__asm__("ldy %v,X", _sprite_list);
__asm__("sty %v", cs);
__asm__("sty ptr1");
__asm__("inx");
__asm__("ldy %v,X", _sprite_list);
__asm__("sty %v+1", cs);
__asm__("sty ptr1+1");
// new_y = cs->lo_y
__asm__("ldy #%b", offsetof(struct sprite_data, lo_y));
__asm__("lda (ptr1),Y");
__asm__("sta %v", new_y);
// if new_y >= current_y + buffer
__asm__("lda %v", current_y);
__asm__("clc");
__asm__("adc #%b", VIC_SPR_HEIGHT - 2);
__asm__("cmp %v", new_y);
__asm__("bcc exitloop");
} while(true);
__asm__("exitloop: ");
return IRQ_HANDLED;
}
#define WAW_SPRITE_COUNT 9 #define WAW_SPRITE_COUNT 9
#define WAW_SPRITE_OFFSET 0 #define WAW_SPRITE_OFFSET 0
#define WAW_COLUMNS 3 #define WAW_COLUMNS 3
@ -536,7 +384,8 @@ struct waw {
typedef struct waw waw; typedef struct waw waw;
void init_waw(waw* w) { void init_waw(waw* w) {
static unsigned char i, j, x, y, sprite_x, sprite_y, idx; static unsigned int x, sprite_x;
static unsigned char i, j, y, sprite_y, idx;
static waw* waw; static waw* waw;
static sprite_handle sprite; static sprite_handle sprite;
static sprite_handle* sprites; static sprite_handle* sprites;
@ -556,10 +405,12 @@ void init_waw(waw* w) {
sprite = new_sprite(true); sprite = new_sprite(true);
set_sprite_graphic(sprite, WAW_SPRITE_OFFSET + idx); set_sprite_graphic(sprite, WAW_SPRITE_OFFSET + idx);
if(idx == WAW_MOUTHINDEX) { if(idx == WAW_MOUTHINDEX) {
set_sprite_position(sprite, sprite_x, sprite_y + waw->mouth_offset); set_sprite_x(sprite, sprite_x);
set_sprite_y(sprite, sprite_y + waw->mouth_offset);
} }
else { else {
set_sprite_position(sprite, sprite_x, sprite_y); set_sprite_x(sprite, sprite_x);
set_sprite_y(sprite, sprite_y);
} }
sprites[idx] = sprite; sprites[idx] = sprite;
idx++; idx++;
@ -568,11 +419,10 @@ void init_waw(waw* w) {
} }
void update_waw(waw* w) { void update_waw(waw* w) {
static unsigned int sprite_x; static unsigned char y;
static unsigned char y, sprite_y;
static unsigned char idx; static unsigned char idx;
static signed char change_y, mouth_offset; static signed char change_y, mouth_offset;
static sprite_handle* current_sprite; static sprite_handle* sprites;
static sprite_handle sprite; static sprite_handle sprite;
static waw* waw; static waw* waw;
waw = w; waw = w;
@ -613,27 +463,22 @@ void update_waw(waw* w) {
waw->y = y + change_y; waw->y = y + change_y;
current_sprite = waw->sprites; sprites = waw->sprites;
for(idx = 0; idx < WAW_SPRITE_COUNT; idx++) { for(idx = 0; idx < WAW_SPRITE_COUNT; idx++) {
sprite = *current_sprite; sprite = sprites[idx];
((unsigned char*)&sprite_x)[0] = sprite->lo_x;
((unsigned char*)&sprite_x)[1] = sprite->hi_x;
sprite_y = sprite->lo_y + change_y;
// Mouth // Mouth
if(idx == WAW_MOUTHINDEX) { if(idx == WAW_MOUTHINDEX) {
set_sprite_position(sprite, sprite_x, current_sprite[-1]->lo_y + mouth_offset); set_sprite_y(sprite, sprites[idx-1]->lo_y + mouth_offset);
} }
else { else {
set_sprite_position(sprite, sprite_x, sprite_y); set_sprite_y(sprite, sprite->lo_y + change_y);
} }
current_sprite++;
} }
} }
unsigned char main(void) { unsigned char main(void) {
static unsigned char err; static unsigned char err;
//static waw waw2 = {VIC_SPR_WIDTH * WAW_COLUMNS * 2,VIC_SPR_HEIGHT * 2,0,true,true}; static waw waw2 = {VIC_SPR_WIDTH * WAW_COLUMNS * 2,VIC_SPR_HEIGHT * 2,0,true,true};
static waw waw = {0,0,0,true,true}; static waw waw = {0,0,0,true,true};
updatepalntsc(); updatepalntsc();
@ -646,10 +491,10 @@ unsigned char main(void) {
init_sprite_pool(); init_sprite_pool();
init_waw(&waw); init_waw(&waw);
//init_waw(&waw2); init_waw(&waw2);
character_init(true); character_init(true);
setup_irq_handler(&main_raster_irq); setup_irq_handler();
screen_init(true); screen_init(true);
do { do {
@ -658,7 +503,7 @@ unsigned char main(void) {
} }
update_waw(&waw); update_waw(&waw);
//update_waw(&waw2); update_waw(&waw2);
last_updated++; last_updated++;
} while(true); } while(true);

223
src/main_raster_irq_asm.s Normal file
View file

@ -0,0 +1,223 @@
.macpack longbranch
.import __sprite_list, _irq_setup_done, _is_pal, _game_clock, _sprite_count, _main_raster_irq
.importzp ptr1
.include "c64.inc"
.interruptor raster_irq, 2
.define IRQ_NOT_HANDLED #$00
.define IRQ_HANDLED #$01
.define VIC_IRQ_RASTER #$01
; FIXME
.define SPR_POINTERS $C000+$3F8
.define VIC_SPR_COUNT #$8
.define VIC_SPR_HEIGHT #$21
; ARG A = sprite index
; SETS ptr1 and current_sprite to sprite at index in list
; SETS A and new_y to sprite's y value
.macro get_next_sprite
asl
tax
ldy __sprite_list,X
sty current_sprite
sty ptr1
inx
ldy __sprite_list,X
sty current_sprite+1
sty ptr1+1
ldy #$03 ; FIXME offsetof(lo_y)
lda (ptr1),Y
sta new_y
.endmacro
.macro himasker dest
lda dest
and hi_mask
ora (ptr1),Y
sta dest
.endmacro
.segment "DATA"
ptr1_save: .res 2
sprite_index: .byte $ff
vic_sprite: .byte $00
current_y: .byte $00
new_y: .byte $00
hi_mask: .byte $00
current_sprite: .res 2
raster_clock: .byte $06
.segment "CODE"
.proc main_raster_irq
; Make sure this is a raster interrupt and we're ready
lda _irq_setup_done
jeq unhandled
lda VIC_IRQ_RASTER
bit VIC_IRR
jeq unhandled
; set the flag so we know we've handled it
ora VIC_IRR
sta VIC_IRR
; if we're at the beginning of the sprite loop, initialize the variables
lda sprite_index
cmp #$ff
bne sprite_index_updated
lda #$00
sta sprite_index
sta vic_sprite
; If we're PAL, the game clock is already 50hz
ldx _is_pal
bne update_game_clock
; If we're NTSC, skip every 6th frame
dec raster_clock
bne update_game_clock
; Reset the raster clock
ldx #$06
stx raster_clock
jmp sprite_index_updated
update_game_clock:
inc _game_clock
bne sprite_index_updated
inc _game_clock+1
sprite_index_updated:
get_next_sprite
sprite_update_loop:
; set the current sprite y value
lda new_y
sta current_y
lda #$01
ldx vic_sprite
beq done
shift:
asl
dex
bne shift
done:
eor #$ff
sta hi_mask
; prep the pointer for struct access
lda current_sprite
ldx current_sprite+1
sta ptr1
stx ptr1+1
ldy #$00 ; FIXME offsetof(color)
; store color and pointer into arrays
ldx vic_sprite
lda (ptr1),y
sta VIC_SPR0_COLOR,X
iny
lda (ptr1),y
sta SPR_POINTERS,X
; inc vic_sprite for next loop
inx
txa
cmp VIC_SPR_COUNT
bne write_vic_sprite
lda #$00
write_vic_sprite:
sta vic_sprite
; Double the previous value of vic_sprite and use it to set the x and y
dex
txa
asl
tax
iny
lda (ptr1),y
sta VIC_SPR0_X,X
iny
lda (ptr1),Y
sta VIC_SPR0_Y,x
tax
inx
stx VIC_HLINE
iny
himasker VIC_SPR_ENA
iny
himasker VIC_SPR_HI_X
iny
himasker VIC_SPR_EXP_X
sta VIC_SPR_EXP_Y
iny
himasker VIC_SPR_MCOLOR
; inc sprite_index
ldx sprite_index
inx
txa
cmp _sprite_count
bne moarcs
; if the index equals the count, reset
lda #$ff
sta sprite_index
sta VIC_HLINE
jmp end_sprite_update_loop
moarcs:
sta sprite_index
get_next_sprite
; if new_y >= current_y + buffer
lda current_y
clc
adc VIC_SPR_HEIGHT-$2
cmp new_y
jcs sprite_update_loop
end_sprite_update_loop:
handled:
lda IRQ_HANDLED
rts
unhandled:
lda IRQ_NOT_HANDLED
rts
.endproc
.proc raster_irq
lda ptr1
ldx ptr1+1
sta ptr1_save
stx ptr1_save+1
clc
jsr main_raster_irq
; mark interrupt as handled / unhandled
lsr
lda ptr1_save
ldx ptr1_save+1
sta ptr1
stx ptr1+1
rts
.endproc