ifconst bankswitch if bankswitch == 8 ORG $2FFC RORG $FFFC endif if bankswitch == 16 ORG $4FFC RORG $FFFC endif if bankswitch == 32 ORG $8FFC RORG $FFFC endif else ifconst ROM2k ORG $F7FC else ORG $FFFC endif endif .word start .word start ; MACRO.H ; Version 1.05, 13/NOVEMBER/2003 VERSION_MACRO = 105 ; ; THIS FILE IS EXPLICITLY SUPPORTED AS A DASM-PREFERRED COMPANION FILE ; PLEASE DO *NOT* REDISTRIBUTE MODIFIED VERSIONS OF THIS FILE! ; ; This file defines DASM macros useful for development for the Atari 2600. ; It is distributed as a companion machine-specific support package ; for the DASM compiler. Updates to this file, DASM, and associated tools are ; available at at http://www.atari2600.org/dasm ; ; Many thanks to the people who have contributed. If you take issue with the ; contents, or would like to add something, please write to me ; (atari2600@taswegian.com) with your contribution. ; ; Latest Revisions... ; ; 1.05 14/NOV/2003 - Added VERSION_MACRO equate (which will reflect 100x version #) ; This will allow conditional code to verify MACRO.H being ; used for code assembly. ; 1.04 13/NOV/2003 - SET_POINTER macro added (16-bit address load) ; ; 1.03 23/JUN/2003 - CLEAN_START macro added - clears TIA, RAM, registers ; ; 1.02 14/JUN/2003 - VERTICAL_SYNC macro added ; (standardised macro for vertical synch code) ; 1.01 22/MAR/2003 - SLEEP macro added. ; - NO_ILLEGAL_OPCODES switch implemented ; 1.0 22/MAR/2003 Initial release ; Note: These macros use illegal opcodes. To disable illegal opcode usage, ; define the symbol NO_ILLEGAL_OPCODES (-DNO_ILLEGAL_OPCODES=1 on command-line). ; If you do not allow illegal opcode usage, you must include this file ; *after* including VCS.H (as the non-illegal opcodes access hardware ; registers and require them to be defined first). ; Available macros... ; SLEEP n - sleep for n cycles ; VERTICAL_SYNC - correct 3 scanline vertical synch code ; CLEAN_START - set machine to known state on startup ; SET_POINTER - load a 16-bit absolute to a 16-bit variable ;------------------------------------------------------------------------------- ; SLEEP duration ; Original author: Thomas Jentzsch ; Inserts code which takes the specified number of cycles to execute. This is ; useful for code where precise timing is required. ; ILLEGAL-OPCODE VERSION DOES NOT AFFECT FLAGS OR REGISTERS. ; LEGAL OPCODE VERSION MAY AFFECT FLAGS ; Uses illegal opcode (DASM 2.20.01 onwards). MAC SLEEP ;usage: SLEEP n (n>1) .CYCLES SET {1} IF .CYCLES < 2 ECHO "MACRO ERROR: 'SLEEP': Duration must be > 1" ERR ENDIF IF .CYCLES & 1 IFNCONST NO_ILLEGAL_OPCODES nop 0 ELSE bit VSYNC ENDIF .CYCLES SET .CYCLES - 3 ENDIF REPEAT .CYCLES / 2 nop REPEND ENDM ;------------------------------------------------------------------------------- ; VERTICAL_SYNC ; Original author: Manuel Polik ; Inserts the code required for a proper 3 scannline ; vertical sync sequence ; ; Note: Alters the accumulator ; ; IN: ; OUT: A = 1 MAC VERTICAL_SYNC LDA #$02 ; A = VSYNC enable STA WSYNC ; Finish current line STA VSYNC ; Start vertical sync STA WSYNC ; 1st line vertical sync STA WSYNC ; 2nd line vertical sync LSR ; A = VSYNC disable STA WSYNC ; 3rd line vertical sync STA VSYNC ; Stop vertical sync ENDM ;------------------------------------------------------------------------------- ; CLEAN_START ; Original author: Andrew Davie ; Standardised start-up code, clears stack, all TIA registers and RAM to 0 ; Sets stack pointer to $FF, and all registers to 0 ; Sets decimal mode off, sets interrupt flag (kind of un-necessary) ; Use as very first section of code on boot (ie: at reset) ; Code written to minimise total ROM usage - uses weird 6502 knowledge :) MAC CLEAN_START sei cld ldx #0 txa tay .CLEAR_STACK dex txs pha bne .CLEAR_STACK ; SP=$FF, X = A = Y = 0 ENDM ;------------------------------------------------------- ; SET_POINTER ; Original author: Manuel Rotschkar ; ; Sets a 2 byte RAM pointer to an absolute address. ; ; Usage: SET_POINTER pointer, address ; Example: SET_POINTER SpritePTR, SpriteData ; ; Note: Alters the accumulator, NZ flags ; IN 1: 2 byte RAM location reserved for pointer ; IN 2: absolute address MAC SET_POINTER .POINTER SET {1} .ADDRESS SET {2} LDA #<.ADDRESS ; Get Lowbyte of Address STA .POINTER ; Store in pointer LDA #>.ADDRESS ; Get Hibyte of Address STA .POINTER+1 ; Store in pointer+1 ENDM ; EOF ; this file is screwed, I accidentally deleted the comments. Restore with version in .99b zip file. 2600basicheader.asm bB.asm std_kernel.asm startup.asm pf_drawing.asm pf_scrolling.asm std_routines.asm std_overscan.asm bB2.asm score_graphics.asm banksw.asm 2600basicfooter.asm minikernel ; display up to 6 lives on screen sta WSYNC sleep 10 ; can we optimize this? lda #0 ldy #7 sta VDELP0 sta VDELP1 ifnconst lives_compact ifnconst lives_centered sta RESP0 endif lda.w lives ifnconst lives_centered sta RESP1 endif lsr lsr lsr lsr ifconst lives_centered sta RESP0 endif lsr tax ifconst lives_centered sta RESP1 endif lda lifenusiz0table,x sta NUSIZ0 lda lifenusiz1table,x sta NUSIZ1 lda lifecolor sta COLUP0 sta COLUP1 lda #$b0 sta HMP0 else ifnconst lives_centered sta.w RESP0 sta RESP1 endif lda lives lsr lsr lsr lsr lsr tax lda lifenusiz0table,x ifconst lives_centered sta RESP0 sta RESP1 sta.w NUSIZ0 else sta NUSIZ0 endif lda lifenusiz1table,x sta NUSIZ1 lda lifecolor sta COLUP0 sta COLUP1 lda #$10 sta HMP1 endif sta HMOVE ; cycle 73 lifeloop cpx #0 beq skipall lda (lifepointer),y sta GRP0 cpx #1 beq skipall sta GRP1 skipall dey sta WSYNC bpl lifeloop iny sty GRP0 sty GRP1 rts if (<*) > $F5 align 256 endif ifconst lives_compact lifenusiz1table .byte 0 lifenusiz0table .byte 0,0,0,1,1,3,3,3 else lifenusiz1table .byte 0 lifenusiz0table .byte 0,0,0,2,2,6,6,6 endif ; VCS.H ; Version 1.05, 13/November/2003 VERSION_VCS = 105 ; THIS IS A PRELIMINARY RELEASE OF *THE* "STANDARD" VCS.H ; THIS FILE IS EXPLICITLY SUPPORTED AS A DASM-PREFERRED COMPANION FILE ; PLEASE DO *NOT* REDISTRIBUTE THIS FILE! ; ; This file defines hardware registers and memory mapping for the ; Atari 2600. It is distributed as a companion machine-specific support package ; for the DASM compiler. Updates to this file, DASM, and associated tools are ; available at at http://www.atari2600.org/dasm ; ; Many thanks to the original author(s) of this file, and to everyone who has ; contributed to understanding the Atari 2600. If you take issue with the ; contents, or naming of registers, please write to me (atari2600@taswegian.com) ; with your views. Please contribute, if you think you can improve this ; file! ; ; Latest Revisions... ; 1.05 13/NOV/2003 - Correction to 1.04 - now functions as requested by MR. ; - Added VERSION_VCS equate (which will reflect 100x version #) ; This will allow conditional code to verify VCS.H being ; used for code assembly. ; 1.04 12/NOV/2003 Added TIA_BASE_WRITE_ADDRESS and TIA_BASE_READ_ADDRESS for ; convenient disassembly/reassembly compatibility for hardware ; mirrored reading/writing differences. This is more a ; readability issue, and binary compatibility with disassembled ; and reassembled sources. Per Manuel Rotschkar's suggestion. ; 1.03 12/MAY/2003 Added SEG segment at end of file to fix old-code compatibility ; which was broken by the use of segments in this file, as ; reported by Manuel Polik on [stella] 11/MAY/2003 ; 1.02 22/MAR/2003 Added TIMINT($285) ; 1.01 Constant offset added to allow use for 3F-style bankswitching ; - define TIA_BASE_ADDRESS as $40 for Tigervision carts, otherwise ; it is safe to leave it undefined, and the base address will ; be set to 0. Thanks to Eckhard Stolberg for the suggestion. ; Note, may use -DLABEL=EXPRESSION to define TIA_BASE_ADDRESS ; - register definitions are now generated through assignment ; in uninitialised segments. This allows a changeable base ; address architecture. ; 1.0 22/MAR/2003 Initial release ;------------------------------------------------------------------------------- ; TIA_BASE_ADDRESS ; The TIA_BASE_ADDRESS defines the base address of access to TIA registers. ; Normally 0, the base address should (externally, before including this file) ; be set to $40 when creating 3F-bankswitched (and other?) cartridges. ; The reason is that this bankswitching scheme treats any access to locations ; < $40 as a bankswitch. IFNCONST TIA_BASE_ADDRESS TIA_BASE_ADDRESS = 0 ENDIF ; Note: The address may be defined on the command-line using the -D switch, eg: ; dasm.exe code.asm -DTIA_BASE_ADDRESS=$40 -f3 -v5 -ocode.bin ; *OR* by declaring the label before including this file, eg: ; TIA_BASE_ADDRESS = $40 ; include "vcs.h" ; Alternate read/write address capability - allows for some disassembly compatibility ; usage ; to allow reassembly to binary perfect copies). This is essentially catering ; for the mirrored ROM hardware registers. ; Usage: As per above, define the TIA_BASE_READ_ADDRESS and/or TIA_BASE_WRITE_ADDRESS ; using the -D command-line switch, as required. If the addresses are not defined, ; they defaut to the TIA_BASE_ADDRESS. IFNCONST TIA_BASE_READ_ADDRESS TIA_BASE_READ_ADDRESS = TIA_BASE_ADDRESS ENDIF IFNCONST TIA_BASE_WRITE_ADDRESS TIA_BASE_WRITE_ADDRESS = TIA_BASE_ADDRESS ENDIF ;------------------------------------------------------------------------------- SEG.U TIA_REGISTERS_WRITE ORG TIA_BASE_WRITE_ADDRESS ; DO NOT CHANGE THE RELATIVE ORDERING OF REGISTERS! VSYNC ds 1 ; $00 0000 00x0 Vertical Sync Set-Clear VBLANK ds 1 ; $01 xx00 00x0 Vertical Blank Set-Clear WSYNC ds 1 ; $02 ---- ---- Wait for Horizontal Blank RSYNC ds 1 ; $03 ---- ---- Reset Horizontal Sync Counter NUSIZ0 ds 1 ; $04 00xx 0xxx Number-Size player/missle 0 NUSIZ1 ds 1 ; $05 00xx 0xxx Number-Size player/missle 1 COLUP0 ds 1 ; $06 xxxx xxx0 Color-Luminance Player 0 COLUP1 ds 1 ; $07 xxxx xxx0 Color-Luminance Player 1 COLUPF ds 1 ; $08 xxxx xxx0 Color-Luminance Playfield COLUBK ds 1 ; $09 xxxx xxx0 Color-Luminance Background CTRLPF ds 1 ; $0A 00xx 0xxx Control Playfield, Ball, Collisions REFP0 ds 1 ; $0B 0000 x000 Reflection Player 0 REFP1 ds 1 ; $0C 0000 x000 Reflection Player 1 PF0 ds 1 ; $0D xxxx 0000 Playfield Register Byte 0 PF1 ds 1 ; $0E xxxx xxxx Playfield Register Byte 1 PF2 ds 1 ; $0F xxxx xxxx Playfield Register Byte 2 RESP0 ds 1 ; $10 ---- ---- Reset Player 0 RESP1 ds 1 ; $11 ---- ---- Reset Player 1 RESM0 ds 1 ; $12 ---- ---- Reset Missle 0 RESM1 ds 1 ; $13 ---- ---- Reset Missle 1 RESBL ds 1 ; $14 ---- ---- Reset Ball AUDC0 ds 1 ; $15 0000 xxxx Audio Control 0 AUDC1 ds 1 ; $16 0000 xxxx Audio Control 1 AUDF0 ds 1 ; $17 000x xxxx Audio Frequency 0 AUDF1 ds 1 ; $18 000x xxxx Audio Frequency 1 AUDV0 ds 1 ; $19 0000 xxxx Audio Volume 0 AUDV1 ds 1 ; $1A 0000 xxxx Audio Volume 1 GRP0 ds 1 ; $1B xxxx xxxx Graphics Register Player 0 GRP1 ds 1 ; $1C xxxx xxxx Graphics Register Player 1 ENAM0 ds 1 ; $1D 0000 00x0 Graphics Enable Missle 0 ENAM1 ds 1 ; $1E 0000 00x0 Graphics Enable Missle 1 ENABL ds 1 ; $1F 0000 00x0 Graphics Enable Ball HMP0 ds 1 ; $20 xxxx 0000 Horizontal Motion Player 0 HMP1 ds 1 ; $21 xxxx 0000 Horizontal Motion Player 1 HMM0 ds 1 ; $22 xxxx 0000 Horizontal Motion Missle 0 HMM1 ds 1 ; $23 xxxx 0000 Horizontal Motion Missle 1 HMBL ds 1 ; $24 xxxx 0000 Horizontal Motion Ball VDELP0 ds 1 ; $25 0000 000x Vertical Delay Player 0 VDELP1 ds 1 ; $26 0000 000x Vertical Delay Player 1 VDELBL ds 1 ; $27 0000 000x Vertical Delay Ball RESMP0 ds 1 ; $28 0000 00x0 Reset Missle 0 to Player 0 RESMP1 ds 1 ; $29 0000 00x0 Reset Missle 1 to Player 1 HMOVE ds 1 ; $2A ---- ---- Apply Horizontal Motion HMCLR ds 1 ; $2B ---- ---- Clear Horizontal Move Registers CXCLR ds 1 ; $2C ---- ---- Clear Collision Latches ;------------------------------------------------------------------------------- SEG.U TIA_REGISTERS_READ ORG TIA_BASE_READ_ADDRESS ; bit 7 bit 6 CXM0P ds 1 ; $00 xx00 0000 Read Collision M0-P1 M0-P0 CXM1P ds 1 ; $01 xx00 0000 M1-P0 M1-P1 CXP0FB ds 1 ; $02 xx00 0000 P0-PF P0-BL CXP1FB ds 1 ; $03 xx00 0000 P1-PF P1-BL CXM0FB ds 1 ; $04 xx00 0000 M0-PF M0-BL CXM1FB ds 1 ; $05 xx00 0000 M1-PF M1-BL CXBLPF ds 1 ; $06 x000 0000 BL-PF ----- CXPPMM ds 1 ; $07 xx00 0000 P0-P1 M0-M1 INPT0 ds 1 ; $08 x000 0000 Read Pot Port 0 INPT1 ds 1 ; $09 x000 0000 Read Pot Port 1 INPT2 ds 1 ; $0A x000 0000 Read Pot Port 2 INPT3 ds 1 ; $0B x000 0000 Read Pot Port 3 INPT4 ds 1 ; $0C x000 0000 Read Input (Trigger) 0 INPT5 ds 1 ; $0D x000 0000 Read Input (Trigger) 1 ;------------------------------------------------------------------------------- SEG.U RIOT ORG $280 ; RIOT MEMORY MAP SWCHA ds 1 ; $280 Port A data register for joysticks: ; Bits 4-7 for player 1. Bits 0-3 for player 2. SWACNT ds 1 ; $281 Port A data direction register (DDR) SWCHB ds 1 ; $282 Port B data (console switches) SWBCNT ds 1 ; $283 Port B DDR INTIM ds 1 ; $284 Timer output TIMINT ds 1 ; $285 ; Unused/undefined registers ($285-$294) ds 1 ; $286 ds 1 ; $287 ds 1 ; $288 ds 1 ; $289 ds 1 ; $28A ds 1 ; $28B ds 1 ; $28C ds 1 ; $28D ds 1 ; $28E ds 1 ; $28F ds 1 ; $290 ds 1 ; $291 ds 1 ; $292 ds 1 ; $293 TIM1T ds 1 ; $294 set 1 clock interval TIM8T ds 1 ; $295 set 8 clock interval TIM64T ds 1 ; $296 set 64 clock interval T1024T ds 1 ; $297 set 1024 clock interval ;------------------------------------------------------------------------------- ; The following required for back-compatibility with code which does not use ; segments. SEG ; EOF ; this file is screwed, I accidentally deleted the comments. Restore with version in .99b zip file. superchipheader.asm bB.asm std_kernel.asm startup.asm pf_drawing.asm pf_scrolling.asm std_routines.asm std_overscan.asm bB2.asm score_graphics.asm banksw.asm 2600basicfooter.asm ; Compute mul1*mul2+acc -> acc:mul1 [mul2 is unchanged] ; Routine courtesy of John Payson (AtariAge member supercat) ; x and a contain multiplicands, result in a, temp1 contains any overflow mul16 sty temp1 sta temp2 ldx #8 dec temp2 loopmul lsr ror temp1 bcc noaddmul adc temp2 noaddmul dex bne loopmul RETURN ; div int/int ; numerator in A, denom in temp1 ; returns with quotient in A, remainder in temp1 div16 sty temp1 ldx #8 loopdiv cmp temp1 bcc toosmalldiv sbc temp1 ; Note: Carry is, and will remain, set. rol temp2 rol dex bne loopdiv beq donediv toosmalldiv rol temp2 rol dex bne loopdiv donediv sta temp1 lda temp2 RETURN drawscreen ifconst debugscore ldx #14 lda INTIM ; display # cycles left in the score ifconst mincycles lda mincycles cmp INTIM lda mincycles bcc nochange lda INTIM sta mincycles nochange endif ; cmp #$2B ; bcs no_cycles_left bmi cycles_left ldx #64 eor #$ff ;make negative cycles_left stx scorecolor and #$7f ; clear sign bit tax lda scorebcd,x sta score+2 lda scorebcd1,x sta score+1 jmp done_debugscore scorebcd .byte $00, $64, $28, $92, $56, $20, $84, $48, $12, $76, $40 .byte $04, $68, $32, $96, $60, $24, $88, $52, $16, $80, $44 .byte $08, $72, $36, $00, $64, $28, $92, $56, $20, $84, $48 .byte $12, $76, $40, $04, $68, $32, $96, $60, $24, $88 scorebcd1 .byte 0, 0, 1, 1, 2, 3, 3, 4, 5, 5, 6 .byte 7, 7, 8, 8, 9, $10, $10, $11, $12, $12, $13 .byte $14, $14, $15, $16, $16, $17, $17, $18, $19, $19, $20 .byte $21, $21, $22, $23, $23, $24, $24, $25, $26, $26 done_debugscore endif ifconst debugcycles lda INTIM ; if we go over, it mucks up the background color ; cmp #$2B ; BCC overscan bmi overscan sta COLUBK bcs doneoverscan endif overscan lda INTIM ;wait for sync bmi overscan doneoverscan ;do VSYNC lda #2 sta WSYNC sta VSYNC STA WSYNC STA WSYNC LDA #0 STA WSYNC STA VSYNC sta VBLANK ifnconst overscan_time lda #37+128 else lda #overscan_time+128 endif sta TIM64T ifconst legacy if legacy < 100 ldx #4 adjustloop lda player0x,x sec sbc #14 ;? sta player0x,x dex bpl adjustloop endif endif if (<*)>$F0 align 256, $EA endif sta WSYNC ldx #4 SLEEP 3 HorPosLoop ; 5 lda player0x,X ;+4 9 sec ;+2 11 DivideLoop sbc #15 bcs DivideLoop;+4 15 sta temp1,X ;+4 19 sta RESP0,X ;+4 23 sta WSYNC dex bpl HorPosLoop;+5 5 ; 4 ldx #4 ldy temp1,X lda repostable-256,Y sta HMP0,X ;+14 18 dex ldy temp1,X lda repostable-256,Y sta HMP0,X ;+14 32 dex ldy temp1,X lda repostable-256,Y sta HMP0,X ;+14 46 dex ldy temp1,X lda repostable-256,Y sta HMP0,X ;+14 60 dex ldy temp1,X lda repostable-256,Y sta HMP0,X ;+14 74 sta WSYNC sta HMOVE ;+3 3 ifconst legacy if legacy < 100 ldx #4 adjustloop2 lda player0x,x clc adc #14 ;? sta player0x,x dex bpl adjustloop2 endif endif ;set score pointers lax score+2 jsr scorepointerset sty scorepointers+5 stx scorepointers+2 lax score+1 jsr scorepointerset sty scorepointers+4 stx scorepointers+1 lax score jsr scorepointerset sty scorepointers+3 stx scorepointers vblk ; run possible vblank bB code ifconst vblank_bB_code jsr vblank_bB_code endif vblk2 LDA INTIM bmi vblk2 jmp kernel .byte $80,$70,$60,$50,$40,$30,$20,$10,$00 .byte $F0,$E0,$D0,$C0,$B0,$A0,$90 repostable scorepointerset and #$0F asl asl asl adc #$d5) align 256 endif ; this is a kludge to prevent page wrapping - fix!!! .skipDrawlastP1 sleep 2 lda #0 jmp .continuelastP1 .endkerloop ; enter at cycle 59?? nop .enterfromNBL ifconst pfres ldy.w playfield+pfres*4-4 sty PF1 ;3 ldy.w playfield+pfres*4-3 sty PF2 ;3 ldy.w playfield+pfres*4-1 sty PF1 ; possibly too early? ldy.w playfield+pfres*4-2 sty PF2 ;3 else ldy.w playfield+44 sty PF1 ;3 ldy.w playfield+45 sty PF2 ;3 ldy.w playfield+47 sty PF1 ; possibly too early? ldy.w playfield+46 sty PF2 ;3 endif enterlastkernel lda ballheight ; tya dcp bally ; sleep 4 ; sbc stack3 rol rol sta ENABL lda player1height ;3 dcp player1y ;5 bcc .skipDrawlastP1 ldy player1y ;3 lda (player1pointer),y ;5; player0pointer must be selected carefully by the compiler ; so it doesn't cross a page boundary! .continuelastP1 sta GRP1 ;3 ifnconst player1colors lda missile1height ;3 dcp missile1y ;5 else lda (player1color),y sta COLUP1 endif dex ;dec temp4 ; might try putting this above PF writes beq endkernel ifconst pfres ldy.w playfield+pfres*4-4 sty PF1 ;3 ldy.w playfield+pfres*4-3 sty PF2 ;3 ldy.w playfield+pfres*4-1 sty PF1 ; possibly too early? ldy.w playfield+pfres*4-2 sty PF2 ;3 else ldy.w playfield+44 sty PF1 ;3 ldy.w playfield+45 sty PF2 ;3 ldy.w playfield+47 sty PF1 ; possibly too early? ldy.w playfield+46 sty PF2 ;3 endif ifnconst player1colors rol;2 rol;2 sta ENAM1 ;3 else ifnconst playercolors sleep 7 else lda.w player0colorstore sta COLUP0 endif endif lda.w player0height dcp player0y bcc .skipDrawlastP0 ldy player0y lda (player0pointer),y .continuelastP0 sta GRP0 ifnconst no_blank_lines lda missile0height ;3 dcp missile0y ;5 sbc stack1 sta ENAM0 ;3 jmp .endkerloop else ifconst readpaddle ldy currentpaddle lda INPT0,y bpl noreadpaddle2 inc paddle jmp .endkerloop noreadpaddle2 sleep 4 jmp .endkerloop else ; no_blank_lines and no paddle reading sleep 14 jmp .endkerloop endif endif ; ifconst donepaddleskip ;paddleskipread ; this is kind of lame, since it requires 4 cycles from a page boundary crossing ; plus we get a lo-res paddle read ; bmi donepaddleskip ; endif .skipDrawlastP0 sleep 2 lda #0 jmp .continuelastP0 ifconst no_blank_lines no_blank_lines_bailout ldx #0 endif endkernel ; 6 digit score routine stx PF1 stx PF2 stx PF0 clc ifconst pfrowheight lda #pfrowheight+2 else ifnconst pfres lda #10 else lda #(96/pfres)+2 ; try to come close to the real size endif endif sbc playfieldpos sta playfieldpos txa ifconst shakescreen bit shakescreen bmi noshakescreen2 ldx #$3D noshakescreen2 endif sta WSYNC,x ; STA WSYNC ;first one, need one more sta REFP0 sta REFP1 STA GRP0 STA GRP1 ; STA PF1 ; STA PF2 sta HMCLR sta ENAM0 sta ENAM1 sta ENABL lda temp2 ;restore variables that were obliterated by kernel sta player0y lda temp3 sta player1y ifnconst player1colors lda temp6 sta missile1y endif ifnconst playercolors ifnconst readpaddle lda temp5 sta missile0y endif endif lda stack2 sta bally ifconst no_blank_lines sta WSYNC endif lda INTIM clc ifnconst vblank_time adc #43+12+87 else adc #vblank_time+12+87 endif ; sta WSYNC sta TIM64T ifconst minikernel jsr minikernel endif ; now reassign temp vars for score pointers ; score pointers contain: ; score1-5: lo1,lo2,lo3,lo4,lo5,lo6 ; swap lo2->temp1 ; swap lo4->temp3 ; swap lo6->temp5 ifnconst noscore lda scorepointers+1 ; ldy temp1 sta temp1 ; sty scorepointers+1 lda scorepointers+3 ; ldy temp3 sta temp3 ; sty scorepointers+3 sta HMCLR tsx stx stack1 ldx #$10 stx HMP0 sta WSYNC ldx #0 STx GRP0 STx GRP1 ; seems to be needed because of vdel lda scorepointers+5 ; ldy temp5 sta temp5,x ; sty scorepointers+5 lda #>scoretable sta scorepointers+1 sta scorepointers+3 sta scorepointers+5,x sta temp2,x sta temp4,x sta temp6,x LDY #7 STA RESP0 STA RESP1 LDA #$03 STA NUSIZ0 STA NUSIZ1,x STA VDELP0 STA VDELP1 LDA #$20 STA HMP1 LDA scorecolor ; STA HMCLR ; STA WSYNC; second one STA HMOVE ; cycle 73 ? STA COLUP0 STA COLUP1 lda (scorepointers),y sta GRP0 ifconst pfscore lda pfscorecolor sta COLUPF endif lda (scorepointers+8),y sta WSYNC sleep 2 jmp beginscore if ((<*)>$d4) align 256 ; kludge that potentially wastes space! should be fixed! endif loop2 lda (scorepointers),y ;+5 68 204 sta GRP0 ;+3 71 213 D1 -- -- -- ifconst pfscore lda.w pfscore1 sta PF1 else sleep 7 endif ; cycle 0 lda (scorepointers+$8),y ;+5 5 15 beginscore sta GRP1 ;+3 8 24 D1 D1 D2 -- lda (scorepointers+$6),y ;+5 13 39 sta GRP0 ;+3 16 48 D3 D1 D2 D2 lax (scorepointers+$2),y ;+5 29 87 txs lax (scorepointers+$4),y ;+5 36 108 sleep 3 ifconst pfscore lda pfscore2 sta PF1 else sleep 6 endif lda (scorepointers+$A),y ;+5 21 63 stx GRP1 ;+3 44 132 D3 D3 D4 D2! tsx stx GRP0 ;+3 47 141 D5 D3! D4 D4 sta GRP1 ;+3 50 150 D5 D5 D6 D4! sty GRP0 ;+3 53 159 D4* D5! D6 D6 dey bpl loop2 ;+2 60 180 ldx stack1 txs ; lda scorepointers+1 ldy temp1 ; sta temp1 sty scorepointers+1 LDA #0 sta PF1 STA GRP0 STA GRP1 STA VDELP0 STA VDELP1;do we need these STA NUSIZ0 STA NUSIZ1 ; lda scorepointers+3 ldy temp3 ; sta temp3 sty scorepointers+3 ; lda scorepointers+5 ldy temp5 ; sta temp5 sty scorepointers+5 endif ;noscore LDA #%11000010 sta WSYNC STA VBLANK RETURN ifconst shakescreen doshakescreen bit shakescreen bmi noshakescreen sta WSYNC noshakescreen ldx missile0height inx rts endif processor 6502 include "vcs.h" include "macro.h" include "2600basic_variable_redefs.h" player0x = $80 player1x = $81 missile0x = $82 missile1x = $83 ballx = $84 objecty = $85 player0y = $85 player1y = $86 missile1height = $87 missile1y = $88 bally = $89 player1color = $87 ; replaces missile 1 player0pointer = $8A ;uses $8A-$8B player0pointerlo = $8A player0pointerhi = $8B player1pointer = $8C ; $8C-$8D player1pointerlo = $8C player1pointerhi = $8D player0height = $8E player1height = $8F missile0height = $90 missile0y = $91 ballheight = $92 currentpaddle = $90 ; replaces missile 0 (and can't be used with playercolor) paddle = $91 ; replaces missile 0 player0colorstore = $82 ; replaces missile 0 player0color = $90 ; replaces missile 0 score = $93 ; $93-$95 scorepointers = $96 ; $96-$9B = 6 bytes temp1 = $9C ;used by kernel. can be used in program too, but temp2 = $9D ;are obliterated when drawscreen is called. temp3 = $9E temp4 = $9F temp5 = $A0 temp6 = $A1 rand = $A2 scorecolor = $A3 var0 = $A4 var1 = $A5 var2 = $A6 var3 = $A7 var4 = $A8 var5 = $A9 var6 = $AA var7 = $AB var8 = $AC var9 = $AD var10 = $AE var11 = $AF var12 = $B0 var13 = $B1 var14 = $B2 var15 = $B3 var16 = $B4 var17 = $B5 var18 = $B6 var19 = $B7 var20 = $B8 var21 = $B9 var22 = $BA var23 = $BB var24 = $BC var25 = $BD var26 = $BE var27 = $BF var28 = $C0 var29 = $C1 var30 = $C2 var31 = $C3 var32 = $C4 var33 = $C5 var34 = $C6 var35 = $C7 var36 = $C8 var37 = $C9 var38 = $CA var39 = $CB var40 = $CC var41 = $CD var42 = $CE var43 = $CF var44 = $D0 var45 = $D1 var46 = $D2 var47 = $D3 temp7 = $D4 ; This is used to aid in bankswitching playfieldpos = $D5 A = $d6 a = $d6 B = $d7 b = $d7 C = $d8 c = $d8 D = $d9 d = $d9 E = $da e = $da F = $db f = $db G = $dc g = $dc H = $dd h = $dd I = $de i = $de J = $df j = $df K = $e0 k = $e0 L = $e1 l = $e1 M = $e2 m = $e2 N = $e3 n = $e3 O = $e4 o = $e4 P = $e5 p = $e5 Q = $e6 q = $e6 R = $e7 r = $e7 S = $e8 s = $e8 T = $e9 t = $e9 U = $ea u = $ea V = $eb v = $eb W = $ec w = $ec X = $ed x = $ed Y = $ee y = $ee Z = $ef z = $ef ; available for other uses, or if unused, provide more stack space aux1 = $f0 aux2 = $f1 aux3 = $f2 aux4 = $f3 aux5 = $f4 aux6 = $f5 ; playfield color/height pointers pfcolortable = $f0 ; and $d5 pfheighttable = $f0 ; and $d5 ; the above pointers are the same because if color and height are both used together, ; they must used absolute indexed and cannot use pointers lifepointer = $f2 ; pointer to "lives" shape ; upper 3 bits of $f2 contain the number of lives lifecolor = $f4 lives = $f3 ; # lives >> 5 statusbarlength = $f5 ; only uses upper 5 bits; other bits free pfscore1 = $f2 ; optional playfield bytes in score pfscore2 = $f3 pfscorecolor = $f4 stack1 = $f6 stack2 = $f7 stack3 = $f8 stack4 = $f9 ; the stack bytes above may be used in the kernel ; stack = F6-F7, F8-F9, FA-FB, FC-FD, FE-FF MAC RETURN ; auto-return from either a regular or bankswitched module ifnconst bankswitch rts else jmp BS_return endif ENDM ifconst superchip playfieldbase = $10D0 else playfieldbase = $A4 endif ; define playfield start based on height ifnconst pfres playfield = playfieldbase else playfield = playfieldbase-(pfres-12)*4 endif ; every bank has this stuff at the same place ; this code can switch to/from any bank at any entry point ; and can preserve register values ; note: lines not starting with a space are not placed in all banks ; ; line below tells the compiler how long this is - do not remove ;size=32 begin_bscode ldx #$ff txs lda #>(start-1) pha lda #<(start-1) pha BS_return pha txa pha tsx lda 4,x ; get high byte of return address rol rol rol rol and #bs_mask ;1 3 or 7 for F8/F6/F4 tax inx BS_jsr lda bankswitch_hotspot-1,x pla tax pla rts if ((* & $1FFF) > ((bankswitch_hotspot & $1FFF) - 1)) echo "WARNING: size parameter in banksw.asm too small - the program probably will not work." echo "Change to",[(*-begin_bscode+1)&$FF]d,"and try again." endif processor 6502 include "vcs.h" include "macro.h" include "multisprite.h" include "2600basic_variable_redefs.h" ifconst bankswitch if bankswitch == 8 ORG $1000 RORG $D000 endif if bankswitch == 16 ORG $1000 RORG $9000 endif if bankswitch == 32 ORG $1000 RORG $1000 endif else ORG $F000 endif ; y and a contain multiplicands, result in a mul8 sty temp1 sta temp2 lda #0 reptmul8 lsr temp2 bcc skipmul8 clc adc temp1 ;bcs donemul8 might save cycles? skipmul8 ;beq donemul8 might save cycles? asl temp1 bne reptmul8 donemul8 RETURN div8 ; a=numerator y=denominator, result in a cpy #2 bcc div8end+1;div by 0 = bad, div by 1=no calc needed, so bail out sty temp1 ldy #$ff div8loop sbc temp1 iny bcs div8loop div8end tya ; result in a RETURN minikernel ; display up to 6 lives on screen sta WSYNC ldx #$20 stx HMP1 stx VDELP0 lda lives lsr lsr lsr lsr lsr sta RESP0 sta RESP1 stx VDELP1 tax lda lifenusiz0table,x sta NUSIZ0 lda lifenusiz1table,x sta NUSIZ1 lda lifecolor sta COLUP0 sta COLUP1 lda #$10 sta HMP0 lda statusbarlength lsr lsr lsr ; 0-31 ; 3 cases: 0-7, 8-15, 16-24 ; if 0-7, temp1=val, temp2=0, temp3=0 ; if 8-15, temp1=255, temp2=val (rev), temp3=0 ; if 16-23, temp1=255, temp2=255, temp3=val tay sta HMOVE ;cycle 74? ifconst statusbarcolor ; only write COLUPF if color variable exists, otherwise use existing PF color lda statusbarcolor sta COLUPF endif cmp #8 bcc zero_7 cmp #16 bcc eight_15 lda #255 sta temp1 sta temp2 lda statustable-16,y sta temp3 lda statustable,y sta temp4 jmp startlifedisplay zero_7 lda #0 sta temp4 sta temp3 sta temp2 lda statustable,y sta temp1 jmp startlifedisplay eight_15 lda #255 sta temp1 lda #0 sta temp4 sta temp3 lda statustable+16,y sta temp2 startlifedisplay ldy #7 lifeloop sta WSYNC stx PF0 lda (lifepointer),y cpx #0 bne onelife .byte $0C onelife sta GRP0 cpx #2 bcs nolives .byte $0C nolives sta GRP1 lda temp4 sta PF0 lda temp1 sta PF2 lda temp3 sta PF1 lda temp2 sta PF2 ;cycle 48! sleep 14 lda #0 dey sta PF1 bpl lifeloop sta WSYNC iny sty PF0 sty PF2 sty PF1 sty GRP0 sty GRP1 rts if (<*) > $F5 align 256 endif lifenusiz1table .byte 0 lifenusiz0table .byte 0,0,0,1,1,3,3,3 statustable ;0-7 and 16+ .byte %00000000 .byte %00000001 .byte %00000011 .byte %00000111 .byte %00001111 .byte %00011111 .byte %00111111 .byte %01111111 .byte 255 .byte 255 .byte 255 .byte 255 .byte 255 .byte 255 .byte 255 .byte 255 ; 8-15 .byte 0 .byte 0 .byte 0 .byte 0 .byte 0 .byte 0 .byte 0 .byte 0 .byte %00000000 .byte %10000000 .byte %11000000 .byte %11100000 .byte %11110000 .byte %11111000 .byte %11111100 .byte %11111110 FineAdjustTableBegin .byte %01100000 ;left 6 .byte %01010000 .byte %01000000 .byte %00110000 .byte %00100000 .byte %00010000 .byte %00000000 ;left 0 .byte %11110000 .byte %11100000 .byte %11010000 .byte %11000000 .byte %10110000 .byte %10100000 .byte %10010000 .byte %10000000 ;right 8 FineAdjustTableEnd = FineAdjustTableBegin - 241 PFStart .byte 87,43,0,21,0,0,0,10 blank_pf .byte 0,0,0,0,0,0,0,5 ; .byte 43,21,0,10,0,0,0,5 ifconst screenheight pfsub .byte 8,4,2,2,1,0,0,1,0 endif ;--set initial P1 positions multisprite_setup lda #15 sta pfheight ldx #4 ; stx temp3 SetCopyHeight ; lda #76 ; sta NewSpriteX,X ; lda CopyColorData,X ; sta NewCOLUP1,X ;lda SpriteHeightTable,X ; sta spriteheight,x txa sta SpriteGfxIndex,X sta spritesort,X dex bpl SetCopyHeight ; since we can't turn off pf, point PF to zeros here lda #>blank_pf sta PF2pointer+1 sta PF1pointer+1 lda #temp1 ; swap lo4->temp3 ; swap lo6->temp5 lda scorepointers+5 sta temp5 lda scorepointers+1 sta temp1 lda scorepointers+3 sta temp3 lda #>scoretable sta scorepointers+1 sta scorepointers+3 sta scorepointers+5 sta temp2 sta temp4 sta temp6 rts ;------------------------------------------------------------------------- ;----------------------Kernel Routine------------------------------------- ;------------------------------------------------------------------------- ;------------------------------------------------------------------------- ; echo * ; repeat $f147-* ; brk ; repend ; org $F240 SwitchDrawP0K1 ; 72 lda P0Bottom sta P0Top ;+6 2 jmp BackFromSwitchDrawP0K1 ;+3 5 WaitDrawP0K1 ; 74 SLEEP 4 ;+4 2 jmp BackFromSwitchDrawP0K1 ;+3 5 SkipDrawP1K1 ; 11 lda #0 sta GRP1 ;+5 16 so Ball gets drawn jmp BackFromSkipDrawP1 ;+3 19 ;------------------------------------------------------------------------- KernelRoutine ifnconst screenheight jsr wastetime ; waste 12 cycles else sleep 6 endif tsx stx stack1 ldx #ENABL txs ;+9 9 ldx #0 lda pfheight bpl asdhj .byte $24 asdhj tax ; ldx pfheight lda PFStart,x ; get pf pixel resolution for heights 15,7,3,1,0 ifconst screenheight sec if screenheight == 84 sbc pfsub+1,x else sbc pfsub,x endif endif sta pfpixelheight ifconst screenheight ldy #screenheight else ldy #88 endif ; lda #$02 ; sta COLUBK ;+5 18 ; sleep 25 sleep 2 KernelLoopa ; 50 SLEEP 7 ;+4 54 KernelLoopb ; 54 SLEEP 2 ;+12 66 cpy P0Top ;+3 69 beq SwitchDrawP0K1 ;+2 71 bpl WaitDrawP0K1 ;+2 73 lda (player0pointer),Y ;+5 2 sta GRP0 ;+3 5 VDEL because of repokernel BackFromSwitchDrawP0K1 cpy P1Bottom ;+3 8 unless we mean to draw immediately, this should be set ; to a value greater than maximum Y value initially bcc SkipDrawP1K1 ;+2 10 lda (P1display),Y ;+5 15 sta.w GRP1 ;+4 19 BackFromSkipDrawP1 ;fuck sty temp1 ldy pfpixelheight lax (PF1pointer),y stx PF1 ;+7 26 lda (PF2pointer),y sta PF2 ;+7 33 ;sleep 6 stx PF1temp2 sta PF2temp2 dey lda (PF1pointer),y sta PF1temp1 lda (PF2pointer),y sta PF2temp1 ldy temp1 ldx #ENABL txs cpy bally php ;+6 39 VDEL ball cpy missile1y php ;+6 71 cpy missile0y php ;+6 1 ldx #1 dey ;+2 15 cpy RepoLine ;+3 18 beq RepoKernel ;+2 20 ; SLEEP 20 ;+23 43 sleep 6 newrepo ; since we have time here, store next repoline ldx SpriteIndex lda SpriteGfxIndex-1,x tax lda NewSpriteY,x sta temp6 sleep 4 BackFromRepoKernel tya ;+2 45 and pfheight ;+2 47 bne KernelLoopa ;+2 49 dec pfpixelheight bpl KernelLoopb ;+3 54 ; bmi donewkernel ;+3 54 ; bne KernelLoopb+1 ;+3 54 donewkernel jmp DoneWithKernel ;+3 56 ;------------------------------------------------------------------------- ; room here for score? setscorepointers lax score+2 jsr scorepointerset sty scorepointers+5 stx scorepointers+2 lax score+1 jsr scorepointerset sty scorepointers+4 stx scorepointers+1 lax score jsr scorepointerset sty scorepointers+3 stx scorepointers wastetime rts scorepointerset and #$0F asl asl asl adc #=temp1) cmp spriteheight,x bcs countdown ; overlap with x+1>x ; ; stick x at end of gfxtable, dec counter overlapping dec temp3 ldx temp2 inx jsr shiftnumbers jmp skipswapGfxtable largerXislower ; (temp1>A) tay ldx temp2 lda spritesort,x tax tya eor #$FF cmp spriteheight,x bcs notoverlapping dec temp3 ldx temp2 inx jsr shiftnumbers jmp skipswapGfxtable notoverlapping ldx temp2 ; swap display table ldy SpriteGfxIndex+1,x lda SpriteGfxIndex,x sty SpriteGfxIndex,x sta SpriteGfxIndex+1,x skipswapGfxtable ldx temp2 ; swap sort table ldy spritesort+1,x lda spritesort,x sty spritesort,x sta spritesort+1,x countdown dec temp2 bpl sortloop checktoohigh ldx temp3 lda SpriteGfxIndex,x tax lda NewSpriteY,x ifconst screenheight cmp #screenheight-2 else cmp #$56 endif bcc nonetoohigh dec temp3 bne checktoohigh nonetoohigh rts shiftnumbers ; stick current x at end, shift others down ; if x=4: don't do anything ; if x=3: swap 3 and 4 ; if x=2: 2=3, 3=4, 4=2 ; if x=1: 1=2, 2=3, 3=4, 4=1 ; if x=0: 0=1, 1=2, 2=3, 3=4, 4=0 ldy SpriteGfxIndex,x swaploop cpx #4 beq shiftdone lda SpriteGfxIndex+1,x sta SpriteGfxIndex,x inx jmp swaploop shiftdone sty SpriteGfxIndex,x rts ifconst debugscore debugcycles ldx #14 lda INTIM ; display # cycles left in the score ifconst mincycles lda mincycles cmp INTIM lda mincycles bcc nochange lda INTIM sta mincycles nochange endif ; cmp #$2B ; bcs no_cycles_left bmi cycles_left ldx #64 eor #$ff ;make negative cycles_left stx scorecolor and #$7f ; clear sign bit tax lda scorebcd,x sta score+2 lda scorebcd1,x sta score+1 rts scorebcd .byte $00, $64, $28, $92, $56, $20, $84, $48, $12, $76, $40 .byte $04, $68, $32, $96, $60, $24, $88, $52, $16, $80, $44 .byte $08, $72, $36, $00, $64, $28, $92, $56, $20, $84, $48 .byte $12, $76, $40, $04, $68, $32, $96, $60, $24, $88 scorebcd1 .byte 0, 0, 1, 1, 2, 3, 3, 4, 5, 5, 6 .byte 7, 7, 8, 8, 9, $10, $10, $11, $12, $12, $13 .byte $14, $14, $15, $16, $16, $17, $17, $18, $19, $19, $20 .byte $21, $21, $22, $23, $23, $24, $24, $25, $26, $26 endif ; ; Inclues go below - order is crucial, since this is also the order in which ; they will appear in the generated assembly file ; ; header file 2600basicheader.asm ; standard kernel: two players, two missiles, a ball and an asymmetric playfield. std_kernel.asm ; standard startup routine. startup.asm ; below are collections of subroutines and functions ; if you have any more to add, put them immediately below this line. pf_drawing.asm pf_scrolling.asm std_routines.asm ; The overscan routine goes below. it sets up sprites for the std_kernel. ; if you have any routines that will not run until the overscan period, ; put them immediately below this line. std_overscan.asm ; below is the generated batari Basic file bB.asm ; score graphics. score_graphics.asm ; below is the footer, which contains the score digits and startup vectors. ; If you want to create your own custom score digits, you may hack the file below, ; but first you should rename it to something else. 2600basicfooter.asm processor 6502 include "vcs.h" include "macro.h" include "2600basic.h" include "2600basic_variable_redefs.h" ifconst bankswitch if bankswitch == 8 ORG $1000 RORG $D000 endif if bankswitch == 16 ORG $1000 RORG $9000 endif if bankswitch == 32 ORG $1000 RORG $1000 endif else ORG $F000 endif repeat 256 .byte $ff repend pfscroll ;(a=0 left, 1 right, 2 up, 4 down, 6=upup, 12=downdown) bne notleft ;left ifconst pfres ldx #pfres*4 else ldx #48 endif leftloop lda playfield-1,x lsr ifconst superchip lda playfield-2,x rol sta playfield-130,x lda playfield-3,x ror sta playfield-131,x lda playfield-4,x rol sta playfield-132,x lda playfield-1,x ror sta playfield-129,x else rol playfield-2,x ror playfield-3,x rol playfield-4,x ror playfield-1,x endif txa sbx #4 bne leftloop RETURN notleft lsr bcc notright ;right ifconst pfres ldx #pfres*4 else ldx #48 endif rightloop lda playfield-4,x lsr ifconst superchip lda playfield-3,x rol sta playfield-131,x lda playfield-2,x ror sta playfield-130,x lda playfield-1,x rol sta playfield-129,x lda playfield-4,x ror sta playfield-132,x else rol playfield-3,x ror playfield-2,x rol playfield-1,x ror playfield-4,x endif txa sbx #4 bne rightloop RETURN notright lsr bcc notup ;up lsr bcc onedecup dec playfieldpos onedecup dec playfieldpos beq shiftdown bpl noshiftdown2 shiftdown ifconst pfrowheight lda #pfrowheight else ifnconst pfres lda #8 else lda #(96/pfres) ; try to come close to the real size endif endif sta playfieldpos lda playfield+3 sta temp4 lda playfield+2 sta temp3 lda playfield+1 sta temp2 lda playfield sta temp1 ldx #0 up2 lda playfield+4,x ifconst superchip sta playfield-128,x lda playfield+5,x sta playfield-127,x lda playfield+6,x sta playfield-126,x lda playfield+7,x sta playfield-125,x else sta playfield,x lda playfield+5,x sta playfield+1,x lda playfield+6,x sta playfield+2,x lda playfield+7,x sta playfield+3,x endif txa sbx #252 ifconst pfres cpx #(pfres-1)*4 else cpx #44 endif bne up2 lda temp4 ifconst superchip ifconst pfres sta playfield+pfres*4-129 lda temp3 sta playfield+pfres*4-130 lda temp2 sta playfield+pfres*4-131 lda temp1 sta playfield+pfres*4-132 else sta playfield+47-128 lda temp3 sta playfield+46-128 lda temp2 sta playfield+45-128 lda temp1 sta playfield+44-128 endif else ifconst pfres sta playfield+pfres*4-1 lda temp3 sta playfield+pfres*4-2 lda temp2 sta playfield+pfres*4-3 lda temp1 sta playfield+pfres*4-4 else sta playfield+47 lda temp3 sta playfield+46 lda temp2 sta playfield+45 lda temp1 sta playfield+44 endif endif noshiftdown2 RETURN notup ;down lsr bcs oneincup inc playfieldpos oneincup inc playfieldpos lda playfieldpos ifconst pfrowheight cmp #pfrowheight+1 else ifnconst pfres cmp #9 else cmp #(96/pfres)+1 ; try to come close to the real size endif endif bcc noshiftdown lda #1 sta playfieldpos ifconst pfres lda playfield+pfres*4-1 sta temp4 lda playfield+pfres*4-2 sta temp3 lda playfield+pfres*4-3 sta temp2 lda playfield+pfres*4-4 else lda playfield+47 sta temp4 lda playfield+46 sta temp3 lda playfield+45 sta temp2 lda playfield+44 endif sta temp1 ifconst pfres ldx #(pfres-1)*4 else ldx #44 endif down2 lda playfield-1,x ifconst superchip sta playfield-125,x lda playfield-2,x sta playfield-126,x lda playfield-3,x sta playfield-127,x lda playfield-4,x sta playfield-128,x else sta playfield+3,x lda playfield-2,x sta playfield+2,x lda playfield-3,x sta playfield+1,x lda playfield-4,x sta playfield,x endif txa sbx #4 bne down2 lda temp4 ifconst superchip sta playfield-125 lda temp3 sta playfield-126 lda temp2 sta playfield-127 lda temp1 sta playfield-128 else sta playfield+3 lda temp3 sta playfield+2 lda temp2 sta playfield+1 lda temp1 sta playfield endif noshiftdown RETURN ;standard routines needed for pretty much all games ; just the random number generator is left - maybe we should remove this asm file altogether? ; repositioning code and score pointer setup moved to overscan ; read switches, joysticks now compiler generated (more efficient) randomize lda rand lsr ifconst rand16 rol rand16 endif bcc noeor eor #$B4 noeor sta rand ifconst rand16 eor rand16 endif RETURN processor 6502 include "vcs.h" include "macro.h" include "2600basic.h" include "2600basic_variable_redefs.h" ifconst bankswitch if bankswitch == 8 ORG $1000 RORG $D000 endif if bankswitch == 16 ORG $1000 RORG $9000 endif if bankswitch == 32 ORG $1000 RORG $1000 endif else ORG $F000 endif ; ; Inclues go below - order is crucial, since this is also the order in which ; they will appear in the generated assembly file ; ; header file multispriteheader.asm ; this is the batari Basic file ; for bankswitching, the concatenator will only parse until the end of ; bank 1 bB.asm ; standard kernel: two players, two missiles, a ball and an asymmetric playfield. multisprite_kernel.asm ; standard startup routine. startup.asm ; below are collections of subroutines and functions ; if you have any more to add, put them immediately below this line. std_routines.asm ; below is the generated batari Basic file ; note: this file is generated by the concatenation program. ; automatically split off from the bB.asm file where the new bank occurs bB2.asm ; score gfx score_graphics.asm ;bankswitch support banksw.asm ; below is the footer, which contains the score digits and startup vectors. ; If you want to create your own custom score digits, you may hack the file below, ; but first you should rename it to something else. ; also includes bankswitching support (if applicable) 2600basicfooter.asm start sei cld ldy #0 lda $D0 cmp #$2C ;check RAM location #1 bne MachineIs2600 lda $D1 cmp #$A9 ;check RAM location #2 bne MachineIs2600 dey MachineIs2600 ldx #0 txa clearmem inx txs pha bne clearmem sty temp1 ifconst pfrowheight lda pfrowheight else ifconst pfres lda #(96/pfres) else lda #8 endif endif sta playfieldpos ldx #5 initscore lda #(game-1) pha lda #<(game-1) pha pha pha ldx #1 jmp BS_jsr endif ; playfield drawing routines ; you get a 32x12 bitmapped display in a single color :) ; 0-31 and 0-11 pfclear ; clears playfield - or fill with pattern ifconst pfres ldx #pfres*4-1 else ldx #47 endif pfclear_loop ifnconst superchip sta playfield,x else sta playfield-128,x endif dex bpl pfclear_loop RETURN setuppointers stx temp2 ; store on.off.flip value tax ; put x-value in x lsr lsr lsr ; divide x pos by 8 sta temp1 tya asl asl ; multiply y pos by 4 clc adc temp1 ; add them together to get actual memory location offset tay ; put the value in y lda temp2 ; restore on.off.flip value rts pfread ;x=xvalue, y=yvalue jsr setuppointers lda setbyte,x and playfield,y eor setbyte,x ; beq readzero ; lda #1 ; readzero RETURN pfpixel ;x=xvalue, y=yvalue, a=0,1,2 jsr setuppointers ifconst bankswitch lda temp2 ; load on.off.flip value (0,1, or 2) beq pixelon_r ; if "on" go to on lsr bcs pixeloff_r ; value is 1 if true lda playfield,y ; if here, it's "flip" eor setbyte,x ifconst superchip sta playfield-128,y else sta playfield,y endif RETURN pixelon_r lda playfield,y ora setbyte,x ifconst superchip sta playfield-128,y else sta playfield,y endif RETURN pixeloff_r lda setbyte,x eor #$ff and playfield,y ifconst superchip sta playfield-128,y else sta playfield,y endif RETURN else jmp plotpoint endif pfhline ;x=xvalue, y=yvalue, a=0,1,2, temp3=endx jsr setuppointers jmp noinc keepgoing inx txa and #7 bne noinc iny noinc jsr plotpoint cpx temp3 bmi keepgoing RETURN pfvline ;x=xvalue, y=yvalue, a=0,1,2, temp3=endx jsr setuppointers sty temp1 ; store memory location offset inc temp3 ; increase final x by 1 lda temp3 asl asl ; multiply by 4 sta temp3 ; store it ; Thanks to Michael Rideout for fixing a bug in this code ; right now, temp1=y=starting memory location, temp3=final ; x should equal original x value keepgoingy jsr plotpoint iny iny iny iny cpy temp3 bmi keepgoingy RETURN plotpoint lda temp2 ; load on.off.flip value (0,1, or 2) beq pixelon ; if "on" go to on lsr bcs pixeloff ; value is 1 if true lda playfield,y ; if here, it's "flip" eor setbyte,x ifconst superchip sta playfield-128,y else sta playfield,y endif rts pixelon lda playfield,y ora setbyte,x ifconst superchip sta playfield-128,y else sta playfield,y endif rts pixeloff lda setbyte,x eor #$ff and playfield,y ifconst superchip sta playfield-128,y else sta playfield,y endif rts setbyte .byte $80 .byte $40 .byte $20 .byte $10 .byte $08 .byte $04 .byte $02 .byte $01 .byte $01 .byte $02 .byte $04 .byte $08 .byte $10 .byte $20 .byte $40 .byte $80 .byte $80 .byte $40 .byte $20 .byte $10 .byte $08 .byte $04 .byte $02 .byte $01 .byte $01 .byte $02 .byte $04 .byte $08 .byte $10 .byte $20 .byte $40 .byte $80 ; feel free to modify the score graphics - just keep each digit 8 high ; and keep the conditional compilation stuff intact ifconst ROM2k ORG $F7AC else ifconst bankswitch if bankswitch == 8 ORG $2F94-bscode_length RORG $FF94-bscode_length endif if bankswitch == 16 ORG $4F94-bscode_length RORG $FF94-bscode_length endif if bankswitch == 32 ORG $8F94-bscode_length RORG $FF94-bscode_length endif else ORG $FF9C endif endif scoretable .byte %00111100 .byte %01100110 .byte %01100110 .byte %01100110 .byte %01100110 .byte %01100110 .byte %01100110 .byte %00111100 .byte %01111110 .byte %00011000 .byte %00011000 .byte %00011000 .byte %00011000 .byte %00111000 .byte %00011000 .byte %00001000 .byte %01111110 .byte %01100000 .byte %01100000 .byte %00111100 .byte %00000110 .byte %00000110 .byte %01000110 .byte %00111100 .byte %00111100 .byte %01000110 .byte %00000110 .byte %00000110 .byte %00011100 .byte %00000110 .byte %01000110 .byte %00111100 .byte %00001100 .byte %00001100 .byte %01111110 .byte %01001100 .byte %01001100 .byte %00101100 .byte %00011100 .byte %00001100 .byte %00111100 .byte %01000110 .byte %00000110 .byte %00000110 .byte %00111100 .byte %01100000 .byte %01100000 .byte %01111110 .byte %00111100 .byte %01100110 .byte %01100110 .byte %01100110 .byte %01111100 .byte %01100000 .byte %01100010 .byte %00111100 .byte %00110000 .byte %00110000 .byte %00110000 .byte %00011000 .byte %00001100 .byte %00000110 .byte %01000010 .byte %00111110 .byte %00111100 .byte %01100110 .byte %01100110 .byte %01100110 .byte %00111100 .byte %01100110 .byte %01100110 .byte %00111100 .byte %00111100 .byte %01000110 .byte %00000110 .byte %00111110 .byte %01100110 .byte %01100110 .byte %01100110 .byte %00111100 ifconst ROM2k ORG $F7FC else ifconst bankswitch if bankswitch == 8 ORG $2FF4-bscode_length RORG $FFF4-bscode_length endif if bankswitch == 16 ORG $4FF4-bscode_length RORG $FFF4-bscode_length endif if bankswitch == 32 ORG $8FF4-bscode_length RORG $FFF4-bscode_length endif else ORG $FFFC endif endif pfread cmp #16 bcc lefthalf eor #31 ; 16-31 converted to 15-0 lefthalf tax lda bytemask,x cpx #8 bcc bytedone and (PF2pointer),y .byte $0C bytedone and (PF1pointer),y RETURN bytemask .byte $80,$40,$20,$10,8,4,2,1 .byte 1,2,4,8,$10,$20,$40,$80 ; Fixed point math routines - created by AtariAge member djmips ; some changes by Fred Quimby ;assignment from 8.8 to 4.4 Assign88to44: ; A(4.4) = A,X(8.8) stx temp1 rol temp1 asl rol temp1 asl rol temp1 asl rol temp1 asl rts ;assignment from 4.4 to 8.8 ; Assign44to88: ; A,X(8.8) = A(4.4) sta temp1 lda #0 asl temp1 sbc #0 ; eor #$ff ; do sign extend rol asl temp1 rol asl temp1 rol asl temp1 rol ldx temp1 rts ifconst bankswitch Assign88to44bs: ; A(4.4) = A,X(8.8) stx temp1 rol temp1 asl rol temp1 asl rol temp1 asl rol temp1 asl RETURN ;assignment from 4.4 to 8.8 ; Assign44to88bs: ; A,X(8.8) = A(4.4) sta temp1 lda #0 asl temp1 sbc #0 ; eor #$ff ; do sign extend rol asl temp1 rol asl temp1 rol asl temp1 rol ldx temp1 RETURN endif ; ;Addition/subtraction asm procedures: ;add/sub 8.8 to/from 4.4 Add88to44: ; A(4.4) = A,X(8.8) + Y(4.4) jsr Assign88to44 sty temp1 clc adc temp1 rts Sub88from44: ; A(4.4) = A,X(8.8) - Y(4.4) jsr Assign88to44 sty temp1 sec sbc temp1 rts Add44to88: ; A,X(8.8) = A,X(8.8) + Y(4.4) sta temp2 stx temp3 tya jsr Assign44to88 clc sta temp1 txa adc temp3 tax lda temp1 adc temp2 rts Sub44from88: ; A,X(8.8) = A,X(8.8) - Y(4.4) sta temp2 stx temp3 tya jsr Assign44to88 sec sta temp1 lda temp3 stx temp3 sbc temp3 tax lda temp2 sbc temp1 rts missile0x = $80 missile1x = $81 ballx = $82 objecty = $83 missile0y = $83 missile1y = $84 bally = $85 ; multisprite stuff below - 5 bytes each starting with spritex SpriteIndex = $86 player0x = $87 NewSpriteX = $88 ; X position player1x = $88 player2x = $89 player3x = $8A player4x = $8B player5x = $8C player0y = $8D NewSpriteY = $8E ; Y position player1y = $8E player2y = $8F player3y = $90 player4y = $91 player5y = $92 NewNUSIZ = $93 _NUSIZ1 = $93 NUSIZ2 = $94 NUSIZ3 = $95 NUSIZ4 = $96 NUSIZ5 = $97 NewCOLUP1 = $98 _COLUP1 = $98 COLUP2 = $99 COLUP3 = $9A COLUP4 = $9B COLUP5 = $9C SpriteGfxIndex = $9D player0pointer = $A2 player0pointerlo = $A2 player0pointerhi = $A3 ;P0Top = $A4 P0Top = temp5 P0Bottom = $A4 P1Bottom = $A5 player1pointerlo = $A6 player2pointerlo = $A7 player3pointerlo = $A8 player4pointerlo = $A9 player5pointerlo = $AA player1pointerhi = $AB player2pointerhi = $AC player3pointerhi = $AD player4pointerhi = $AE player5pointerhi = $AF player0height = $B0 spriteheight = $B1 ; heights of multiplexed player sprite player1height = $B1 player2height = $B2 player3height = $B3 player4height = $B4 player5height = $B5 PF1temp1 = $B6 PF1temp2 = $B7 PF2temp1 = $B8 PF2temp2 = $B9 pfpixelheight = $BA ; playfield is now a pointer to graphics playfield = $BB PF1pointer = $BB PF2pointer = $BD statusbarlength = $BF aux3 = $BF lifecolor = $C0 pfscorecolor = $C0 aux4 = $C0 P1display = temp2 ; temp2 and temp3 lifepointer = $c1 lives = $c2 pfscore1 = $c1 pfscore2 = $c2 aux5 = $c1 aux6 = $c2 playfieldpos = $C3 RepoLine = temp4 scorepointers = $C4 temp1 = $CA ;used by kernel. can be used in program too, but temp2 = $CB ;are obliterated when drawscreen is called. temp3 = $CC temp4 = $CD temp5 = $CE temp6 = $CF temp7 = $D0 ; This is used to aid in bankswitching score = $D1 pfheight = $D4 scorecolor = $D5 ;need to find other places for these, possibly... rand = $D6 A = $d7 a = $d7 B = $d8 b = $d8 C = $d9 c = $d9 D = $da d = $da E = $db e = $db F = $dc f = $dc G = $dd g = $dd H = $de h = $de I = $df i = $df J = $e0 j = $e0 K = $e1 k = $e1 L = $e2 l = $e2 M = $e3 m = $e3 N = $e4 n = $e4 O = $e5 o = $e5 P = $e6 p = $e6 Q = $e7 q = $e7 R = $e8 r = $e8 S = $e9 s = $e9 T = $ea t = $ea U = $eb u = $eb V = $ec v = $ec W = $ed w = $ed X = $ee x = $ee Y = $ef y = $ef Z = $f0 z = $f0 spritesort = $f1 ; helps with flickersort spritesort2 = $f2 ; helps with flickersort spritesort3 = $f3 spritesort4 = $f4 spritesort5 = $f5 stack1 = $f6 stack2 = $f7 stack3 = $f8 stack4 = $f9 ; the stack bytes above may be used in the kernel ; stack = F6-F7, F8-F9, FA-FB, FC-FD, FE-FF MAC RETURN ; auto-return from either a regular or bankswitched module ifnconst bankswitch rts else jmp BS_return endif ENDM ; ; Inclues go below - order is crucial, since this is also the order in which ; they will appear in the generated assembly file ; ; header file multispriteheader.asm multisprite_kernel.asm ; standard startup routine. startup.asm ; below are collections of subroutines and functions ; if you have any more to add, put them immediately below this line. std_routines.asm ; The overscan routine goes below. it sets up sprites for the std_kernel. ; if you have any routines that will not run until the overscan period, ; put them immediately below this line. ; below is the generated batari Basic file bB.asm ; score graphics. score_graphics.asm ; below is the footer, which contains the score digits and startup vectors. ; If you want to create your own custom score digits, you may hack the file below, ; but first you should rename it to something else. 2600basicfooter.asm