1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-08-10 11:25:09 +00:00
Files
kickc/src/test/ref/examples/multiplexer/simple-multiplexer.asm
jespergravgaard 1836a9bd92 Finally eliminated copy visitor!
Refactored CallPhiParameters to modify the current control flow graph.
2020-03-07 22:38:40 +01:00

367 lines
8.8 KiB
NASM

// A simple usage of the flexible sprite multiplexer routine
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SPRITES_XPOS = $d000
.label SPRITES_YPOS = $d001
.label SPRITES_XMSB = $d010
.label RASTER = $d012
.label SPRITES_ENABLE = $d015
.label BORDERCOL = $d020
.label SPRITES_COLS = $d027
.label D011 = $d011
.const VIC_RST8 = $80
.const VIC_DEN = $10
.const VIC_RSEL = 8
// The colors of the C64
.const BLACK = 0
.const GREEN = 5
// The number of sprites in the multiplexer
.const PLEX_COUNT = $20
// Location of screen & sprites
.label SCREEN = $400
.label SPRITE = $2000
// The address of the sprite pointers on the current screen (screen+$3f8).
.label PLEX_SCREEN_PTR = SCREEN+$3f8
// The MSB bit of the next sprite to use for showing
.label plex_sprite_msb = 3
// The index of the sprite that is free next. Since sprites are used round-robin this moves forward each time a sprite is shown.
.label plex_free_next = 5
// The index the next sprite to use for showing (sprites are used round-robin)
.label plex_sprite_idx = 9
// The index in the PLEX tables of the next sprite to show
// Prepare for showing the sprites
.label plex_show_idx = $a
// kickasm
main: {
// asm
sei
// init()
jsr init
// loop()
jsr loop
// }
rts
}
// The raster loop
loop: {
// The current index into the y-sinus
.label sin_idx = 2
.label plexFreeNextYpos1_return = 8
.label ss = 4
lda #0
sta.z sin_idx
__b2:
// while(*RASTER!=$ff)
lda #$ff
cmp RASTER
bne __b2
// (*BORDERCOL)++;
inc BORDERCOL
ldx.z sin_idx
ldy #0
__b4:
// PLEX_YPOS[sy] = YSIN[y_idx]
lda YSIN,x
sta PLEX_YPOS,y
// y_idx += 8
txa
axs #-[8]
// for(byte sy: 0..PLEX_COUNT-1)
iny
cpy #PLEX_COUNT-1+1
bne __b4
// sin_idx +=1
inc.z sin_idx
// (*BORDERCOL)++;
inc BORDERCOL
// plexSort()
jsr plexSort
// *BORDERCOL = BLACK
lda #BLACK
sta BORDERCOL
__b6:
// *D011&VIC_RST8
lda #VIC_RST8
and D011
// while((*D011&VIC_RST8)!=0)
cmp #0
bne __b6
lda #0
sta.z ss
lda #1
sta.z plex_sprite_msb
lda #0
sta.z plex_show_idx
sta.z plex_sprite_idx
sta.z plex_free_next
// Show the sprites
__b7:
// *BORDERCOL = BLACK
lda #BLACK
sta BORDERCOL
// return PLEX_FREE_YPOS[plex_free_next];
ldy.z plex_free_next
lda PLEX_FREE_YPOS,y
sta.z plexFreeNextYpos1_return
__b8:
// while(*RASTER<rasterY)
lda RASTER
cmp.z plexFreeNextYpos1_return
bcc __b8
// (*BORDERCOL)++;
inc BORDERCOL
// plexShowSprite()
jsr plexShowSprite
// for( byte ss: 0..PLEX_COUNT-1)
inc.z ss
lda #PLEX_COUNT-1+1
cmp.z ss
bne __b7
// *BORDERCOL = BLACK
lda #BLACK
sta BORDERCOL
jmp __b2
}
// Show the next sprite.
// plexSort() prepares showing the sprites
plexShowSprite: {
.label plex_sprite_idx2 = 8
// plex_sprite_idx2 = plex_sprite_idx*2
lda.z plex_sprite_idx
asl
sta.z plex_sprite_idx2
// ypos = PLEX_YPOS[PLEX_SORTED_IDX[plex_show_idx]]
ldx.z plex_show_idx
ldy PLEX_SORTED_IDX,x
lda PLEX_YPOS,y
// SPRITES_YPOS[plex_sprite_idx2] = ypos
ldy.z plex_sprite_idx2
sta SPRITES_YPOS,y
// ypos+21
clc
adc #$15
// PLEX_FREE_YPOS[plex_free_next] = ypos+21
ldy.z plex_free_next
sta PLEX_FREE_YPOS,y
// plex_free_next+1
ldx.z plex_free_next
inx
// plex_free_next = (plex_free_next+1)&7
lda #7
sax.z plex_free_next
// PLEX_SCREEN_PTR[plex_sprite_idx] = PLEX_PTR[PLEX_SORTED_IDX[plex_show_idx]]
ldx.z plex_show_idx
ldy PLEX_SORTED_IDX,x
lda PLEX_PTR,y
ldx.z plex_sprite_idx
sta PLEX_SCREEN_PTR,x
// xpos_idx = PLEX_SORTED_IDX[plex_show_idx]
ldy.z plex_show_idx
lda PLEX_SORTED_IDX,y
// <PLEX_XPOS[xpos_idx]
asl
tax
lda PLEX_XPOS,x
// SPRITES_XPOS[plex_sprite_idx2] = <PLEX_XPOS[xpos_idx]
ldy.z plex_sprite_idx2
sta SPRITES_XPOS,y
// >PLEX_XPOS[xpos_idx]
lda PLEX_XPOS+1,x
// if(>PLEX_XPOS[xpos_idx]!=0)
cmp #0
bne __b1
// $ff^plex_sprite_msb
lda #$ff
eor.z plex_sprite_msb
// *SPRITES_XMSB &= ($ff^plex_sprite_msb)
and SPRITES_XMSB
sta SPRITES_XMSB
__b2:
// plex_sprite_idx+1
ldx.z plex_sprite_idx
inx
// plex_sprite_idx = (plex_sprite_idx+1)&7
lda #7
sax.z plex_sprite_idx
// plex_show_idx++;
inc.z plex_show_idx
// plex_sprite_msb *=2
asl.z plex_sprite_msb
// if(plex_sprite_msb==0)
lda.z plex_sprite_msb
cmp #0
bne __b5
lda #1
sta.z plex_sprite_msb
rts
__b5:
// }
rts
__b1:
// *SPRITES_XMSB |= plex_sprite_msb
lda SPRITES_XMSB
ora.z plex_sprite_msb
sta SPRITES_XMSB
jmp __b2
}
// Ensure that the indices in PLEX_SORTED_IDX is sorted based on the y-positions in PLEX_YPOS
// Assumes that the positions are nearly sorted already (as each sprite just moves a bit)
// Uses an insertion sort:
// 1. Moves a marker (m) from the start to end of the array. Every time the marker moves forward all elements before the marker are sorted correctly.
// 2a. If the next element after the marker is larger that the current element
// the marker can be moved forwards (as the sorting is correct).
// 2b. If the next element after the marker is smaller than the current element:
// elements before the marker are shifted right one at a time until encountering one smaller than the current one.
// It is then inserted at the spot. Now the marker can move forward.
plexSort: {
.label nxt_idx = 9
.label nxt_y = $a
.label m = 5
lda #0
sta.z m
__b1:
// nxt_idx = PLEX_SORTED_IDX[m+1]
ldy.z m
lda PLEX_SORTED_IDX+1,y
sta.z nxt_idx
// nxt_y = PLEX_YPOS[nxt_idx]
tay
lda PLEX_YPOS,y
sta.z nxt_y
// if(nxt_y<PLEX_YPOS[PLEX_SORTED_IDX[m]])
ldx.z m
ldy PLEX_SORTED_IDX,x
cmp PLEX_YPOS,y
bcs __b2
__b3:
// PLEX_SORTED_IDX[s+1] = PLEX_SORTED_IDX[s]
lda PLEX_SORTED_IDX,x
sta PLEX_SORTED_IDX+1,x
// s--;
dex
// while((s!=$ff) && (nxt_y<PLEX_YPOS[PLEX_SORTED_IDX[s]]))
cpx #$ff
beq __b4
lda.z nxt_y
ldy PLEX_SORTED_IDX,x
cmp PLEX_YPOS,y
bcc __b3
__b4:
// s++;
inx
// PLEX_SORTED_IDX[s] = nxt_idx
lda.z nxt_idx
sta PLEX_SORTED_IDX,x
__b2:
// for(byte m: 0..PLEX_COUNT-2)
inc.z m
lda #PLEX_COUNT-2+1
cmp.z m
bne __b1
ldx #0
plexFreePrepare1___b1:
// PLEX_FREE_YPOS[s] = 0
lda #0
sta PLEX_FREE_YPOS,x
// for( byte s: 0..7)
inx
cpx #8
bne plexFreePrepare1___b1
// }
rts
}
// Initialize the program
init: {
// Set the x-positions & pointers
.label xp = 6
// *D011 = VIC_DEN | VIC_RSEL | 3
lda #VIC_DEN|VIC_RSEL|3
sta D011
// plexInit(SCREEN)
// Initialize the multiplexer
jsr plexInit
lda #<$20
sta.z xp
lda #>$20
sta.z xp+1
ldx #0
__b1:
// PLEX_PTR[sx] = (byte)(SPRITE/$40)
lda #SPRITE/$40
sta PLEX_PTR,x
// PLEX_XPOS[sx] = xp
txa
asl
tay
lda.z xp
sta PLEX_XPOS,y
lda.z xp+1
sta PLEX_XPOS+1,y
// xp += 9
lda #9
clc
adc.z xp
sta.z xp
bcc !+
inc.z xp+1
!:
// for(byte sx: 0..PLEX_COUNT-1)
inx
cpx #PLEX_COUNT-1+1
bne __b1
// *SPRITES_ENABLE = $ff
// Enable & initialize sprites
lda #$ff
sta SPRITES_ENABLE
ldx #0
__b3:
// SPRITES_COLS[ss] = GREEN
lda #GREEN
sta SPRITES_COLS,x
// for(byte ss: 0..7)
inx
cpx #8
bne __b3
// }
rts
}
// Initialize the multiplexer data structures
plexInit: {
ldx #0
__b1:
// PLEX_SORTED_IDX[i] = i
txa
sta PLEX_SORTED_IDX,x
// for(byte i: 0..PLEX_COUNT-1)
inx
cpx #PLEX_COUNT-1+1
bne __b1
// }
rts
}
// The x-positions of the multiplexer sprites ($000-$1ff)
PLEX_XPOS: .fill 2*PLEX_COUNT, 0
// The y-positions of the multiplexer sprites.
PLEX_YPOS: .fill PLEX_COUNT, 0
// The sprite pointers for the multiplexed sprites
PLEX_PTR: .fill PLEX_COUNT, 0
// Indexes of the plex-sprites sorted by sprite y-position. Each call to plexSort() will fix the sorting if changes to the Y-positions have ruined it.
PLEX_SORTED_IDX: .fill PLEX_COUNT, 0
// Contains the Y-position where each sprite is free again. PLEX_FREE_YPOS[s] holds the Y-position where sprite s is free to use again.
PLEX_FREE_YPOS: .fill 8, 0
.align $100
YSIN:
.var min = 50
.var max = 250-21
.var ampl = max-min;
.for(var i=0;i<256;i++)
.byte round(min+(ampl/2)+(ampl/2)*sin(toRadians(360*i/256)))
.pc = SPRITE "SPRITE"
.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)