1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-08-07 22:25:13 +00:00
Files
kickc/src/test/ref/complex/tetris/test-sprites.asm
2019-05-18 21:37:34 +02:00

340 lines
7.8 KiB
NASM

.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Processor port data direction register
.label PROCPORT_DDR = 0
// Mask for PROCESSOR_PORT_DDR which allows only memory configuration to be written
.const PROCPORT_DDR_MEMORY_MASK = 7
// Processor Port Register controlling RAM/ROM configuration and the datasette
.label PROCPORT = 1
// RAM in $A000, $E000 I/O in $D000
.const PROCPORT_RAM_IO = $35
// The offset of the sprite pointers from the screen start address
.const SPRITE_PTRS = $3f8
.label SPRITES_XPOS = $d000
.label SPRITES_YPOS = $d001
.label RASTER = $d012
.label SPRITES_ENABLE = $d015
.label SPRITES_EXPAND_Y = $d017
.label SPRITES_MC = $d01c
.label SPRITES_EXPAND_X = $d01d
.label SPRITES_COLS = $d027
.label VIC_CONTROL = $d011
.label D018 = $d018
// VIC II IRQ Status Register
.label IRQ_STATUS = $d019
// VIC II IRQ Enable Register
.label IRQ_ENABLE = $d01a
// Bits for the IRQ Status/Enable Registers
.const IRQ_RASTER = 1
// CIA#1 Interrupt Status & Control Register
.label CIA1_INTERRUPT = $dc0d
// Value that disables all CIA interrupts when stored to the CIA Interrupt registers
.const CIA_INTERRUPT_CLEAR = $7f
// CIA#2 Port A: Serial bus, RS-232, VIC memory bank
.label CIA2_PORT_A = $dd00
// CIA #2 Port A data direction register.
.label CIA2_PORT_A_DDR = $dd02
// The vector used when the HARDWARE serves IRQ interrupts
.label HARDWARE_IRQ = $fffe
// The colors of the C64
.const BLACK = 0
// Address of the first screen
.label PLAYFIELD_SCREEN_1 = $400
// Address of the second screen
.label PLAYFIELD_SCREEN_2 = $2c00
// Address of the sprites covering the playfield
.label PLAYFIELD_SPRITES = $2000
// Address of the charset
.label PLAYFIELD_CHARSET = $2800
// The Y-position of the first sprite row
.const SPRITES_FIRST_YPOS = $31
.label SIN = $1400
.label SIN_SPRITE = $2800
// Screen Sprite pointers on screen 1
.label PLAYFIELD_SPRITE_PTRS_1 = PLAYFIELD_SCREEN_1+SPRITE_PTRS
// Screen Sprite pointers on screen 2
.label PLAYFIELD_SPRITE_PTRS_2 = PLAYFIELD_SCREEN_2+SPRITE_PTRS
// The line of the first IRQ
.const IRQ_RASTER_FIRST = SPRITES_FIRST_YPOS+$13
.const toSpritePtr1_return = PLAYFIELD_SPRITES/$40
.label render_screen_showing = 5
.label irq_raster_next = 6
.label irq_sprite_ypos = 7
.label irq_sprite_ptr = 8
.label irq_cnt = 9
.label sin_idx = 2
bbegin:
// The screen currently being showed to the user. $00 for screen 1 / $20 for screen 2.
lda #0
sta render_screen_showing
// The raster line of the next IRQ
lda #IRQ_RASTER_FIRST
sta irq_raster_next
// Y-pos of the sprites on the next IRQ
lda #SPRITES_FIRST_YPOS+$15
sta irq_sprite_ypos
// Index of the sprites to show on the next IRQ
lda #toSpritePtr1_return+3
sta irq_sprite_ptr
// Counting the 10 IRQs
lda #0
sta irq_cnt
jsr main
rts
main: {
.const toSpritePtr2_return = SIN_SPRITE/$40
.const vicSelectGfxBank1_toDd001_return = 3
.const toD0181_return = (>(PLAYFIELD_SCREEN_1&$3fff)*4)|(>PLAYFIELD_CHARSET)/4&$f
.label xpos = 2
.label ypos = 3
lda #3
sta CIA2_PORT_A_DDR
lda #vicSelectGfxBank1_toDd001_return
sta CIA2_PORT_A
lda #toD0181_return
sta D018
jsr sprites_init
lda #$ff
sta SPRITES_ENABLE
lda #$32
sta ypos
lda #$18
sta xpos
ldy #4
b1:
tya
asl
tax
lda xpos
sta SPRITES_XPOS,x
lda ypos
sta SPRITES_YPOS,x
tya
sec
sbc #3
sta SPRITES_COLS,y
lda #toSpritePtr2_return
sta PLAYFIELD_SPRITE_PTRS_1,y
lax xpos
axs #-[$18]
stx xpos
lax ypos
axs #-[$18]
stx ypos
iny
cpy #8
bne b1
jsr sprites_irq_init
jsr loop
rts
}
loop: {
.label s = 3
lda #0
sta sin_idx
b2:
lda #$ff
cmp RASTER
bne b2
ldx sin_idx
lda #4
sta s
b4:
lda s
asl
tay
lda SIN,x
sta SPRITES_YPOS,y
txa
axs #-[$a]
inc s
lda #8
cmp s
bne b4
inc sin_idx
jmp b2
}
// Setup the IRQ
sprites_irq_init: {
sei
// Acknowledge any IRQ and setup the next one
lda #IRQ_RASTER
sta IRQ_STATUS
lda CIA1_INTERRUPT
// Disable kernal & basic
lda #PROCPORT_DDR_MEMORY_MASK
sta PROCPORT_DDR
lda #PROCPORT_RAM_IO
sta PROCPORT
// Disable CIA 1 Timer IRQ
lda #CIA_INTERRUPT_CLEAR
sta CIA1_INTERRUPT
// Set raster line
lda #$7f
and VIC_CONTROL
sta VIC_CONTROL
lda #IRQ_RASTER_FIRST
sta RASTER
// Enable Raster Interrupt
lda #IRQ_RASTER
sta IRQ_ENABLE
// Set the IRQ routine
lda #<sprites_irq
sta HARDWARE_IRQ
lda #>sprites_irq
sta HARDWARE_IRQ+1
cli
rts
}
// Setup the sprites
sprites_init: {
.label xpos = 2
lda #$f
sta SPRITES_ENABLE
lda #0
sta SPRITES_MC
sta SPRITES_EXPAND_Y
sta SPRITES_EXPAND_X
lda #$18+$f*8
sta xpos
ldy #0
b1:
tya
asl
tax
lda xpos
sta SPRITES_XPOS,x
lda #BLACK
sta SPRITES_COLS,y
lax xpos
axs #-[$18]
stx xpos
iny
cpy #4
bne b1
rts
}
// Raster Interrupt Routine - sets up the sprites covering the playfield
// Repeats 10 timers every 2 lines from line IRQ_RASTER_FIRST
// Utilizes duplicated gfx in the sprites to allow for some leeway in updating the sprite pointers
sprites_irq: {
.const toSpritePtr2_return = PLAYFIELD_SPRITES/$40
.label raster_sprite_gfx_modify = 4
sta rega+1
stx regx+1
//(*BGCOL)++;
// Clear decimal flag (because it is used by the score algorithm)
cld
// Place the sprites
lda irq_sprite_ypos
sta SPRITES_YPOS
sta SPRITES_YPOS+2
sta SPRITES_YPOS+4
sta SPRITES_YPOS+6
ldx irq_raster_next
inx
// Wait for the y-position before changing sprite pointers
stx raster_sprite_gfx_modify
b8:
lda RASTER
cmp raster_sprite_gfx_modify
bcc b8
ldx irq_sprite_ptr
lda render_screen_showing
cmp #0
beq b1
stx PLAYFIELD_SPRITE_PTRS_2
inx
txa
sta PLAYFIELD_SPRITE_PTRS_2+1
sta PLAYFIELD_SPRITE_PTRS_2+2
clc
adc #1
sta PLAYFIELD_SPRITE_PTRS_2+3
b2:
inc irq_cnt
lda #9
cmp irq_cnt
beq b3
lda #$a
cmp irq_cnt
beq b4
lax irq_raster_next
axs #-[$14]
stx irq_raster_next
lax irq_sprite_ypos
axs #-[$15]
stx irq_sprite_ypos
lax irq_sprite_ptr
axs #-[3]
stx irq_sprite_ptr
b5:
// Setup next interrupt
lda irq_raster_next
sta RASTER
// Acknowledge the IRQ and setup the next one
lda #IRQ_RASTER
sta IRQ_STATUS
rega:
lda #00
regx:
ldx #00
rti
b4:
lda #0
sta irq_cnt
lda #IRQ_RASTER_FIRST
sta irq_raster_next
lax irq_sprite_ypos
axs #-[$15]
stx irq_sprite_ypos
lax irq_sprite_ptr
axs #-[3]
stx irq_sprite_ptr
jmp b5
b3:
lax irq_raster_next
axs #-[$15]
stx irq_raster_next
lda #SPRITES_FIRST_YPOS
sta irq_sprite_ypos
lda #toSpritePtr2_return
sta irq_sprite_ptr
jmp b5
b1:
stx PLAYFIELD_SPRITE_PTRS_1
inx
stx PLAYFIELD_SPRITE_PTRS_1+1
stx PLAYFIELD_SPRITE_PTRS_1+2
inx
txa
sta PLAYFIELD_SPRITE_PTRS_1+3
jmp b2
}
.pc = PLAYFIELD_SPRITES "PLAYFIELD_SPRITES"
.var sprites = LoadPicture("playfield-sprites.png", List().add($010101, $000000))
// Put the sprites into memory
.for(var sy=0;sy<10;sy++) {
.var sprite_gfx_y = sy*20
.for(var sx=0;sx<3;sx++) {
.for (var y=0;y<21; y++) {
.var gfx_y = sprite_gfx_y + mod(2100+y-sprite_gfx_y,21)
.for (var c=0; c<3; c++) {
.byte sprites.getSinglecolorByte(sx*3+c,gfx_y)
}
}
.byte 0
}
}
.pc = SIN "SIN"
.var AMPL = 200-21
.for(var i=0; i<256; i++) {
.byte 51+AMPL/2+sin(toRadians([i*360]/256))*AMPL/2
}
.pc = SIN_SPRITE "SIN_SPRITE"
.fill $40, $ff