gigatron/rom/Contrib/at67/gasm/starfield.gasm
2025-01-28 19:17:01 +03:00

551 lines
19 KiB
Plaintext

%include include\gigatron.i
%include include\macros.i
vram EQU 0x0800
midiStreamPtr EQU 0x82
midiCommand EQU midiStreamPtr + 0x02
midiChannel EQU midiStreamPtr + 0x04
midiDelay EQU midiStreamPtr + 0x06
midiNote EQU midiStreamPtr + 0x08
midiScratch EQU midiStreamPtr + 0x0A
vbase EQU 0x90
pixels EQU 0x92
xPos EQU 0x94
yPos EQU 0x96
xVel EQU 0x98
yVel EQU 0x9A
i EQU 0x9C
frame EQU 0x9E
scratch EQU 0xA0
pixel EQU 0xA2
random EQU 0xA4
skip EQU 0xA6
xyAbs EQU 0xA8
colour EQU 0xAA
ii EQU 0xB0
jj EQU 0xB1
kk EQU 0xB2
ll EQU 0xB3
xx EQU 0xB4
yy EQU 0xB5
xyPosArray EQU 0x600
xyVelArray EQU 0x680
numStars EQU 40 ; max 64, (arrays are fixed at a maximum size of 64)
_startAddress_ EQU 0x0200 ; entry point for the code, if this is missing defaults to 0x0200
_callTable_ EQU 0x007E ; call addresses are automatically stored here by the assembler, it grows downwards
; this is optional, if you choose not to use it, then you must use the LDWI xxxx, CALL _vAC paradigm
; *NOTE* gt1 spec only allows for one zero page segment, .vasm files use this for the call table
; do *NOT* make this address higher than 0x00BE, it will conflict with future ROM loading mechanisms
; do *NOT* define constants, (DB or DW), between 0x30 -> 0x44 and 0xc0 -> 0xFF, these addresses are
; used by the loader and the vCPU stack, you can create variables in these areas as long as you don't
; corrupt your nested CALL return addresses on the stack
_singleStepWatch_ EQU i ; the single step debugger watches this variable location to decide when to step,
; choose a variable that is updated often
start EQU 0x200
loopInit EQU 0x300
vBlank EQU 0x400
clearScreen EQU 0x08A1
clearScreen_0 EQU 0x09A1
resetAudio EQU 0x0AA1
playMidi EQU 0x0BA1
midiStartNote EQU 0x0CA1
midiSegment EQU 0x0DA1
; look up table that retrieves skip values based on max velocity component
skipLut EQU 0x500
skipLut DB 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
DB 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F
DB 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F 0x0F
DB 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07
DB 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07
DB 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03
DB 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03
DB 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
DB 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
; look up table that is used to return (abs({-8...8} - {0}) <<4)
xyAbsLut EQU 0x590
xyAbsLut DB 0x80 0x70 0x60 0x50 0x40 0x30 0x20 0x10 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80
; look up table that retrieves colours
colourLut EQU 0x5A0
colourLut DB 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15
DB 0x2A 0x2A 0x2A 0x2A 0x2A 0x2A 0x2A 0x2A 0x2A 0x2A 0x2A 0x2A 0x2A 0x2A 0x2A 0x2A
DB 0x3F 0x3F 0x3F 0x3F 0x3F 0x3F 0x3F 0x3F 0x3F 0x3F 0x3F 0x3F 0x3F 0x3F 0x3F 0x3F
start CALL resetAudio
CALL clearScreen
LDWI vram
STW vbase ; vram base address
STW pixels ; pixel address
LDWI skipLut
STW skip
LDWI xyAbsLut
STW xyAbs
LDWI colourLut
STW colour
LDWI xyPosArray
STW xPos
LDWI xyPosArray + 1
STW yPos
LDWI xyVelArray
STW xVel
LDWI xyVelArray + 1
STW yVel
LD giga_frameCount
STW frame
init LDI numStars
ST i
; center position
rand_vel CALL randPos
CALL randVel
INC xPos
INC xPos
INC yPos
INC yPos
INC xVel
INC xVel
INC yVel
INC yVel
LD i
SUBI 0x01
ST i
BGT rand_vel
LD giga_frameCount ; Start checking midi stream immediately
ST midiDelay
CALL loopInit
loopInit LDWI giga_rand1
;LDWI SYS_Random_34
;STW giga_sysFn
;SYS 34
STW random
LDI numStars
ST i
LDWI xyPosArray
STW xPos
LDWI xyPosArray + 1
STW yPos
LDWI xyVelArray
STW xVel
LDWI xyVelArray + 1
STW yVel
; main loop
loop LDW yVel ; high nibble of yVel is max(abs(xVel), abs(yVel)), (0x10...0x80}
PEEK
ANDI 0xF0
STW scratch
LutPeek skip scratch
STW scratch
LD giga_frameCount
ANDW scratch
BNE pickcolour
counter LDW xVel ; increment counter per star, (embedded in high nibble of xVel)
PEEK
ADDI 0x10
POKE xVel
pickcolour LDW xVel ; high nibble of xVel is counter
PEEK
ANDI 0xF0
SUBI 0x30
BGE maxcolour
LDW xVel ; counter indexes into colourLut
PEEK
ANDI 0xF0
STW scratch
LutPeek colour scratch
BRA pixelcolour
maxcolour LDI 0x3F
pixelcolour ST pixel
erase LDW xPos
DEEK
ADDW vbase
STW pixels
LDI 0x00
POKE pixels
CALL velocity
; x position bounds checking
xbounds LDW xPos
PEEK
BLE xyreset
SUBI 0xA0
BGE xyreset
; y position bounds checking
ybounds LDW yPos
PEEK
BLE xyreset
SUBI 0x6E
BLT draw
; reset
xyreset CALL randPos
CALL randVel
CALL velocity ; origin
LDI 0b00010101
ST pixel
; generate vram address
draw LDW xPos
DEEK
ADDW vbase
STW pixels
LD pixel
POKE pixels ; plot new pixel
INC xPos
INC xPos
INC yPos
INC yPos
INC xVel
INC xVel
INC yVel
INC yVel
CALL playMidi
LD i
SUBI 0x01
ST i
BGT loop
CALL vBlank
BRA loopInit
;------------------------------------------------------------------------------
; subroutines
vBlank LD giga_frameCount
SUBW frame
BEQ vBlank
LD giga_frameCount
STW frame
RET
; random position
randPos LD i
ANDI 0x03
ADDW random
PEEK
ANDI 0x03
ADDI 0x4E
POKE xPos
LD i
ADDI 0x01
ANDI 0x03
ADDW random
PEEK
ANDI 0x03
ADDI 0x3A
POKE yPos
RET
; random velocity
randVel LD i
ADDI 0x02
ANDI 0x03
ADDW random
PEEK ; x velocity
ANDI 0x0F
POKE xVel
STW scratch
LutPeek xyAbs scratch
ORW scratch
POKE xVel ; high nibble = abs(xvel)
LD i
ADDI 0x03
ANDI 0x03
ADDW random
PEEK ; y velocity
ANDI 0x0F
POKE yVel
STW scratch
LutPeek xyAbs scratch
ORW scratch
POKE yVel ; high nibble = abs(yvel)
ANDI 0xF0 ; max(xVel&0xF0, yVel&0xF0)
STW scratch
LD xVel
PEEK
ANDI 0xF0
SUBW scratch
BGT randVel0
LD xVel
PEEK
ANDI 0x0F
POKE xVel ; xvel high nibble = 0
RET ; yvel high nibble = yVel&0xF0
randVel0 LD xVel
PEEK
ANDI 0xF0
STW scratch
LD yVel
PEEK
ANDI 0x0F
ORW scratch
POKE yVel
LD xVel
PEEK
ANDI 0x0F
POKE xVel ; xvel high nibble = 0
RET ; yvel high nibble = xVel&0xF0
; position += velocity
velocity LDW xPos
PEEK
STW scratch
LDW xVel
PEEK
ANDI 0x0F
SUBI 0x08 ; {0x0...0xF} -> {-8...+8} - {0}
BLT x_vel0
ADDI 0x01
x_vel0 ADDW scratch
POKE xPos
LDW yPos
PEEK
STW scratch
LDW yVel
PEEK
ANDI 0x0F
SUBI 0x08 ; {0x0...0xF} -> {-8...+8} - {0}
BLT y_vel0
ADDI 0x01
y_vel0 ADDW scratch
POKE yPos
RET
;------------------------------------------------------------------------------
; clears the viewable screen
clearScreen LDWI SYS_Draw4_30 ; setup 4 pixel SYS routine
STW giga_sysFn
LDWI 0x0000 ; 4 pixels of colour
STW giga_sysArg0
STW giga_sysArg2
LDI giga_yres / 2 ; counters
ST jj
LDI giga_xres / 4
ST ii
LDWI 0x0800 ; top line
STW xx
LDWI 0x7F00 ; bottom line
STW kk
PUSH ; save clearScreen's caller return address
CALL clearScreen_0 ; jump to clearScreen_0
; clear left and right edge single pixel vertical strips, (for screen shake)
clearStrips STW scratch
LDI 0x00
POKE scratch
LDW scratch
ADDI 0x5F
STW scratch
LDI 0x00
POKE scratch
RET
clearScreen_0 POP ; restore clearScreen's caller return address
clearS_loop LDW xx
STW giga_sysArg4 ; top line
SYS 30
LDW kk
STW giga_sysArg4 ; bottom line
SYS 30
LD xx ; 4 horizontal pixels
ADDI 0x04
ST xx
LD kk ; 4 horizontal pixels
ADDI 0x04
ST kk
LoopCounterTo1 ii clearS_loop
; clear one extra pixel wide stripes for screen shake
PUSH ; top
LDW xx
CALL clearStrips
POP
PUSH ; bottom
LDW kk
CALL clearStrips
POP
INC yy ; next top line
LD ll ; next bottom line
SUBI 0x01
ST ll
LDI 0x00 ; reset xx, kk and ii
ST xx
ST kk
LDI giga_xres / 4
ST ii
LoopCounterTo1 jj clearS_loop
RET
;------------------------------------------------------------------------------
resetAudio LDWI 0x0000
STW midiCommand
STW midiDelay
STW midiNote
LDWI giga_soundChan1 + 2 ; keyL, keyH
STW midiChannel
STW midiScratch
LDWI ffe00 ; midi score
STW midiStreamPtr
LDI 0x04
ST ii
resetA_loop LDI giga_soundChan1 ; reset low byte
ST midiScratch
LDWI 0x0300
DOKE midiScratch ; wavA and wavX
INC midiScratch
INC midiScratch
LDWI 0x0000
DOKE midiScratch ; keyL and keyH
INC midiScratch
INC midiScratch
DOKE midiScratch ; oscL and oscH
INC midiScratch + 1 ; increment high byte
LoopCounterTo1 ii resetA_loop
RET
playMidi LDI 0x10 ; keep pumping soundTimer, so that global sound stays alive
ST giga_soundTimer
LD giga_frameCount
SUBW midiDelay
BEQ playM_start
RET
playM_start PUSH
playM_process LDW midiStreamPtr
PEEK ; get midi stream byte
STW midiCommand
LDW midiStreamPtr
ADDI 0x01
STW midiStreamPtr
LDI 0xF0
ANDW midiCommand
XORI 0x90 ; check for start note
BNE playM_endnote
CALL midiStartNote ; start note
BRA playM_process
playM_endnote XORI 0x10 ; check for end note
BNE playM_segment
CALL midiEndNote ; end note
BRA playM_process
playM_segment XORI 0x50 ; check for new segment
BNE playM_delay
LDW midiStreamPtr ; midi score
DEEK
STW midiStreamPtr ; 0xD0 new midi segment address
BRA playM_process
playM_delay LD giga_frameCount ; midiDelay = (midiCommand + peek(frameCount)) & 0x00FF
ADDW midiCommand
ST midiDelay
POP
RET
midiStartNote LDWI giga_notesTable ; note table in ROM
STW midiScratch
LDW midiStreamPtr ; ROM pointer = (Peek(midiStreamPtr) - 11)*2) + giga_notesTable
PEEK
SUBI 11
LSLW
ADDW midiScratch
STW midiScratch
LUP 0x00 ; get ROM midi note low byte
ST midiNote
LDW midiScratch
LUP 0x01 ; get ROM midi note high byte
ST midiNote + 1
LDW midiCommand
ANDI 0x03 ; get channel
ST midiScratch + 1
LDI 0x00
ST midiScratch
LDW midiScratch
ADDW midiChannel ; channel address
STW midiScratch
LDW midiNote
DOKE midiScratch ; set note
LDW midiStreamPtr
ADDI 0x01 ; midiStreamPtr++
STW midiStreamPtr
RET
midiEndNote LDW midiCommand
ANDI 0x03 ; get channel
ST midiScratch + 1
LDI 0x00
ST midiScratch
LDW midiScratch
ADDW midiChannel ; channel address
STW midiScratch
LDWI 0x0000
DOKE midiScratch ; end note
RET
%include midi.i