%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