diff --git a/vcs/include/arena.a02 b/vcs/include/arena.a02 new file mode 100644 index 0000000..619969b --- /dev/null +++ b/vcs/include/arena.a02 @@ -0,0 +1,148 @@ +;arena.a02 - Two Line Arena Kernal for Atari 2600 +;Requires Constants ARLINS, P0LINS and P1LINS + +P0DRAW EQU $D0 ;Player 0 Draw Counter +P1DRAW EQU $D1 ;Player 1 Draw Counter +P0PTRL EQU $D2 ;Player 0 Graphics Pointer +P0PTRH EQU $D3 +P1PTRL EQU $D4 ;Player 0 Graphics Pointer +P1PTRH EQU $D5 + +P0OFST: STA TEMP0 ;Save Multiplier + BEQ POFFSX ;If 0, Return + LDA #P0LINS ;Load # of Lines + BNE POFFST + +P1OFST: STA TEMP0 ;Save Multiplier + BEQ POFFSX ;If 0, Return + LDA #P1LINS ;Load # of Lines +POFFST: STA TEMP1 +POFFSL: TXA + CLC + ADC TEMP1 + TAX + TYA + ADC #0 + TAY + DEC TEMP0 + BNE POFFSL +POFFSX: RTS + +;p0prep() - Prepare Player 0 for Display +;Args: A - Y-Position +; X,Y - Address of Graphics Data +;Uses: ARLINS, P0LINS +;Sets: TEMP0 - Y-Position +;Affects; A,C,N,Z +P0PREP: LSR ;Divide by 2 for Two-line Position + STA TEMP0 ;Save Y Position + ROL ;Rotate Carry into Bit 1 + EOR #1 ;Reverse It + STA VDELP0 ;and Store in Vertical Delay Register + LDA #ARLINS ;Draw = Top Line + Height - Y Position + CLC + ADC #P0LINS + SEC + SBC TEMP0 + STA P0DRAW + TXA ;Pointer = GfxAddr + Height - 1 - Y Position + CLC + ADC #P0LINS-1 + TAX + TYA + ADC #0 + TAY + TXA + SEC + SBC TEMP0 + STA P0PTRL + TYA + SBC #0 + STA P0PTRH + RTS + +;p1prep() - Prepare Player 1 for Display +;Args: A - Y-Position +; X,Y - Address of Graphics Data +;Uses: ARLINS, P1LINS +;Sets: TEMP1 - Y-Position +;Affects; A,C,N,Z +P1PREP: CLC ;Add 1 to Y-Position + ADC #1 ;to Compensate for GRP1 Priming + LSR ;Divide by 2 for Two-line Position + STA TEMP1 ;Save Y Position + ROL ;Rotate Carry into Bit 1 + EOR #1 ;Reverse It + STA VDELP1 ;and Store in Vertical Delay Register + LDA #ARLINS ;Draw = Top Line + Height - Y Position + 1 + CLC + ADC #P1LINS+1 + SEC + SBC TEMP1 + STA P1DRAW + TXA ;Pointer = GfxAddr + Height - 1 - Y Position + CLC + ADC #P1LINS-1 + TAX + TYA + ADC #0 + TAY + TXA + SEC + SBC TEMP1 + STA P1PTRL + TYA + SBC #0 + STA P1PTRH + RTS + +;ardisp() - Kernel Display Routine +;Args: A = Playfield Color +;Uses: ARLINS, P0LINS, P1LINS, P0PTRL, P1PTRL +;Affects: A,X,Y,C,N,Z +ARDISP: STA COLUPF + LDY #ARLINS+1 ; 2 14 - Number of Kernal Lines (Scanlines / 2) + LDX #$FF ; - Initialize Playfield Index + LDA #1 ; - Reflect Playfield + STA CTRLPF ; - Set Playfield Control Register + LDA #P1LINS-1 ; - Preset GRP1 if Player 1 on Top Line + DCP P1DRAW ; + BCS ARDIS0 ; + LDA #0 ; + BYTE $2C ; +ARDIS0: LDA (P1PTRL),Y ; + STA GRP1 ; 3 6 + DEY ; 2 ?? +ARDISL: TYA ; 2 29 - Get Loop Counter + AND #ARMULT-1 ; 2 31 - Mask Against Multiplier + BNE ARDISS ; 2 33 If 0 + INX ; 2 35 - Increment Playfield Pointer +ARDISS: LDA #P0LINS-1 ; 2 15 - Player 1 Height minus 1 due to STArting with 0 + DCP P0DRAW ; 5 20 - Decrement P0DRAW and compare with height + BCS ARDIS1 ; 2 22 - If Player 0 not on Current Scanline + LDA #0 ; 2 24 - Load 0 (No Graphics) + BYTE $2C ; 4 28 - Else (BIT trick) +ARDIS1: LDA (P0PTRL),Y ;(5 28)- Load Player 0 Graphics Line + STA WSYNC ; 3 31 - Start Line 2 + STA GRP0 ; 3 3 - Set Player 0 Graphics Data + LDA ARENA0,X ; 4 7 - get current scanline's playfield pattern + STA PF0 ; 3 10 - @0-22 and update it + LDA ARENA1,X ; 4 14 - get current scanline's playfield pattern + STA PF1 ; 3 17 - @71-28 and update it + LDA ARENA2,X ; 4 21 - get current scanline's playfield pattern + STA PF2 ; 3 24 - @60-39 + LDA #P1LINS-1 ; 2 26 - Player 1 Height minus 1 due to STArting with 0 + DCP P1DRAW ; 5 31 - Load 0 (No Graphics) + BCS ARDIS2 ; 2 33 - If Player 1 not on Current Scanline + LDA #0 ; 2 35 - Load 0 (No Graphics) + BYTE $2C ; 4 39 - Else (BIT trick) +ARDIS2: LDA (P1PTRL),Y ;(5 39)- Load Player 1 Graphics Line + STA WSYNC ; 3 42 - Start Line 2 + STA GRP1 ; 3 3 - Set Player 1 Graphics Data + DEY ; 2 5 - Decrement Loop Counter + BNE ARDISL ; 2 7 - and Loop if >= 0 + STY PF0 ; 3 10 - Clear Playfield + STY PF1 ; 3 13 - + STY PF2 ; 3 16 - + RTS + diff --git a/vcs/include/arena.h02 b/vcs/include/arena.h02 new file mode 100644 index 0000000..02e80db --- /dev/null +++ b/vcs/include/arena.h02 @@ -0,0 +1,10 @@ +/* Two Line Kernal Arena Kernal for Atari 2600 * + * Requires the following equates be set: * + * ARNLNS - Number of Scanlines to Display * + * P0HGHT - Height of Player 0 in Kernel Lines * + * P1HGHT - Height of Player 1 in Kernel Lines */ + +void p0prep(); //Prepare Player 0 for Display +void p1prep(); //Prepare Player 1 for Display + +void ardisp(); //Display Arena diff --git a/vcs/include/banks.a02 b/vcs/include/banks.a02 new file mode 100644 index 0000000..49fe97e --- /dev/null +++ b/vcs/include/banks.a02 @@ -0,0 +1,11 @@ +;Bank Switching Registers +BANK0 EQU $1FF4 ;Select Bank 0 (32K) +BANK1 EQU $1FF5 ;Select Bank 1 (32K) +BANK2 EQU $1FF6 ;Select Bank 2 (32K) Bank 0 (16K) Switch Banks (8K) +BANK3 EQU $1FF7 ;Select Bank 3 (32K) Bank 1 (16K) Switch Banks (8K) +BANK4 EQU $1FF8 ;Select Bank 4 (32K) Bank 2 (16K) +BANK5 EQU $1FF9 ;Select Bank 5 (32K) Bank 3 (16K) +BANK6 EQU $1FFA ;Select Bank 6 (32K) +BANK7 EQU $1FFB ;Select Bank 7 (32K) + + diff --git a/vcs/include/basinit.a02 b/vcs/include/basinit.a02 new file mode 100644 index 0000000..26bec92 --- /dev/null +++ b/vcs/include/basinit.a02 @@ -0,0 +1,22 @@ +;Atari 2600 Initialization Code - C02 Assembly Language File +;Based on Batari Basic Initialization Code + +START: SEI ;Disable Interrupts + CLD ;Disable Decimal Modes + LDY #0 ;Set Y-Index to $00 + LDA $D0 ;If Location $D0 + CMP #$2C ; Does Not Contain $2C + BNE IS2600 ;And + LDA $D1 ; Location $D1 + CMP #$A9 ; Does Not Contain $D1 + BNE IS2600 ;Then + DEY ; Set Y-Index to $FF +IS2600: LDX #0 ; + TXA ; +CLRMEM: INX ;Clear TIA Registers and RAM + TXS ; by Cycling Through All Stack Locations + PHA ; and Pushing 0 + BNE CLRMEM ; which leaves Stack Pointer at $FF + TYA ;Copy 2600 Flag to Accumulator + JMP MAIN + diff --git a/vcs/include/colors.a02 b/vcs/include/colors.a02 new file mode 100644 index 0000000..3df15ec --- /dev/null +++ b/vcs/include/colors.a02 @@ -0,0 +1,45 @@ +;colors.a02 - Atari 2600 Color/BW Assembly Language Routines + +;getclr(mask, clr, bw) - Get Color Based on Color B&W Switch Position +;Args: A - Mask for Color Cycling (0=None) +; Y - Color/Luminance to use in Color Mode +; X - Color/Luminance to use in B&W Mode +;Returns: Color to Use +GETCLR: STA TEMP2 ;Save Color Cycling Mask + LDA SWCHB ;Read Console Switches + AND #%00001000 ;Test TV Type Switch + BNE GETCLC ;If Off + TXA ; Load B&W Mode Color/Luminance + EOR TEMP2 ; Apply Mask + AND #$0F ; and Strip High Nybble + RTS ;Else +GETCLC: TYA ; Load Color Mode Color/Luminance + EOR TEMP2 ; and Apply Apply Mask + RTS ;Return Selected Color + +;setclr(mask, &clrtbl) - Set Object Colors +;Args: X,Y = Pointer to 8-Byte Color Table Color Table +; Player0, Player1, Playfield, Background (Color) +; Player0, Player1, Playfield, Background (B&W) +;Sets: TEMP0,TEMP1 = Pointer to Color Table +;Affects: A,X,Y,N,Z +SETCLR: STY TEMP1 ;Save Pointer to Color Table + STX TEMP0 + STA TEMP2 ;Save Color Cycling Mask + LDX #3 ;Setting 4 colors (0-3) + LDY #3 ;Refault to the color entries in the table (0-3) + LDA SWCHB ;Read Console Switches + AND #%00001000 ;Test TV Type Switch + BNE SETCLL ;If On + LDA #$0F ; Use Color Entries + AND TEMP2 ;Else + STA TEMP2 ; Strip High Nybble from Mask + LDY #7 ; and Use B&W Entries +SETCLL: LDA (TEMP0),Y ;Get Color/B&W Value + EOR TEMP2 ;Apply Color Cycling Mask + STA COLUP0,x ;and Set Object Color + DEY ;Decrement Table Pointer + DEX ;Decrement Register Pointer + BPL SETCLL ;If >0, Loop + RTS ;Return + diff --git a/vcs/include/colors.h02 b/vcs/include/colors.h02 new file mode 100644 index 0000000..cad571a --- /dev/null +++ b/vcs/include/colors.h02 @@ -0,0 +1,5 @@ +/* Atari 2600 Library Functions for C02 */ + +void getclr(); //Select Color based on Color/B&W Switch +void setclr(); //Set Colors from Color Table + diff --git a/vcs/include/colors.txt b/vcs/include/colors.txt new file mode 100644 index 0000000..252f220 --- /dev/null +++ b/vcs/include/colors.txt @@ -0,0 +1,20 @@ +vcslib - Atari 2600 Library Functions for C02 + +This library contains commonly used functions for the Atari VCS. + + setclr(&tbl); Sets all four system colors from array tbl, + based on the position of the Color/B&W + awitch. + + The array consists of 8 bytes of TIA + Color/Luminance values, as follows: + Player 0 (Color Mode) + Player 1 (Color Mode) + Playfield (Color Mode) + Background (Color Mode) + Player 0 (B&W Mode) + Player 1 (B&W Mode) + Playfield (B&W Mode) + Background (B&W Mode) + + diff --git a/vcs/include/digits.a02 b/vcs/include/digits.a02 new file mode 100644 index 0000000..ffff425 --- /dev/null +++ b/vcs/include/digits.a02 @@ -0,0 +1,101 @@ +;=============================================================================== +; Digit Graphics +;=============================================================================== + align 256 +DGTGFX: .byte %01110111 + .byte %01010101 + .byte %01010101 + .byte %01010101 + .byte %01110111 + + .byte %00010001 + .byte %00010001 + .byte %00010001 + .byte %00010001 + .byte %00010001 + + .byte %01110111 + .byte %00010001 + .byte %01110111 + .byte %01000100 + .byte %01110111 + + .byte %01110111 + .byte %00010001 + .byte %00110011 + .byte %00010001 + .byte %01110111 + + .byte %01010101 + .byte %01010101 + .byte %01110111 + .byte %00010001 + .byte %00010001 + + .byte %01110111 + .byte %01000100 + .byte %01110111 + .byte %00010001 + .byte %01110111 + + .byte %01110111 + .byte %01000100 + .byte %01110111 + .byte %01010101 + .byte %01110111 + + .byte %01110111 + .byte %00010001 + .byte %00010001 + .byte %00010001 + .byte %00010001 + + .byte %01110111 + .byte %01010101 + .byte %01110111 + .byte %01010101 + .byte %01110111 + + .byte %01110111 + .byte %01010101 + .byte %01110111 + .byte %00010001 + .byte %01110111 + + .byte %00100010 + .byte %01010101 + .byte %01110111 + .byte %01010101 + .byte %01010101 + + .byte %01100110 + .byte %01010101 + .byte %01100110 + .byte %01010101 + .byte %01100110 + + .byte %00110011 + .byte %01000100 + .byte %01000100 + .byte %01000100 + .byte %00110011 + + .byte %01100110 + .byte %01010101 + .byte %01010101 + .byte %01010101 + .byte %01100110 + + .byte %01110111 + .byte %01000100 + .byte %01100110 + .byte %01000100 + .byte %01110111 + + .byte %01110111 + .byte %01000100 + .byte %01100110 + .byte %01000100 + .byte %01000100 + + diff --git a/vcs/include/digits.h02 b/vcs/include/digits.h02 new file mode 100644 index 0000000..e69de29 diff --git a/vcs/include/k2line.a02 b/vcs/include/k2line.a02 index 6a47b1f..e310434 100644 --- a/vcs/include/k2line.a02 +++ b/vcs/include/k2line.a02 @@ -1,6 +1,12 @@ ;k2line.a02 - Two Line Kernal Assembly Language File for C02 ;Requires ConSTAnts KNLLNS, P0HGHT and P1HGHT +;Set Kernel Top Line +;;TODO - Adjust for Extra WSYNC in DSPLNS +;; Need to Execute a second WSYNC if KNLLNS is Even + +KNLTOP EQU KNLLNS/2-1 ;Kernel Lines / 2 Scanlines - 1 (Zero Based) + P0DRAW EQU $D0 ;Player 0 Draw Counter P1DRAW EQU $D1 ;Player 1 Draw Counter P0PTRL EQU $D2 ;Player 0 Graphics Pointer @@ -19,7 +25,7 @@ P0PREP: LSR ;Divide by 2 for Two-line Position ROL ;Rotate Carry into Bit 1 EOR #1 ;Reverse It STA VDELP0 ;and Store in Vertical Delay Register - LDA #KNLLNS-1 ;Draw = Top Line + Height - Y Position + LDA #KNLTOP ;Draw = Top Line + Height - Y Position CLC ADC #P0HGHT SEC @@ -54,7 +60,7 @@ P1PREP: CLC ;Add 1 to Y-Position ROL ;Rotate Carry into Bit 1 EOR #1 ;Reverse It STA VDELP1 ;and Store in Vertical Delay Register - LDA #KNLLNS-1 ;Draw = Top Line + Height - Y Position + 1 + LDA #KNLTOP ;Draw = Top Line + Height - Y Position + 1 CLC ADC #P1HGHT+1 SEC @@ -80,7 +86,7 @@ P1PREP: CLC ;Add 1 to Y-Position ;Args: None ;Uses: KNLLNS, P0HGHT, P1HGHT, P0PTRL, P1PTRL ;Affects: A,X,Y,C,N,Z -DSPLNS: LDY #KNLLNS ; - Number of Kernal Lines (Scanlines / 2) +DSPLNS: LDY #KNLTOP+1 ; - Number of Kernal Lines (Scanlines / 2) LDA #1 ; - Reflect Playfield STA CTRLPF ; - Set Playfield Control Register LDA #P1HGHT-1 ; - Preset GRP1 if Player 1 on Top Line @@ -89,8 +95,6 @@ DSPLNS: LDY #KNLLNS ; - Number of Kernal Lines (Scanlines / 2) LDA #0 ; BYTE $2C ; DSPLN0: LDA (P1PTRL),Y ; - STA WSYNC ; - Beginning of Line - STA HMOVE ; 3 3 - Position Objects STA GRP1 ; 3 6 DEY ; 2 8 AND ($FF),Y ; 5 13 - Waste 5 Cycles to Match Line 2 Loop diff --git a/vcs/include/k2line0.a02 b/vcs/include/k2line0.a02 new file mode 100644 index 0000000..b17e29f --- /dev/null +++ b/vcs/include/k2line0.a02 @@ -0,0 +1,112 @@ +;k2line.a02 - Two Line Kernal Assembly Language File for C02 +;Requires Constants PLYR0H and PLYR1H, +;Variables PLYR0D and PLYR1D, and Pointers PLYR0P and PLYR1P + +PLYR0H EQU $D0 ;Player 0 Height +PLYR1H EQU $D1 ;Player 1 Height +PLYR0D EQU $D2 ;Player 0 Draw Counter +PLYR1D EQU $D3 ;Player 1 Draw Pointer +PLYR0P EQU $D4 ;Player 0 Graphics Pointer +PLYR1P EQU $D6 ;Player 1 Graphics Pointer +PLYR0T EQU $D8 ;Player 0 Pointer Offset +PLYR1T EQU $DA ;Player 1 Pointer Offset +SCNLNS EQU $DF ;Number of Scanlines + +;setpl0() - Set Player 0 Data +;Args: A = Player 0 Height +; Y,X = Pointer to Player 0 Graphics Data +SETPL0: STA PLYR0H ;Save Player 0 Height + DEC PLYR0H ;and Decrement + STX PLYR0P ;Save Player 0 Pointer + STY PLYR0P+1 + RTS + +;setpl1() - Set Player 1 Data +;Args: A = Player 1 Height +; Y,X = Pointer to Player 1 Graphics Data +SETPL1: STA PLYR1H ;Save Player 1 Height + DEC PLYR1H ;and Decrement + STX PLYR1P ;Save Player 1 Pointer + STY PLYR1P+1 + RTS + +;prppl0() - Prep Player Variables +;Args: A = Player 0 Y-Position +PRPPL0: STA TEMP0 + LDA SCNLNS ;PLYR0D = SCNLNS + PLYR0H - PLYR0Y + CLC + ADC PLYR0H +; ADC #1 + SEC + SBC TEMP0 + STA PLYR0D + LDA PLYR0P ;PLYR0T = PLYR0P + PLYR0H - PLYR0Y - 1 + CLC + ADC PLYR0H + SEC + SBC TEMP0 + STA PLYR0T + LDA PLYR0P+1 + SBC #0 + STA PLYR0T+1 + RTS + +;prppl1() - Prep Player 1 Variables +;Args: A = Player 1 Y Position +PRPPL1: STA TEMP1 + LDA SCNLNS ;PLYR1D = SCNLNS + PLYR1H - PLYR1Y + CLC + ADC PLYR1H +; ADC #1 + SEC + SBC TEMP1 + STA PLYR1D + LDA PLYR1P ;PLYR1T = PLYR1P + PLYR1H - PLYR1Y - 1 + CLC + ADC PLYR1H + SEC + SBC TEMP1 + STA PLYR1T + LDA PLYR1P+1 + SBC #0 + STA PLYR1T+1 + RTS + +;prpdsp() - Prep Display +PRPDSP: LDA #0 + STA WSYNC ;Wait for Horizontal Sync + STA HMOVE ;Move Objects + STA VDELP0 ;Clear Player 0 Vertical Delay + RTS + +;dsplns() - Display Two Line Kernal +DSPLNS: LDY SCNLNS ; (13) Set Number of Lines to Draw + DEY +DSPLNL: LDA PLYR0H ;2 21 - Height of Player 0 (Zero Based) + DCP PLYR0D ;5 26 - Decrement PLYR0D and compare with height + BCS DSPLN0 ;2 28 - (3 23) If Player 0 not on Current Scanline + LDA #0 ;2 30 - Load Blank Line + BYTE $2C ;4 34 - Else (BIT trick) +DSPLN0: LDA (PLYR0T),Y ;5 49 - Load Player 0 Graphics Line + STA WSYNC ;3 52 - End of Line 2 + STA GRP0 ;3 3 - Set Player 0 Graphics Data + LDX #%11111111 ;2 5 - Load Playfield Pattern + STX PF0 ;3 8 - and Store + STX PF1 ;3 11 + STX PF2 ;3 14 + LDA PLYR1H ;2 16 - Height of Player 1 + DCP PLYR1D ;5 21 - Decrement PLYR1D and compare with height + BCS DSPLN1 ;2 23 - (3 18) If Player 0 not on Current Scanline + LDA #0 ;2 25 - Load Blank Line + BYTE $2C ;4 29 - - Else (BIT trick) +DSPLN1 LDA (PLYR1T),Y ;5 34 - Load Player 1 Graphics Line + STA WSYNC ;3 37 - End of Line 1 + STA GRP1 ;3 3 - Set Player 0 Graphics Data + LDX #0 ;2 5 - Load Playfield Pattern + STX PF0 ;3 8 - and Store + STX PF1 ;3 11 + STX PF2 ;3 14 + DEY ;2 16 - decrease the 2LK loop counter + BPL DSPLNL ;2 18 - (3 21) Branch if more lines to draw + RTS + diff --git a/vcs/include/k2line1.a02 b/vcs/include/k2line1.a02 new file mode 100644 index 0000000..17386d8 --- /dev/null +++ b/vcs/include/k2line1.a02 @@ -0,0 +1,131 @@ +;k2line.a02 - Two Line Kernal Assembly Language File for C02 +;Requires Constants PLYR0H and PLYR1H, +;Variables PLYR0D and PLYR1D, and Pointers PLYR0P and PLYR1P + +PLYR0H EQU $D0 ;Player 0 Height +PLYR1H EQU $D1 ;Player 1 Height +PLYR0D EQU $D2 ;Player 0 Draw Counter +PLYR1D EQU $D3 ;Player 1 Draw Pointer +PLYR0P EQU $D4 ;Player 0 Graphics Pointer +PLYR1P EQU $D6 ;Player 1 Graphics Pointer +PLYR0T EQU $D8 ;Player 0 Pointer Offset +PLYR1T EQU $DA ;Player 1 Pointer Offset +SCNLNS EQU $DF ;Number of Scanlines + +;setpl0() - Set Player 0 Data +;Args: A = Player 0 Height +; Y,X = Pointer to Player 0 Graphics Data +SETPL0: STA PLYR0H ;Save Player 0 Height + DEC PLYR0H ;and Decrement + STX PLYR0P ;Save Player 0 Pointer + STY PLYR0P+1 + RTS + +;setpl1() - Set Player 1 Data +;Args: A = Player 1 Height +; Y,X = Pointer to Player 1 Graphics Data +SETPL1: STA PLYR1H ;Save Player 1 Height + DEC PLYR1H ;and Decrement + STX PLYR1P ;Save Player 1 Pointer + STY PLYR1P+1 + RTS + +;prppl0() - Prep Player Variables +;Args: A = Player 0 Y-Position +PRPPL0: LDX #1 ;Divide Y-Position by 2 + SEC + SBC #1 + LSR ;and Set Vertical Delay if No Remainder + STA TEMP0 + BCS PRPPN0 + STX VDELP0 +PRPPN0: LDA SCNLNS ;PLYR0D = SCNLNS + PLYR0H - PLYR0Y + CLC + ADC PLYR0H + SEC + SBC TEMP0 + STA PLYR0D + LDA PLYR0P ;PLYR0T = PLYR0P + PLYR0H - PLYR0Y - 1 + CLC + ADC PLYR0H + SEC + SBC TEMP0 + STA PLYR0T + LDA PLYR0P+1 + SBC #0 + STA PLYR0T+1 + RTS + +;prppl1() - Prep Player 1 Variables +;Args: A = Player 1 Y Position +PRPPL1: LDX #1 + CLC ;Increment Y-Position + ADC #1 ; to compensate for priming of GRP1 + LSR ;Divide by 2 + STA TEMP1 ; and set Vertical Delay if No Remainder + BCS PRPPN1 + STX VDELP1 +PRPPN1: LDA SCNLNS ;PLYR1D = SCNLNS + PLYR1H - PLYR1Y + CLC + ADC #1 + ADC PLYR1H + SEC + SBC TEMP1 + STA PLYR1D + LDA PLYR1P ;PLYR1T = PLYR1P + PLYR1H - PLYR1Y - 1 + CLC + ADC PLYR1H + SEC + SBC TEMP1 + STA PLYR1T + LDA PLYR1P+1 + SBC # + STA PLYR1T+1 + RTS + +;prpdsp() - Prep Display +PRPDSP: LDA #0 + STA WSYNC ;Wait for Horizontal Sync + STA HMOVE ;Move Objects + STA VDELP0 ;Clear Player 0 Vertical Delay + STA VDELP1 ;Clear Player 0 Vertical Delay + RTS + +;dsplns() - Display Two Line Kernal +DSPLNS: LDY SCNLNS ; (13) Set Number of Lines to Draw + LDA PLYR1H ; 2 9 - Get Player 1 Height + DCP PLYR1D ; 5 14 - Decrement counter and compare with height + BCS DSPLNP ; 2 16 - (3 18) If not on current scanline + LDA #0 ; 2 18 - Load Blank Line + BYTE $2C ; 4 22 - Else (BIT trick) +DSPLNP: LDA (PLYR1T),Y ; 5 22 - Load Player 0 Graphics Line + STA GRP1 ; 3 25 - Set Player 0 Graphics Data + DEY +DSPLNL: LDA PLYR0H ;2 21 - Height of Player 0 (Zero Based) + DCP PLYR0D ;5 26 - Decrement counter and compare with height + BCS DSPLN0 ;2 28 - (3 23) If Player 0 not on Current Scanline + LDA #0 ;2 30 - Load Blank Line + BYTE $2C ;4 34 - Else (BIT trick) +DSPLN0: LDA (PLYR0T),Y ;5 49 - Load Player 0 Graphics Line + STA WSYNC ;3 52 - End of Line 2 + STA GRP0 ;3 3 - Set Player 0 Graphics Data + LDX #%11111111 ;2 5 - Load Playfield Pattern + STX PF0 ;3 8 - and Store + STX PF1 ;3 11 + STX PF2 ;3 14 + LDA PLYR1H ;2 16 - Get Player 1 Height + DCP PLYR1D ;5 21 - Decrement counter and compare with height + BCS DSPLN1 ;2 23 - (3 18) If not on current scanline + LDA #0 ;2 25 - Load Blank Line + BYTE $2C ;4 29 - - Else (BIT trick) +DSPLN1 LDA (PLYR1T),Y ;5 34 - Load Player 1 Graphics Line + STA WSYNC ;3 37 - End of Line 1 + STA GRP1 ;3 3 - Set Player 0 Graphics Data + LDX #0 ;2 5 - Load Playfield Pattern + STX PF0 ;3 8 - and Store + STX PF1 ;3 11 + STX PF2 ;3 14 + DEY ;2 16 - decrease the 2LK loop counter + BPL DSPLNL ;2 18 - (3 21) Branch if more lines to draw + RTS + diff --git a/vcs/include/kernel.asm b/vcs/include/kernel.asm new file mode 100644 index 0000000..ab1f324 --- /dev/null +++ b/vcs/include/kernel.asm @@ -0,0 +1,106 @@ + processor 6502 + include "vcs.h" + include "macro.h" + SEG + ORG $F000 +Reset +StartOfFrame + ; Start of vertical blank processing + lda #0 + sta VBLANK + lda #2 + sta VSYNC + + ; 3 scanlines of VSYNCH signal... + sta WSYNC + sta WSYNC + sta WSYNC + lda #0 + sta VSYNC + ; 37 scanlines of vertical blank... + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + + ; 192 scanlines of picture... + + ldx #0 + REPEAT 192; scanlines + inx + stx COLUBK + sta WSYNC + REPEND + + lda #%01000010 + sta VBLANK ; end of screen - enter blanking + ; 30 scanlines of overscan... + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + jmp StartOfFrame + ORG $FFFA + .word Reset ; NMI + .word Reset ; RESET + .word Reset ; IRQ + END diff --git a/vcs/include/notes.txt b/vcs/include/notes.txt new file mode 100644 index 0000000..e2f79f7 --- /dev/null +++ b/vcs/include/notes.txt @@ -0,0 +1,5 @@ +Timer Setting + 76/64 = 38/32 = 19/16 + X*19 = X*16 + X*2 + X*1 + + diff --git a/vcs/include/scharge.a02 b/vcs/include/scharge.a02 new file mode 100644 index 0000000..348a44d --- /dev/null +++ b/vcs/include/scharge.a02 @@ -0,0 +1,6 @@ +;Atari VCS Supercharger Assembly Language Routines + +SCCTL EQU $FFF8 ;Supercharger Control Register +SCAUD EQU $FFF9 ;Supercharger Audio Data + + diff --git a/vcs/include/score2.a02 b/vcs/include/score2.a02 index b209931..a5483ca 100644 --- a/vcs/include/score2.a02 +++ b/vcs/include/score2.a02 @@ -1,19 +1,18 @@ ;Atari 2600 Two Player Score Kernel ;Score Routine Variables -SCORE0 EQU $E8 ;Player One Score -SCORE1 EQU $E9 ;Player Two Score -SC0ONE EQU $EA ;One Score Ones Digit Offset -SC1ONE EQU $EB ;Player Ten Score Ones Digit Offset -SC0TEN EQU $EC ;Player One Score Ones Digit Offset -SC1TEN EQU $ED ;Player Ten Score Ones Digit Offset -SC0GFX EQU $EE ;Player One Score Graphics Data -SC1GFX EQU $EF ;Player Two Score Graphics Data - +SCORE0 EQU $E8 ;Player One Score +SCORE1 EQU $E9 ;Player Two Score +SC0ONE EQU $EA ;One Score Ones Digit Offset +SC1ONE EQU $EB ;Player Ten Score Ones Digit Offset +SC0TEN EQU $EC ;Player One Score Ones Digit Offset +SC1TEN EQU $ED ;Player Ten Score Ones Digit Offset +SC0GFX EQU $EE ;Player One Score Graphics Data +SC1GFX EQU $EF ;Player Two Score Graphics Data ;Prep Scores For Diplay -SCRPRP: LDX #1 ;Offset into SCORE0/SCORE1 -SCRPRL: LDA SCORE0,X ;Get SCORE1 (First Pass) or SCORE0 (Second Pass) +SCPREP: LDX #1 ;Offset into SCORE0/SCORE1 +SCPREL: LDA SCORE0,X ;Get SCORE1 (First Pass) or SCORE0 (Second Pass) AND #$0F ;Remove Tens Digit STA TEMP0 ;And Save It ASL ;Multiply By 4 @@ -30,14 +29,14 @@ SCRPRL: LDA SCORE0,X ;Get SCORE1 (First Pass) or SCORE0 (Second Pass) ADC TEMP0 ;Add Saved Value, Resulting in Digit / 16 * 5 STA SC0TEN,X ;Store in SC0TEN (First Pass) or SC1TEN (Second Pass) DEX ;Point to SCORE 1 - BPL SCRPRL ;AND Loop if >0 + BPL SCPREL ;AND Loop if >0 RTS ;Return -;Display Score Kernel - Uses 12 Lines Total -SCRDSP: LDA #2 ; - Use Player Colors +;scdisp() - Score Display Kernel - Uses 12 Scanlines Total +SCDISP: LDA #2 ; - Use Player Colors STA CTRLPF ; - Set Playfield Control Register LDX #5 ; 43 - cycle after looping -SCRDSL: LDY SC0TEN ; 3 46 - get the tens digit offset for the Score +SCDISL: LDY SC0TEN ; 3 46 - get the tens digit offset for the Score LDA DGTGFX,Y ; 5 51 - use it to load the digit graphics AND #$F0 ; 2 53 - remove the graphics for the ones digit STA SC0GFX ; 3 56 - AND save it @@ -57,7 +56,7 @@ SCRDSL: LDY SC0TEN ; 3 46 - get the tens digit offset for the Score AND #$0F ; 2 26 - remove the graphics for the tens digit ORA SC1GFX ; 3 29 - merge with the tens digit graphics STA SC1GFX ; 3 32 - AND save it - JSR SCRDSR ;12 44 - waste 12 cycles + JSR SCDISX ;12 44 - waste 12 cycles STA PF1 ; 3 47 - @39-54, update playfield for Timer display LDY SC0GFX ; 3 50 - preload for next scanline STA WSYNC ; 3 53 - wait for end of scanline @@ -66,12 +65,12 @@ SCRDSL: LDY SC0TEN ; 3 46 - get the tens digit offset for the Score INC SC1TEN ; 5 13 - advance for the next line of graphic data INC SC0ONE ; 5 18 - advance for the next line of graphic data INC SC1ONE ; 5 23 - advance for the next line of graphic data - JSR SCRDSR ;12 35 - waste 12 cycles + JSR SCDISX ;12 35 - waste 12 cycles DEX ; 2 37 - decrease the loop counter STA PF1 ; 3 40 - @39-54, update playfield for the Timer display - BNE SCRDSL ; 2 42 - (3 43) if dex != 0 then branch to ScoreLoop + BNE SCDISL ; 2 42 - (3 43) if dex != 0 then branch to ScoreLoop STA WSYNC ; 3 45 - wait for end of scanline STX PF1 ; 3 3 - x = 0, so this blanks out playfield STA WSYNC ; 3 6 - wait for end of scanline -SCRDSR: RTS ; 6 12 - Return +SCDISX: RTS ; 6 12 - Return diff --git a/vcs/include/score2.h02 b/vcs/include/score2.h02 index a4424ea..f3c35cc 100644 --- a/vcs/include/score2.h02 +++ b/vcs/include/score2.h02 @@ -1,13 +1,5 @@ /* Atari 2600 Two-Player Score Kernel */ -char score1; //Player One Score -char score2; //Player Two Score - -char sc1one; //Player One Score Ones Digit Offset -char sc1ten; //Player One Score Ones Digit Offset -char sc2one; //Player Ten Score Ones Digit Offset -char sc2ten; //Player Ten Score Ones Digit Offset - -char sc1gfx; //Player One Score Graphics Data -char sc2gfx; //Player Two Score Graphics Data +char score0; //Player One Score +char score1; //Player Two Score diff --git a/vcs/include/startup.a02 b/vcs/include/startup.a02 new file mode 100644 index 0000000..717ecb9 --- /dev/null +++ b/vcs/include/startup.a02 @@ -0,0 +1,204 @@ +;Atari 2600 Initialization Code - C02 Assembly Language File + +PLR0X EQU $80 +PLR1X EQU $81 +MSL0X EQU $82 +MSL1X EQU $83 +BALLX EQU $84 + +OBJTY EQU $85 +PLR0Y EQU $85 +PLR1Y EQU $86 +MSL1HT EQU $87 +MSL1Y EQU $88 +BALLY EQU $89 + +PLR0LO EQU $8A +PLR0HI EQU $8B +PLR1LO EQU $8C +PLR1HI EQU $8D + +PLR0HT EQU $8E +PLR1HT EQU $8F +MSL0HT EQU $90 +MSL0Y EQU $91 +BALLHT EQU $92 + + +SCORE EQU $93 ; $93-$95 +SCOREPOINTERS EQU $96 ; $96-$9B EQU 6 BYTES +TEMP1 EQU $9C ;USED BY KERNEL +TEMP2 EQU $9D ;CAN BE USED IN PROGRAM TOO, BUT +TEMP3 EQU $9E ;ARE OBLITERATED WHEN DRAWSCREEN IS CALLED. +TEMP4 EQU $9F +TEMP5 EQU $A0 +TEMP6 EQU $A1 + +RAND EQU $A2 +SCORECOLOR EQU $A3 + +VAR0 EQU $A4 +VAR1 EQU $A5 +VAR2 EQU $A6 +VAR3 EQU $A7 +VAR4 EQU $A8 +VAR5 EQU $A9 +VAR6 EQU $AA +VAR7 EQU $AB +VAR8 EQU $AC +VAR9 EQU $AD +VAR10 EQU $AE +VAR11 EQU $AF +VAR12 EQU $B0 +VAR13 EQU $B1 +VAR14 EQU $B2 +VAR15 EQU $B3 +VAR16 EQU $B4 +VAR17 EQU $B5 +VAR18 EQU $B6 +VAR19 EQU $B7 +VAR20 EQU $B8 +VAR21 EQU $B9 +VAR22 EQU $BA +VAR23 EQU $BB +VAR24 EQU $BC +VAR25 EQU $BD +VAR26 EQU $BE +VAR27 EQU $BF +VAR28 EQU $C0 +VAR29 EQU $C1 +VAR30 EQU $C2 +VAR31 EQU $C3 +VAR32 EQU $C4 +VAR33 EQU $C5 +VAR34 EQU $C6 +VAR35 EQU $C7 +VAR36 EQU $C8 +VAR37 EQU $C9 +VAR38 EQU $CA +VAR39 EQU $CB +VAR40 EQU $CC +VAR41 EQU $CD +VAR42 EQU $CE +VAR43 EQU $CF +VAR44 EQU $D0 +VAR45 EQU $D1 +VAR46 EQU $D2 +VAR47 EQU $D3 + +TEMP7 EQU $D4 ; THIS IS USED TO AID IN BANKSWITCHING + +PLAYFIELDPOS EQU $D5 + +A EQU $D6 +B EQU $D7 +C EQU $D8 +D EQU $D9 +E EQU $DA +F EQU $DB +G EQU $DC +H EQU $DD +I EQU $DE +J EQU $DF +K EQU $E0 +L EQU $E1 +M EQU $E2 +N EQU $E3 +O EQU $E4 +P EQU $E5 +Q EQU $E6 +R EQU $E7 +S EQU $E8 +T EQU $E9 +U EQU $EA +V EQU $EB +W EQU $EC +X EQU $ED +Y EQU $EE +Z EQU $EF + +; AVAILABLE FOR OTHER USES, OR IF UNUSED, PROVIDE MORE STACK SPACE + +AUX1 EQU $F0 +AUX2 EQU $F1 +AUX3 EQU $F2 +AUX4 EQU $F3 +AUX5 EQU $F4 +AUX6 EQU $F5 + +; PLAYFIELD COLOR/HT POINTERS +PFCOLORTABLE EQU $F0 ; AND $D5 +PFHTTABLE EQU $F0 ; AND $D5 +; THE ABOVE POINTERS ARE THE SAME BECAUSE IF COLOR AND HT ARE BOTH USED TOGETHER, +; THEY MUST USED ABSOLUTE INDEXED AND CANNOT USE POINTERS + +LIFEPOINTER EQU $F2 ; POINTER TO "LIVES" SHAPE +; UPPER 3 BITS OF $F2 CONTAIN THE NUMBER OF LIVES +LIFECOLOR EQU $F4 +LIVES EQU $F3 ; # LIVES >> 5 +STATUSBARLENGTH EQU $F5 ; ONLY USES UPPER 5 BITS; OTHER BITS FREE + +PFSCORE1 EQU $F2 ; OPTIONAL PLAYFIELD BYTES IN SCORE +PFSCORE2 EQU $F3 +PFSCORECOLOR EQU $F4 + +STACK1 EQU $F6 +STACK2 EQU $F7 +STACK3 EQU $F8 +STACK4 EQU $F9 + + +START: SEI ;Disable Interrupts + CLD ;Disable Decimal Modes + LDY #0 ;Set Y-Index to $00 + LDA $D0 ;If Location $D0 + CMP #$2C ; Does Not Contain $2C + BNE IS2600 ;And + LDA $D1 ; Location $D1 + CMP #$A9 ; Does Not Contain $D1 + BNE IS2600 ;Then + DEY ; Set Y-Index to $FF +IS2600: LDX #0 ;Initialize X-Index + TXA ;Initialize Accumulator +CLRMEM: INX ; + TXS ; + PHA + BNE CLRMEM + STY TEMP1 + IFCONST PFROWHT + LDA PFROWHT + 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 diff --git a/vcs/include/sticks.a02 b/vcs/include/sticks.a02 new file mode 100644 index 0000000..69b92c4 --- /dev/null +++ b/vcs/include/sticks.a02 @@ -0,0 +1,27 @@ +;C02 VCS Library - Joystick Assembly Language Subroutines + +;getstk(cntrlr) - Read Joystick +;Args: A = Controller Number, 0=Left, 1=Right +;Sets: TEMP0 = Left Joystick Raw Directional Bits +; TEMP1 = Right Joystick Raw Directional Bits +; X = Controller Number +;Returns: A = Joystick Bits (1 if Pressed) +; 0=Up, 1=Down, 2=Left, 3=Right, 7=Trigger +; N = Set if Trigger Pressed +; Z = Set if No Buttons or Trigger Pressed +GETSTK: TAX ;Save Stick Number in Index + LDA SWCHA ;Read Joystick Register + LSR ;Shift High Nybble into Low Nybble + LSR + LSR + LSR + STA TEMP0 ;Save Left Joystick Raw Bits + LDA SWCHA ;Read Joystick Register + AND #$0F ;Strip High Nybble + STA TEMP1 ;Save Right Joystick Raw Bits + LDA INPT4,X ;Read Joystick Trigger + AND #$80 ;Strip Bits 1-6 + ORA TEMP0,X ;Combine with Directional Bits + EOR #$8F ;Reverse Bits + RTS + diff --git a/vcs/include/sticks.h02 b/vcs/include/sticks.h02 new file mode 100644 index 0000000..c379f08 --- /dev/null +++ b/vcs/include/sticks.h02 @@ -0,0 +1,10 @@ +/* Atari 2600 Joystick Functions for C02 */ + +//Joystick Directions +//#define STKUP = 1 //Joystick Up +//#define STKDN = 2 //Joystick Down +//#define STKLF = 4 //Joystick Left +//#define STKRT = 8 //Joystick Right + +char getstk(); //Read Joystick + diff --git a/vcs/include/sticks.txt b/vcs/include/sticks.txt new file mode 100644 index 0000000..51c6388 --- /dev/null +++ b/vcs/include/sticks.txt @@ -0,0 +1,31 @@ +sticks - Atari 2600 Joystick Functions for C02 + +This library contains a function for reading the joysticks: + + res = getstk(cntrlr); Reads the state of the specified joystick. + + The joystick to be read is specified by + the argument cntrlr: + 0 = Left Joystick + 1 = Right Joystick + + Returns a byte comprised of the bits: + Bit Hex Dec Control + 0 $01 1 Up + 1 $02 2 Down + 2 $03 4 Left + 3 $04 8 Right + 7 $05 128 Trigger + + A 1 in a bit means that the direction + or trigger is pressed, so the function + will return 0 if they joystick is + centered and the trigger is not pressed. + This is the reverse of the raw bits from + the hardware ports. + + Note: The raw bits for the left joystick + are stored in TEMP0, while the raw bits + for the right joystick are stored in TEMP1. + + diff --git a/vcs/include/timerbar.a02 b/vcs/include/timerbar.a02 new file mode 100644 index 0000000..8887419 --- /dev/null +++ b/vcs/include/timerbar.a02 @@ -0,0 +1,71 @@ +;Atari 2600 Timer Bar Kernel + +;Timer Variables +TMRPF0 EQU $F0 ;Timer Playfield Leftmost Byte +TMRPF1 EQU $F1 +TMRPF2 EQU $F2 +TMRPF3 EQU $F3 +TMRPF4 EQU $F4 +TMRPF5 EQU $F5 ;Timer Playfield Rightmost Byte + +;tmprep() - Prepare Timer Bar +TMPREP: LDA #%11111111 + STA TMRPF0 + STA TMRPF1 + STA TMRPF2 + STA TMRPF3 + STA TMRPF4 + STA TMRPF5 + RTS + +;tmtick() - Tick Down Timer Bar +;Returns: A=$FF If Timer has Not Expired +; $00 If Timer has Expired +TMTICK: LDA TMRPF0 ;Check Leftmost Nybble of Timer Bar + AND #$F0 ;If 0 + BEQ TMTICX ; Return FALSE + LSR TMRPF5 ;PF2 right side, reversed bits so shift right + ROL TMRPF4 ;PF1 right side, normal bits so shift left + ROR TMRPF3 ;PF0 right side, reversed bits so shift right + LDA TMRPF3 ;only upper nybble used, so we need to put bit 3 into C + LSR + LSR + LSR + LSR + ROR TMRPF2 ;PF2 left side, reversed bits so shift right + ROL TMRPF1 ;PF1 left side, normal bits so shift left + ROR TMRPF0 ;PF0 left side, reversed bits so shift right + LDA #$FF ;Return TRUE +TMTICX: RTS + +;tmdisp() - Display Timer Bar +;Args: A = Timer Bar Color +TMDISP: STA COLUPF ; - Set Playfield Color + LDX #0 ; - Offset for Writes + STX CTRLPF ; - Set Playfield to Defaults + LDY #1 ; - Use Two Scanlines +TMDISL: STA WSYNC ; - Wait for Beginning of Line + LDA TMRPF0,X ; 4 4 - Copy Data to Playfield Left + STA PF0,X ; 5 9 - Indexed Mode Uses Extra Cycles + LDA TMRPF1,X ; 4 13 + STA PF1,X ; 5 18 + LDA TMRPF2,X ; 4 22 + STA PF2,X ; 5 27 + JSR TMDISX ;12 39 - Wait 12 Cycles + LDA TMRPF3 ; 3 42 - Copy Data To Playfield Right + STA PF0 ; 3 45 + LDA TMRPF4 ; 3 50 + STA PF1 ; 3 53 + LDA TMRPF5 ; 3 56 + STA PF2 ; 3 59 + DEY ; 2 62 + BPL TMDISL ; 2 64 (3 65) + STA WSYNC ; 3 67 + LDA #0 ; 2 2 + STA PF0 ; 3 5 + STA PF1 ; 3 8 + STA PF2 ; 3 11 + STA COLUPF ; 3 14 + STA WSYNC ; 3 20 - Gap between timer and Arena +TMDISX: RTS + diff --git a/vcs/include/timerbar.h02 b/vcs/include/timerbar.h02 new file mode 100644 index 0000000..048119a --- /dev/null +++ b/vcs/include/timerbar.h02 @@ -0,0 +1,3 @@ +/* Atari 2600 Timer Bar Kernel */ + + diff --git a/vcs/include/vcsdefs.h02 b/vcs/include/vcsdefs.h02 new file mode 100644 index 0000000..2d44f85 --- /dev/null +++ b/vcs/include/vcsdefs.h02 @@ -0,0 +1,55 @@ +/* VCS Definitions Header */ + +//Boolean True and False +#define TRUE = $FF +#define FALSE = $0 + +//Set/Clear Various Registers +//ENAM0, ENAM1, ENABL - Enable/Disable Missiles, Ball +//REFP0, REFP01 - Enable/Disable Player Reflection +//RESPMO, RESPM1 - Disable/Enable Missiles +//VDELP0, VDELP1, VDELBL - Delay Players, Ball +#define CLEAR = 0 +#define SET = $0B + +//VBLANK Latches +#define TRGL = $40 //Enable Joystick Trigger Latch +#define DPDL = $80 //Dump Paddle Potentiometers + +//NUSIZ0 and NUSIZ1 Missile Bit Masks +#define MS1CLK = 0 //1 Clock Wide Missile +#define MS2CLK = 1 //2 Clock Wide Missile +#define MS4CLK = 2 //4 Clock Wide Missile +#define MS8CLK = 3 //8 Clock Wide Missile + +//NUSIZ0 and NUSIZ1 Player Bit Masks +#define PL1SNG = 0 //Single Sized Player +#define PL1DBL = 5 //Double Sized Player +#define PL1QUD = 7 //Quadruple Sized Player +#define PL2CLS = 1 //Two Close Copies of Player +#define PL2MED = 2 //Two Medium Copies of Player +#define PL2WID = 4 //Two Wide Copies of Player +#define PL3CLS = 3 //Three Close Copies of Player +#define PL3MED = 6 //Three Medium Copies of Player + +//AUDC0 and AUDC1 Audio Control Registers +#define D02PUR = $04 //Divide by 2, Pure Tone +#define D06PUR = $0C //Divide by 6, Pure Tone +#define D32PUR = $06 //Divide by 31, Pure Tone +#define D93PUR = $0E //Divide by 93, Pure Tone +#define D00PL4 = $01 //No Divide, 4 Bit Polynomial +#define D00PL5 = $09 //No Divide, 5 Bit Polynomial +#define D00PL9 = $08 //No Divide, 9 Bit Polynomial +#define D15PL4 = $02 //Divide by 15 -> 4 Bit Polynomial +#define PL5PL4 = $03 //5 Bit Polynomial -> 4 Bit Polynomial +#define PL5D06 = $0F //5 Bit Polynomial -> Divide by 6 +#define PL4502 = $07 //6 Bit Polynomial -> Divide by 2 + +//SWCHB Console Switch Bit Masks +#define P1DIFF = $80 //Player 1 Difficulty +#define P0DIFF = $40 //Player 0 Difficulty +#define CLRBW = $08 //Color/Black & White +#define SELECT = $02 //Game Select +#define RESET = $01 //Game Reset + + diff --git a/vcs/include/vcsfoot.a02 b/vcs/include/vcsfoot.a02 new file mode 100644 index 0000000..9e544fa --- /dev/null +++ b/vcs/include/vcsfoot.a02 @@ -0,0 +1,9 @@ +;vcsfoot.a02 - C02 Assembly Language Footer File for Atari 2600 +;Created by Curtis F Kaylor - June 18, 2017 + + ORG $FFF4 ;Control and Interrupt Registers + DS 8 ;$FFF4-$FFF9 Bank Switch Registers + DC.W START ;$FFFC Reset Vector + DC.W IRQBRK ;$FFFE Interrupt Vector + + diff --git a/vcs/include/vcsfoot.h02 b/vcs/include/vcsfoot.h02 new file mode 100644 index 0000000..b8cff8b --- /dev/null +++ b/vcs/include/vcsfoot.h02 @@ -0,0 +1,9 @@ +/* vcsfoot.h02 - C02 Footer File for Atari 2600 * + * The last line of the program must be * + * #include * + * The following two labels must be present in the program * + * irqbrk: subroutine to call when a BRK instruction is encountered * + * start: program start on power up */ + +#pragma vartable //Write Variable Table + diff --git a/vcs/include/vcshead.a02 b/vcs/include/vcshead.a02 new file mode 100644 index 0000000..913604e --- /dev/null +++ b/vcs/include/vcshead.a02 @@ -0,0 +1,79 @@ +;vcshead.a02 - C02 Assembly Language Header file for Atari 2600 +;based on VCS.H Version 1.05, 13/November/2003 +;https://github.com/munsie/dasm/blob/master/machines/atari2600/vcs.h + +;TIA Registers - Write +VSYNC EQU $00 ;0000 00x0 Vertical Sync Set-Clear +VBLANK EQU $01 ;xx00 00x0 Vertical Blank Set-Clear +WSYNC EQU $02 ;---- ---- Wait for Horizontal Blank +RSYNC EQU $03 ;---- ---- Reset Horizontal Sync Counter +NUSIZ0 EQU $04 ;00xx 0xxx Number-Size player/missle 0 +NUSIZ1 EQU $05 ;00xx 0xxx Number-Size player/missle 1 +COLUP0 EQU $06 ;xxxx xxx0 Color-Luminance Player 0 +COLUP1 EQU $07 ;xxxx xxx0 Color-Luminance Player 1 +COLUPF EQU $08 ;xxxx xxx0 Color-Luminance Playfield +COLUBK EQU $09 ;xxxx xxx0 Color-Luminance Background +CTRLPF EQU $0A ;00xx 0xxx Control Playfield, Ball, Collisions +REFP0 EQU $0B ;0000 x000 Reflection Player 0 +REFP1 EQU $0C ;0000 x000 Reflection Player 1 +PF0 EQU $0D ;xxxx 0000 Playfield Register Byte 0 +PF1 EQU $0E ;xxxx xxxx Playfield Register Byte 1 +PF2 EQU $0F ;xxxx xxxx Playfield Register Byte 2 +RESP0 EQU $10 ;---- ---- Reset Player 0 +RESP1 EQU $11 ;---- ---- Reset Player 1 +RESM0 EQU $12 ;---- ---- Reset Missle 0 +RESM1 EQU $13 ;---- ---- Reset Missle 1 +RESBL EQU $14 ;---- ---- Reset Ball +AUDC0 EQU $15 ;0000 xxxx Audio Control 0 +AUDC1 EQU $16 ;0000 xxxx Audio Control 1 +AUDF0 EQU $17 ;000x xxxx Audio Frequency 0 +AUDF1 EQU $18 ;000x xxxx Audio Frequency 1 +AUDV0 EQU $19 ;0000 xxxx Audio Volume 0 +AUDV1 EQU $1A ;0000 xxxx Audio Volume 1 +GRP0 EQU $1B ;xxxx xxxx Graphics Register Player 0 +GRP1 EQU $1C ;xxxx xxxx Graphics Register Player 1 +ENAM0 EQU $1D ;0000 00x0 Graphics Enable Missle 0 +ENAM1 EQU $1E ;0000 00x0 Graphics Enable Missle 1 +ENABL EQU $1F ;0000 00x0 Graphics Enable Ball +HMP0 EQU $20 ;xxxx 0000 Horizontal Motion Player 0 +HMP1 EQU $21 ;xxxx 0000 Horizontal Motion Player 1 +HMM0 EQU $22 ;xxxx 0000 Horizontal Motion Missle 0 +HMM1 EQU $23 ;xxxx 0000 Horizontal Motion Missle 1 +HMBL EQU $24 ;xxxx 0000 Horizontal Motion Ball +VDELP0 EQU $25 ;0000 000x Vertical Delay Player 0 +VDELP1 EQU $26 ;0000 000x Vertical Delay Player 1 +VDELBL EQU $27 ;0000 000x Vertical Delay Ball +RESMP0 EQU $28 ;0000 00x0 Reset Missle 0 to Player 0 +RESMP1 EQU $29 ;0000 00x0 Reset Missle 1 to Player 1 +HMOVE EQU $2A ;---- ---- Apply Horizontal Motion +HMCLR EQU $2B ;---- ---- Clear Horizontal Move Registers +CXCLR EQU $2C ;---- ---- Clear Collision Latches + +;TIA Regisers - Read bit 7 bit 6 +CXM0P EQU $00 ;xx00 0000 Read Collision M0-P1 M0-P0 +CXM1P EQU $01 ;xx00 0000 M1-P0 M1-P1 +CXP0FB EQU $02 ;xx00 0000 P0-PF P0-BL +CXP1FB EQU $03 ;xx00 0000 P1-PF P1-BL +CXM0FB EQU $04 ;xx00 0000 M0-PF M0-BL +CXM1FB EQU $05 ;xx00 0000 M1-PF M1-BL +CXBLPF EQU $06 ;x000 0000 BL-PF +CXPPMM EQU $07 ;xx00 0000 P0-P1 M0-M1 +INPT0 EQU $08 ;x000 0000 Read Pot Port 0 +INPT1 EQU $09 ;x000 0000 Read Pot Port 1 +INPT2 EQU $0A ;x000 0000 Read Pot Port 2 +INPT3 EQU $0B ;x000 0000 Read Pot Port 3 +INPT4 EQU $0C ;x000 0000 Read Input (Trigger) 0 +INPT5 EQU $0D ;x000 0000 Read Input (Trigger) 1 + +; RIOT Registers +SWCHA EQU $280 ;Port A data register for joysticks: + ;Bits 4-7 for player 1. Bits 0-3 for player 2. +SWACNT EQU $281 ;Port A data direction register (DDR) +SWCHB EQU $282 ;Port B data (console switches) +SWBCNT EQU $283 ;Port B DDR +INTIM EQU $284 ;Timer output +TIM1T EQU $294 ;set 1 clock interval +TIM8T EQU $295 ;set 8 clock interval +TIM64T EQU $296 ;set 64 clock interval +T1024T EQU $297 ;set 1024 clock interval + diff --git a/vcs/include/vcshead.h02 b/vcs/include/vcshead.h02 new file mode 100644 index 0000000..b542788 --- /dev/null +++ b/vcs/include/vcshead.h02 @@ -0,0 +1,80 @@ +//vcshead.h02 - C02 Header file for Atari 2600 + +//TIA Registers - Write +char VSYNC; //Vertical Sync +char VBLANK; //Vertical Blank +char WSYNC; //Wait for Horizontal Blank +char RSYNC; //Reset Horizontal Sync Counter +char NUSIZ0; //Number-Size Player/Missile 0 +char NUSIZ1; //Number-Size Player/Missile 1 +char COLUP0; //Color-Luminance Player 0 +char COLUP1; //Color-Luminance Player 1 +char COLUPF; //Color-Luminance Playfield +char COLUBK; //Color-Luminance Background +char CTRLPF; //Control Playfield, Ball, Collisions +char REFP0; //Reflection Player 0 +char REFP1; //Reflection Player 1 +char PF0; //Playfield Register Byte 0 +char PF1; //Playfield Register Byte 1 +char PF2; //Playfield Register Byte 2 +char RESP0; //Reset Player 0 +char RESP1; //Reset Player 1 +char RESM0; //Reset Missle 0 +char RESM1; //Reset Missle 1 +char RESBL; //Reset Ball +char AUDC0; //Audio Control 0 +char AUDC1; //Audio Control 1 +char AUDF0; //Audio Frequency 0 +char AUDF1; //Audio Frequency 1 +char AUDV0; //Audio Volume 0 +char AUDV1; //Audio Volume 1 +char GRP0; //Graphics Register Player 0 +char GRP1; //Graphics Register Player 1 +char ENAM0; //0000 00x0 Graphics Enable Missle 0 +char ENAM1; //0000 00x0 Graphics Enable Missle 1 +char ENABL; //0000 00x0 Graphics Enable Ball +char HMP0; //Horizontal Motion Player 0 +char HMP1; //Horizontal Motion Player 1 +char HMM0; //Horizontal Motion Missle 0 +char HMM1; //Horizontal Motion Missle 1 +char HMBL; //Horizontal Motion Ball +char VDELP0; //0000 000x Vertical Delay Player 0 +char VDELP1; //0000 000x Vertical Delay Player 1 +char VDELBL; //0000 000x Vertical Delay Ball +char RESMP0; //0000 00x0 Reset Missle 0 to Player 0 +char RESMP1; //0000 00x0 Reset Missle 1 to Player 1 +char HMOVE; //Apply Horizontal Motion +char HMCLR; //Clear Horizontal Move Registers +char CXCLR; //Clear Collision Latches + +//TIA Registers - Read bit 7 bit 6 +char CXM0P; //Read Collision M0-P1 M0-P0 +char CXM1P; // M1-P0 M1-P1 +char CXP0FB; // P0-PF P0-BL +char CXP1FB; // P1-PF P1-BL +char CXM0FB; // M0-PF M0-BL +char CXM1FB; // M1-PF M1-BL +char CXBLPF; // BL-PF +char CXPPMM; // P0-P1 M0-M1 +char INPT0; //Read Pot Port 0 +char INPT1; //Read Pot Port 1 +char INPT2; //Read Pot Port 2 + +char INPT3; //Read Pot Port 3 +char INPT4; //Read Input (Trigger) 0 +char INPT5; //Read Input (Trigger) 1 + +//RIOT Registers +char SWCHA; //Port A data register for joysticks: + //Bits 4-7 for Player 1. Bits 0-3 for Player 2. +char SWACNT; //Port A data direction register (DDR) +char SWCHB; //Port B data (console switches) +char SWBCNT; //Port B DDR +char INTIM; //Timer output +char TIM1T; //set 1 clock interval +char TIM8T; //set 8 clock interval +char TIM64T; //set 64 clock interval +char T1024T; //set 1024 clock interval + +#pragma zeropage $80 //Zero Page RAM Base Address + diff --git a/vcs/include/vcsinit.a02 b/vcs/include/vcsinit.a02 new file mode 100644 index 0000000..c34db6e --- /dev/null +++ b/vcs/include/vcsinit.a02 @@ -0,0 +1,19 @@ +;Atari 2600 Initialization Code - C02 Assembly Language File +; From CLEAN_START macro by 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 :) + +START: SEI + CLD + LDX #0 + TXA + TAY +STARTC: DEX + TXS + PHA + BNE STARTC + JMP MAIN + diff --git a/vcs/include/vcsinit.h02 b/vcs/include/vcsinit.h02 new file mode 100644 index 0000000..e3aed0c --- /dev/null +++ b/vcs/include/vcsinit.h02 @@ -0,0 +1,7 @@ +/* vcsinit.h02 - Initialize Atari 2600 * + * Usage: * + * #include * + * Contains the start label required by vcsfoot.h02 * + * Program must contain the following label * + * main: program code */ + diff --git a/vcs/include/vcslib.a02 b/vcs/include/vcslib.a02 new file mode 100644 index 0000000..a799e53 --- /dev/null +++ b/vcs/include/vcslib.a02 @@ -0,0 +1,37 @@ +;C02 VCS Library - Assembly Language Subroutines + +;addbcd(addend, &varble) - Add Number to BCD variable +;adcbcd(addend, &varble) - Add Number w/Carry to BCD variable +;Args: A = Number to Add +; X,Y = Pointer to Variable to Add To +;Sets: TEMP0,TEMP1 = Pointer to Color Table +;Affects: A,Y,C,N,Z +;Updates: Variable Pointed to by X,Y +;Returns: A = Result of Addition +ADDBCD: CLC ;Clear Carry - Regular Add +ADCBCD: STX TEMP0 ;Save Pointer to Variable + STY TEMP1 + LDY #0 + SED ;Set Decimal Mode + ADC (TEMP0),Y ;Add Accumulator to Variable + STA (TEMP0),Y ;Store Result in Variable + CLD ;Clear Decimal Mode + RTS ;Return + +;posobj(hrzpos, object) - Position Object +;Args: A = Horizontal Position +; Y = Object (0=Player0, 1=Player1, 2=Missile0, 3=Missle1, 4=Ball) +;Affects: A,C,Z +POSOBJ: SEC + STA WSYNC ;Wait for Beginning of Scanline +POSOBL: SBC #15 ;2 2 - each time thru this loop takes 5 cycles, which is + BCS POSOBL ;2 4 - the same amount of time it takes to draw 15 pixels + EOR #7 ;2 6 - The EOR & ASL statements convert the remainder + ASL ;2 8 - of position/15 to the value needed to fine tune + ASL ;2 10 - the X position + ASL ;2 12 + ASL ;2 14 + STA.WY HMP0,Y ;5 19 - store fine tuning of X + STA RESP0,Y ;4 23 - set coarse X position of object + RTS ;6 29 + diff --git a/vcs/include/vcslib.h02 b/vcs/include/vcslib.h02 new file mode 100644 index 0000000..7a0f33c --- /dev/null +++ b/vcs/include/vcslib.h02 @@ -0,0 +1,6 @@ +/* Atari 2600 Library Functions for C02 */ + +char adcbcd(); //BCD Add w/Carry to Variable +char addbcd(); //BCD Add to Variable +void posobj(); //Position Object + diff --git a/vcs/include/vcslib.txt b/vcs/include/vcslib.txt new file mode 100644 index 0000000..543cfa1 --- /dev/null +++ b/vcs/include/vcslib.txt @@ -0,0 +1,34 @@ +vcslib - Atari 2600 Library Functions for C02 + +This library contains commonly used functions for the Atari VCS. + + res = adcbcd(num, &var); Adds value num plus carry to variable var + using BCD arithmetic. + + Used to update multi-byte BCD numbers, such + as scores with more than two digits. + + Returns the updated contents of var. Can + be called as a void function if the result + is not needed. + + res = addbcd(num, &var); Adds value num to variable var using BCD + arithmetic. + + Used to update BCD numbers, such as two + digit scores. + + Returns the updated contents of var. Can + be called as a void function if the result + is not needed. + + posobj(hrz, obj); Sets horizontal position of object obj to + hrz. + + Argument obj may be any of the following: + 0 = Player 0 + 1 = Player 1 + 2 = Missile 0 + 3 = Missile 1 + 4 = Ball + diff --git a/vcs/include/vcsrtns.a02 b/vcs/include/vcsrtns.a02 new file mode 100644 index 0000000..1184b04 --- /dev/null +++ b/vcs/include/vcsrtns.a02 @@ -0,0 +1,3 @@ +;vcsrtns.a02 - Atari 2600 Common Assembly Language Routines for C02 + + diff --git a/vcs/include/vcsrtns.h02 b/vcs/include/vcsrtns.h02 new file mode 100644 index 0000000..37201a4 --- /dev/null +++ b/vcs/include/vcsrtns.h02 @@ -0,0 +1,8 @@ +/* vcsrtns.h02 - Common Atari 2600 Function for C02 * + * Usage: * + * #include * + * Requires the following zero page variables: * + * TEMP0 * + * */ + + diff --git a/vcs/include/vcsstub.a02 b/vcs/include/vcsstub.a02 new file mode 100644 index 0000000..88581d4 --- /dev/null +++ b/vcs/include/vcsstub.a02 @@ -0,0 +1,71 @@ +;Atart 2600 Program Stub - C02 Assembly Language File + +;Preset Total Number of Kernal Lines +KNLLNS SET 192 ;192 Lines on NTSC Television + +;Variables Used By Other Libraries +TEMP0 EQU $E0 ;Temporary Storage +TEMP1 EQU $E1 +TEMP2 EQU $E2 +TEMP3 EQU $E3 + +;Initialization Code +; From CLEAN_START macro by 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 :) +START: SEI + CLD + LDX #0 + TXA + TAY +STARTC: DEX + TXS + PHA + BNE STARTC + + JSR SETUP ;Execute Setup Code + +MAIN: LDA #2 ;Vertical Sync On Bit Mask + LDX #49 ;41 scanlines * 76 cycles / 64 + STA WSYNC ;Wait for SYNC (halts CPU until end of scanline) + STA VSYNC ;Turn On Vertical Sync + STX TIM64T ;Set timer to go off in 41 scanlines + STA WSYNC ;First Scanline of VSYNC + STA WSYNC ;Second Scanline of VSYNC + LDA #0 ;Vertical Sync Off Bit Mask + STA WSYNC ;Third Scanline of VSYNC + STA VSYNC ;Turn Off Vertical Sync + JSR VRTBLK ;Execute Vertical Blank Code + STA WSYNC ;Wait For Horizontal Sync + STA HMOVE ;Execute Horizontal Moves + JSR CLRHMX ;Clear Horizontal Move Registers +WTVBLK: STA WSYNC ;Wait for End of Vertical Blank + LDA INTIM ;Check Timer + BNE WTVBLK ;Loop If Not Zero + STA VBLANK ;Turn off Vertical Blank + JSR KERNEL ;Execute Kernel Code + STA WSYNC ;Wait for End of Scanline + LDA #2 ;Vertical Blank On Bit Mask + STA VBLANK ;Turn on Vertical Blank + LDA #32 ;27 scanlines * 76 cycles / 64 + STA TIM64T ;Set Timer for 27 scanlines + JSR OVRSCN ;Execute Overscan Code +WTOSCN: STA WSYNC ;Wait for End of Overscan + LDA INTIM ;Check Time + BNE WTOSCN ;Loop If Not Zero + BEQ MAIN ;Loop Back to Vertical Sync + +IRQBRK: RTI ;Catch 6502 Break Instructions + +CLRHMR: NOP ; 2 8 (+6 for calling JSR) + JSR CLRHMX ;12 20 + LDA #0 ; 2 22 - Clear Horizontal Move Registers + LDX #4 ; 2 24 +CLRHML STA HMP0,X ; - Safe to Clear 24 Cycles after HMOVE + DEX + BPL CLRHML +CLRHMX: RTS + diff --git a/vcs/include/vcsstub.h02 b/vcs/include/vcsstub.h02 new file mode 100644 index 0000000..efb9164 --- /dev/null +++ b/vcs/include/vcsstub.h02 @@ -0,0 +1,10 @@ +/* vcsstub.h02 - Atari 2600 Program Stub * + * Usage: * + * #include * + * Contains the start label required by vcsfoot.h02 * + * Program must contain the following functions * + * setup() - Program Startup Code + * vrtblk() - Code to Execute During Vertical Blank * + * kernel() - Kernel Code - Draws Screen * + * ovrscn() - Code to Execute During Overscan */ +