mirror of
https://codeberg.org/hkzlab/TK2048.git
synced 2025-12-25 14:42:16 +11:00
595 lines
No EOL
11 KiB
ArmAsm
595 lines
No EOL
11 KiB
ArmAsm
.rtmodel version,"1"
|
|
.rtmodel core,"6502"
|
|
|
|
.extern _Zp
|
|
.extern VDP_MEM, VDP_REG
|
|
|
|
.section code,text
|
|
|
|
|
|
;;; vdp_point_to_vram_xy:
|
|
;;; Readies the VDP registers to write on a tile at XY
|
|
;;; Parameters:
|
|
;;; - nametable index in vram [_Zp[4]]
|
|
;;; - X coordinate [_Zp[0]]
|
|
;;; - Y coordinate [_Zp[1]]
|
|
;;;
|
|
;;; Returns: nothing
|
|
;;;
|
|
;;; Clobbers:
|
|
;;; - A, Y, X
|
|
;;; - Zp 5, 6
|
|
;;;
|
|
vdp_point_to_vram_xy:
|
|
T_VADD_H$: .equ _Zp+6
|
|
T_VADD_L$: .equ _Zp+5
|
|
P_NT_IDX$: .equ _Zp+4
|
|
P_Y$: .equ _Zp+1
|
|
P_X$: .equ _Zp+0
|
|
|
|
lda #0x00
|
|
sta zp:T_VADD_H$
|
|
lda zp:P_Y$
|
|
sta zp:T_VADD_L$
|
|
|
|
;; Shift Y five times to the left to get the offset for the ROW in VRAM
|
|
ldx #5
|
|
ShiftOffset$:
|
|
asl zp:T_VADD_L$
|
|
rol zp:T_VADD_H$
|
|
dex
|
|
bne ShiftOffset$
|
|
|
|
clc
|
|
|
|
; Calculate the VRAM address
|
|
lda zp:P_X$
|
|
adc zp:T_VADD_L$
|
|
sta zp:T_VADD_L$
|
|
ldx zp:P_NT_IDX$
|
|
lda NameTablesList,x
|
|
adc zp:T_VADD_H$
|
|
sta zp:T_VADD_H$
|
|
|
|
; Setup the VDP to write into VRAM
|
|
lda zp:T_VADD_L$
|
|
sta VDP_REG
|
|
lda zp:T_VADD_H$
|
|
ora #0x40
|
|
sta VDP_REG
|
|
|
|
rts
|
|
|
|
;;; vdp_set_tile:
|
|
;;; Prints the provided ASCII string at the specified coordinates
|
|
;;; Parameters:
|
|
;;; - nametable index in vram [A]
|
|
;;; - X coordinate [_Zp[0]]
|
|
;;; - Y coordinate [_Zp[1]]
|
|
;;; - tile index [_Zp[2]]
|
|
;;;
|
|
;;; Returns: nothing
|
|
;;;
|
|
;;; Clobbers:
|
|
;;; - A, Y, X
|
|
;;; - Zp 5, 6
|
|
;;;
|
|
vdp_set_tile:
|
|
T_VADD_H$: .equ _Zp+6
|
|
T_VADD_L$: .equ _Zp+5
|
|
P_NT_IDX$: .equ _Zp+4
|
|
P_TILE$: .equ _Zp+2
|
|
P_Y$: .equ _Zp+1
|
|
P_X$: .equ _Zp+0
|
|
|
|
sta zp:P_NT_IDX$
|
|
|
|
jsr vdp_point_to_vram_xy
|
|
|
|
lda zp:P_TILE$
|
|
sta VDP_MEM
|
|
|
|
EOS$:
|
|
rts
|
|
|
|
;;; vdp_print_string:
|
|
;;; Prints the provided ASCII string at the specified coordinates (newlines and control chars are not supported)
|
|
;;; Parameters:
|
|
;;; - nametable index in vram [A]
|
|
;;; - X coordinate [_Zp[0]]
|
|
;;; - Y coordinate [_Zp[1]]
|
|
;;; - string address [_Zp[2], _Zp[3]]: Address of the beginning of data to write
|
|
;;;
|
|
;;; Returns: nothing
|
|
;;;
|
|
;;; Clobbers:
|
|
;;; - A, Y, X
|
|
;;; - Zp 5, 6
|
|
;;;
|
|
vdp_print_string:
|
|
T_VADD_H$: .equ _Zp+6
|
|
T_VADD_L$: .equ _Zp+5
|
|
P_NT_IDX$: .equ _Zp+4
|
|
P_DATA_H$: .equ _Zp+3
|
|
P_DATA_L$: .equ _Zp+2
|
|
P_Y$: .equ _Zp+1
|
|
P_X$: .equ _Zp+0
|
|
|
|
sta zp:P_NT_IDX$
|
|
|
|
jsr vdp_point_to_vram_xy
|
|
|
|
ldy #0x00
|
|
NextChar$:
|
|
lda (zp:P_DATA_L$),y
|
|
beq EOS$
|
|
sec
|
|
sbc #0x20
|
|
sta VDP_MEM
|
|
iny
|
|
bne NextChar$
|
|
|
|
EOS$:
|
|
rts
|
|
|
|
;;; vdp_write_vram:
|
|
;;; Write the provided data into VRAM at specified address
|
|
;;; Parameters:
|
|
;;; - data address [_Zp[0], _Zp[1]]: Address of the beginning of data to write
|
|
;;; - data length [_Zp[2], _Zp[3]]: Length of data to write
|
|
;;; - VRAM address [_Zp[4], _Zp[5]]: Start address of data in VRAM
|
|
;;;
|
|
;;; Returns: nothing
|
|
;;;
|
|
;;; Clobbers:
|
|
;;; - A, Y, X
|
|
;;; - Zp 1, 2, 3
|
|
;;;
|
|
vdp_write_vram:
|
|
P_VADD_H$: .equ _Zp+5
|
|
P_VADD_L$: .equ _Zp+4
|
|
P_DLEN_H$: .equ _Zp+3
|
|
P_DLEN_L$: .equ _Zp+2
|
|
P_DATA_H$: .equ _Zp+1
|
|
P_DATA_L$: .equ _Zp+0
|
|
|
|
; Decrement length by one, so or the loop would do an off-by-one write
|
|
sec
|
|
lda zp:P_DLEN_L$
|
|
sbc #1
|
|
sta zp:P_DLEN_L$
|
|
lda zp:P_DLEN_H$
|
|
sbc #0
|
|
sta zp:P_DLEN_H$
|
|
|
|
; Setup the VDP to write into VRAM
|
|
lda zp:P_VADD_L$
|
|
sta VDP_REG
|
|
lda zp:P_VADD_H$
|
|
ora #0x40
|
|
sta VDP_REG
|
|
|
|
; Actually write data into VRAM
|
|
ldx zp:P_DLEN_H$
|
|
ldy #0x00
|
|
CopyLoop$:
|
|
lda (zp:P_DATA_L$),y
|
|
sta VDP_MEM
|
|
iny
|
|
bne SkipHIncr$ ; Check if we did overflow. In case, increment the high byte of the address
|
|
inc zp:P_DATA_H$
|
|
SkipHIncr$:
|
|
dec zp:P_DLEN_L$
|
|
lda zp:P_DLEN_L$
|
|
cmp #0xFF
|
|
bne CopyLoop$
|
|
dex
|
|
bpl CopyLoop$
|
|
|
|
rts
|
|
|
|
;;; vdp_fill_vram:
|
|
;;; Fill VRAM with a specific byte
|
|
;;; Parameters:
|
|
;;; - fill value [A]
|
|
;;; - data length [_Zp[0], _Zp[1]]: Length of data to write
|
|
;;; - VRAM address [_Zp[2], _Zp[3]]: Start address of data in VRAM
|
|
;;;
|
|
;;; Returns: nothing
|
|
;;;
|
|
;;; Clobbers:
|
|
;;; - A, Y, X
|
|
;;; - Zp 0, 1, 2, 4
|
|
;;;
|
|
vdp_fill_vram:
|
|
T_FILLVAL$: .equ _Zp+4
|
|
P_VADD_H$: .equ _Zp+3
|
|
P_VADD_L$: .equ _Zp+2
|
|
P_DLEN_H$: .equ _Zp+1
|
|
P_DLEN_L$: .equ _Zp+0
|
|
|
|
sta zp:T_FILLVAL$
|
|
|
|
; Decrement length by one, so or the loop would do an off-by-one write
|
|
sec
|
|
lda zp:P_DLEN_L$
|
|
sbc #1
|
|
sta zp:P_DLEN_L$
|
|
lda zp:P_DLEN_H$
|
|
sbc #0
|
|
sta zp:P_DLEN_H$
|
|
|
|
; Setup the VDP to write into VRAM
|
|
lda zp:P_VADD_L$
|
|
sta VDP_REG
|
|
lda zp:P_VADD_H$
|
|
ora #0x40
|
|
sta VDP_REG
|
|
|
|
; Fill the VRAM
|
|
ldx zp:P_DLEN_H$
|
|
CopyLoop$:
|
|
lda zp:T_FILLVAL$
|
|
sta VDP_MEM
|
|
|
|
dec zp:P_DLEN_L$
|
|
lda zp:P_DLEN_L$
|
|
cmp #0xFF
|
|
bne CopyLoop$
|
|
dex
|
|
bpl CopyLoop$
|
|
|
|
rts
|
|
|
|
;;; vdp_detect:
|
|
;;; Check if a VDP is present
|
|
;;; Parameters: none
|
|
;;;
|
|
;;; Returns: 0xFF in A if VDP is present, 0 otherwise
|
|
;;;
|
|
;;; Clobbers:
|
|
;;; - A
|
|
;;;
|
|
vdp_detect:
|
|
lda #0x00
|
|
sta VDP_REG
|
|
lda #0x40
|
|
sta VDP_REG
|
|
|
|
lda #0x55
|
|
sta VDP_MEM
|
|
lda #0xAA
|
|
sta VDP_MEM
|
|
|
|
lda #0x00
|
|
sta VDP_REG
|
|
sta VDP_REG
|
|
|
|
eor VDP_MEM
|
|
eor VDP_MEM
|
|
|
|
cmp #0xFF
|
|
beq VdpFound$
|
|
lda #0x00
|
|
VdpFound$:
|
|
rts
|
|
|
|
;;; vdp_hide_sprites:
|
|
;;; Marks all sprites as hidden
|
|
;;; Parameters: none
|
|
;;;
|
|
;;; Returns: nothing
|
|
;;;
|
|
;;; Clobbers:
|
|
;;; - A, Y, X
|
|
;;; - Zp 1, 2, 3, 4, 5, 6, 7
|
|
;;;
|
|
vdp_hide_sprites:
|
|
ldy #0
|
|
HideLoop$:
|
|
tya
|
|
|
|
jsr vdp_hide_sprite
|
|
|
|
iny
|
|
cpy #25
|
|
bne HideLoop$
|
|
|
|
; Make sure the table gets updated in memory
|
|
jsr _vdp_write_interleaved_sat
|
|
|
|
rts
|
|
|
|
;;; vdp_hide_sprite:
|
|
;;; Mark a single sprite as hidden
|
|
;;; Parameters:
|
|
;;; - sprite number [A]
|
|
;;;
|
|
;;; Returns: nothing
|
|
;;;
|
|
;;; Clobbers:
|
|
;;; - A, Y, X
|
|
;;;
|
|
vdp_hide_sprite:
|
|
tay
|
|
ldx SAT_RowCol_Trans_Table,y
|
|
lda #0xC0
|
|
sta SpriteAttributeTable,x
|
|
rts
|
|
|
|
;;; vdp_show_sprite:
|
|
;;; Enable a single sprite in the game grid
|
|
;;; Parameters:
|
|
;;; - sprite number [A]
|
|
;;;
|
|
;;; Returns: nothing
|
|
;;;
|
|
;;; Clobbers:
|
|
;;; - A, Y, X
|
|
;;;
|
|
vdp_show_sprite:
|
|
tay
|
|
ldx SAT_RowCol_Trans_Table,y
|
|
lda SAT_Y_Map,y
|
|
sta SpriteAttributeTable,x
|
|
rts
|
|
|
|
;;; vdp_set_sprite_tile:
|
|
;;; Set the current tile index for a specific sprite
|
|
;;; Parameters:
|
|
;;; - sprite number [A]
|
|
;;; - tile index [_Zp [0]]
|
|
;;;
|
|
;;; Returns: nothing
|
|
;;;
|
|
;;; Clobbers:
|
|
;;; - A, Y, X
|
|
;;;
|
|
vdp_set_sprite_tile:
|
|
P_TILE_IDX$:.equ _Zp+0
|
|
asl zp:P_TILE_IDX$ ; We're using 2x2 tile sprites
|
|
asl zp:P_TILE_IDX$
|
|
|
|
tay
|
|
ldx SAT_RowCol_Trans_Table,y
|
|
lda zp:P_TILE_IDX$
|
|
sta SpriteAttributeTable+2,x
|
|
rts
|
|
|
|
;;; vdp_switch_nt:
|
|
;;; Switch shown nametable
|
|
;;; Parameters:
|
|
;;; - name table index [A]
|
|
;;;
|
|
;;; Returns: nothing
|
|
;;;
|
|
;;; Clobbers:
|
|
;;; - A, X
|
|
;;;
|
|
vdp_switch_nt:
|
|
tax
|
|
lda NameTablesList,x
|
|
lsr a
|
|
lsr a
|
|
sta VDP_REG
|
|
lda #0x82
|
|
sta VDP_REG
|
|
rts
|
|
|
|
;;; vdp_write_registers:
|
|
;;; Initialize the registers of the VDP, using the provided byte array
|
|
;;; Parameters:
|
|
;;; - data address [_Zp[0], _Zp[1]]: Address of the beginning of initialization data, a 16 byte array
|
|
;;;
|
|
;;; Returns: nothing
|
|
;;;
|
|
;;; Clobbers:
|
|
;;; - A, Y
|
|
;;;
|
|
vdp_write_registers:
|
|
P_REG_H$: .equ _Zp+1
|
|
P_REG_L$: .equ _Zp+0
|
|
|
|
; Write the register sequence
|
|
ldy #0x00
|
|
RegLoop$:
|
|
lda (zp:P_REG_L$),y
|
|
sta VDP_REG
|
|
iny
|
|
cpy #16
|
|
bne RegLoop$
|
|
|
|
rts
|
|
|
|
vdp_irq_handler:
|
|
lda VDP_REG ; Clear the interrupt
|
|
|
|
jsr _vdp_write_interleaved_sat
|
|
|
|
rti
|
|
|
|
;;; _vdp_write_interleaved_sat:
|
|
;;; Updates SAT at 0x300 with sprite multiplexing
|
|
;;; Parameters: none
|
|
;;;
|
|
;;; Returns: nothing
|
|
;;;
|
|
;;; Clobbers:
|
|
;;; - A, Y, X
|
|
;;; - Zp 1, 2, 3, 4, 5, 6, 7
|
|
;;;
|
|
_vdp_write_interleaved_sat:
|
|
T_COUNT$: .equ _Zp+7
|
|
T_SATB_IDX$: .equ _Zp+6
|
|
T_DEST_H$: .equ _Zp+5
|
|
T_DEST_L$: .equ _Zp+4
|
|
T_DLEN_H$: .equ _Zp+3
|
|
T_DLEN_L$: .equ _Zp+2
|
|
T_DATA_H$: .equ _Zp+1
|
|
T_DATA_L$: .equ _Zp+0
|
|
|
|
lda #0x00
|
|
sta zp:T_DEST_L$
|
|
lda #0x03
|
|
sta zp:T_DEST_H$
|
|
|
|
lda CurrentByteTableOffset
|
|
cmp #5
|
|
bne NoOverflow$
|
|
lda #0
|
|
sta CurrentByteTableOffset
|
|
NoOverflow$:
|
|
asl a
|
|
sta zp:T_SATB_IDX$
|
|
|
|
lda #4
|
|
sta zp:T_COUNT$
|
|
|
|
WriteLoop$:
|
|
lda #20
|
|
sta zp:T_DLEN_L$
|
|
lda #00
|
|
sta zp:T_DLEN_H$
|
|
|
|
lda zp:T_SATB_IDX$
|
|
tax
|
|
|
|
lda SAT_Block_Table,x
|
|
sta zp:T_DATA_L$
|
|
lda SAT_Block_Table+1,x
|
|
sta zp:T_DATA_H$
|
|
|
|
jsr vdp_write_vram
|
|
|
|
clc
|
|
lda zp:T_DEST_L$
|
|
adc #20
|
|
sta zp:T_DEST_L$
|
|
|
|
lda zp:T_SATB_IDX$
|
|
adc #0x02
|
|
sta zp:T_SATB_IDX$
|
|
dec zp:T_COUNT$
|
|
bpl WriteLoop$
|
|
|
|
inc CurrentByteTableOffset
|
|
|
|
rts
|
|
|
|
;;;;;;;;;;;;;;;;;;
|
|
.section data,data
|
|
|
|
SpriteAttributeTable:
|
|
; Organized in columns
|
|
SAT_Col1:
|
|
.byte 0xC0, 0x08, 0x30, 0x01 ; Col 1
|
|
.byte 0xC0, 0x08, 0x30, 0x01
|
|
.byte 0xC0, 0x08, 0x30, 0x01
|
|
.byte 0xC0, 0x08, 0x30, 0x01
|
|
.byte 0xC0, 0x08, 0x30, 0x01
|
|
SAT_Col2:
|
|
.byte 0xC0, 0x30, 0x30, 0x01 ; Col 2
|
|
.byte 0xC0, 0x30, 0x30, 0x01
|
|
.byte 0xC0, 0x30, 0x30, 0x01
|
|
.byte 0xC0, 0x30, 0x30, 0x01
|
|
.byte 0xC0, 0x30, 0x30, 0x01
|
|
SAT_Col3:
|
|
.byte 0xC0, 0x58, 0x30, 0x01 ; Col 3
|
|
.byte 0xC0, 0x58, 0x30, 0x01
|
|
.byte 0xC0, 0x58, 0x30, 0x01
|
|
.byte 0xC0, 0x58, 0x30, 0x01
|
|
.byte 0xC0, 0x58, 0x30, 0x01
|
|
SAT_Col4:
|
|
.byte 0xC0, 0x80, 0x30, 0x01 ; Col 4
|
|
.byte 0xC0, 0x80, 0x30, 0x01
|
|
.byte 0xC0, 0x80, 0x30, 0x01
|
|
.byte 0xC0, 0x80, 0x30, 0x01
|
|
.byte 0xC0, 0x80, 0x30, 0x01
|
|
SAT_Col5:
|
|
.byte 0xC0, 0xA8, 0x30, 0x01 ; Col 5
|
|
.byte 0xC0, 0xA8, 0x30, 0x01
|
|
.byte 0xC0, 0xA8, 0x30, 0x01
|
|
.byte 0xC0, 0xA8, 0x30, 0x01
|
|
.byte 0xC0, 0xA8, 0x30, 0x01
|
|
; Unused
|
|
.byte 0xD0, 0x00, 0x30, 0x00
|
|
.byte 0xD0, 0x00, 0x30, 0x00
|
|
.byte 0xD0, 0x00, 0x30, 0x00
|
|
.byte 0xD0, 0x00, 0x30, 0x00
|
|
.byte 0xD0, 0x00, 0x30, 0x00
|
|
.byte 0xD0, 0x00, 0x30, 0x00
|
|
.byte 0xD0, 0x00, 0x30, 0x00
|
|
|
|
SAT_RowCol_Trans_Table:
|
|
.byte 0, 20, 40, 60, 80
|
|
.byte 4, 24, 44, 64, 84
|
|
.byte 8, 28, 48, 68, 88
|
|
.byte 12, 32, 52, 72, 92
|
|
.byte 16, 36, 56, 76, 96
|
|
|
|
SAT_Y_Map:
|
|
.byte 0x07
|
|
.byte 0x07
|
|
.byte 0x07
|
|
.byte 0x07
|
|
.byte 0x07
|
|
.byte 0x27
|
|
.byte 0x27
|
|
.byte 0x27
|
|
.byte 0x27
|
|
.byte 0x27
|
|
.byte 0x47
|
|
.byte 0x47
|
|
.byte 0x47
|
|
.byte 0x47
|
|
.byte 0x47
|
|
.byte 0x67
|
|
.byte 0x67
|
|
.byte 0x67
|
|
.byte 0x67
|
|
.byte 0x67
|
|
.byte 0x87
|
|
.byte 0x87
|
|
.byte 0x87
|
|
.byte 0x87
|
|
.byte 0x87
|
|
|
|
SAT_Block_Table:
|
|
.word SAT_Col1
|
|
.word SAT_Col2
|
|
.word SAT_Col3
|
|
.word SAT_Col4
|
|
.word SAT_Col5
|
|
.word SAT_Col1
|
|
.word SAT_Col2
|
|
.word SAT_Col3
|
|
.word SAT_Col4
|
|
.word SAT_Col5
|
|
|
|
; Contains a list of VRAM addresses corresponding to every page
|
|
NameTablesList:
|
|
NT_P0: .byte 0x00
|
|
NT_P1: .byte 0x14
|
|
|
|
|
|
CurrentByteTableOffset:
|
|
.byte 0x00
|
|
|
|
;;;
|
|
;;;
|
|
;;; Exported symbols
|
|
.public vdp_write_vram
|
|
.public vdp_detect
|
|
.public vdp_write_registers
|
|
.public vdp_hide_sprites
|
|
.public vdp_hide_sprite
|
|
.public vdp_show_sprite
|
|
.public vdp_switch_nt
|
|
.public vdp_set_sprite_tile
|
|
.public vdp_print_string
|
|
.public vdp_set_tile
|
|
.public vdp_point_to_vram_xy
|
|
.public vdp_irq_handler
|
|
|
|
.public SpriteAttributeTable ; We'll need to set change visibility and values
|
|
.public NT_P0, NT_P1 |