commit bdddd0ab4f10cae74cb1b490c8d610f400187c8f Author: Christian Viñolo Date: Sat Jan 6 14:09:25 2024 +0100 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d36c11 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.bin +*.lst +*.sym \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..848a1ff --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +NAME = pong + +ASM = $(NAME).asm +BIN = $(NAME).bin + +RM = rm -rf +COMPILE = dasm +EMULATE = stella + +all: build + +build: + $(COMPILE) $(ASM) -f3 -v0 -o$(BIN) + +test: build + $(EMULATE) $(BIN) + +clean: + $(RM) $(BIN) + + \ No newline at end of file diff --git a/macro.h b/macro.h new file mode 100644 index 0000000..fe38850 --- /dev/null +++ b/macro.h @@ -0,0 +1,170 @@ +; MACRO.H +; Version 1.09, 05/SEP/2020 + +VERSION_MACRO = 109 + +; +; THIS FILE IS EXPLICITLY SUPPORTED AS A DASM-PREFERRED COMPANION FILE +; The latest version can be found at https://dasm-assembler.github.io/ +; +; 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. +; +; Many thanks to the people who have contributed. If you find an issue with the +; contents, or would like ot add something, please report as an issue at... +; https://github.com/dasm-assembler/dasm/issues + + +; Latest Revisions... +; 1.09 05/SEP/2020 - updated license/links + +; 1.08 13/JUL/2020 - added use of LXA to CLEAN_START +; 1.07 19/JAN/2020 - correction to comment VERTICAL_SYNC +; 1.06 03/SEP/2004 - nice revision of VERTICAL_SYNC (Edwin Blink) +; 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 +; revised version by Edwin Blink -- saves bytes! +; Inserts the code required for a proper 3 scanline vertical sync sequence +; Note: Alters the accumulator + +; OUT: A = 0 + + MAC VERTICAL_SYNC + lda #%1110 ; each '1' bits generate a VSYNC ON line (bits 1..3) +.VSLP1 sta WSYNC ; 1st '0' bit resets Vsync, 2nd '0' bit exit loop + sta VSYNC + lsr + bne .VSLP1 ; branch until VYSNC has been reset + 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 + + IFNCONST NO_ILLEGAL_OPCODES + lxa #0 + ELSE + ldx #0 + txa + ENDIF + 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 + +;------------------------------------------------------- +; BOUNDARY byte# +; Original author: Denis Debro (borrowed from Bob Smith / Thomas) +; +; Push data to a certain position inside a page and keep count of how +; many free bytes the programmer will have. +; +; eg: BOUNDARY 5 ; position at byte #5 in page + +.FREE_BYTES SET 0 + MAC BOUNDARY + REPEAT 256 + IF <. % {1} = 0 + MEXIT + ELSE +.FREE_BYTES SET .FREE_BYTES + 1 + .byte $00 + ENDIF + REPEND + ENDM + + +; EOF diff --git a/pong.asm b/pong.asm new file mode 100644 index 0000000..4782b41 --- /dev/null +++ b/pong.asm @@ -0,0 +1,818 @@ + PROCESSOR 6502 + INCLUDE "vcs.h" + +;; Colors Constants + +BLACK = $00 +WHITE = $0F + +;; ON/OFF Constants + +ON_BIT = %00000010 +OFF_BIT = %0000000 + +;; Hardware Constants + +INITIAL_SWABCNT = 0 +INITIAL_CTRLPF = %00010000 +INITIAL_NUSIZ01 = %00010000 + +;; Input Constants + +J0_UP = %00010000 +J0_DOWN = %00100000 + +J1_UP = %00000001 +J1_DOWN = %00000010 + +;; Movable Object Constants + +PLAYER0_OFFSET = 0 +PLAYER1_OFFSET = 1 +MISSILE0_OFFSET = 2 +MISSILE1_OFFSET = 3 +BALL_OFFSET = 4 + +;; Common Constants + +COMMON_POS_Y = 100 + +;; Paddle Constants + +MIN_PADDLE_POS_Y = 4 +MAX_PADDLE_POS_Y = 180 + +PADDLE1_POS_X = 16 +PADDLE2_POS_X = 144 + +PADDLE_FIRST_HIT_HEIGHT_OFFSET = 4 +PADDLE_FIRST_HIT_DIR_X = 1 +PADDLE_FIRST_HIT_DIR_Y = -2 + +PADDLE_SECOND_HIT_HEIGHT_OFFSET = 9 +PADDLE_SECOND_HIT_DIR_X = 2 +PADDLE_SECOND_HIT_DIR_Y = -2 + +PADDLE_THIRD_HIT_HEIGHT_OFFSET = 14 +PADDLE_THIRD_HIT_DIR_X = 2 +PADDLE_THIRD_HIT_DIR_Y = -1 + +PADDLE_FOURTH_HIT_HEIGHT_OFFSET = 19 +PADDLE_FOURTH_HIT_DIR_X = 2 +PADDLE_FOURTH_HIT_DIR_Y = 0 + +PADDLE_FIFTH_HIT_HEIGHT_OFFSET = 24 +PADDLE_FIFTH_HIT_DIR_X = 2 +PADDLE_FIFTH_HIT_DIR_Y = 1 + +PADDLE_SIXTH_HIT_HEIGHT_OFFSET = 29 +PADDLE_SIXTH_HIT_DIR_X = 2 +PADDLE_SIXTH_HIT_DIR_Y = 2 + +PADDLE_SEVENTH_HIT_DIR_X = 1 +PADDLE_SEVENTH_HIT_DIR_Y = 2 + +;; Ball Constants + +BALL_INITIAL_POS_X = 80 +BALL_INITIAL_BALL_SPEED = 32 +BALL_DIRECTION_COUNT = 3 + +;; Score Constants + +MAX_SCORE = 9 + +SCORE1_POS_X = 50 +SCORE2_POS_X = 100 + +;; Time Constants + +VBLANK_TIME = 57 ; Formula = 48 scanlines * 76 clock cycles / 64 color clocks +OVERSCAN_TIME = 42 ; Formula = 35 scanlines * 76 clock cycles / 64 color clocks + +;; Scanline Constants + +VISIBLE_SCANLINES = 220 +SCORE_SCANLINES = 8 + +PADDLES_HEIGHT_SCANLINE_DIFF = 224 ; Formula = 256 - 32 pixels height +BALL_HEIGHT_SCANLINE_DIFF = 252 ; Formula = 256 - 4 pixels height + +;; Sound Effect Constants + +WALL_COLLISION_FREQUENCY = $17 +WALL_COLLISION_CONTROL = $0C +WALL_COLLISION_VOLUME = $0C +WALL_COLLISION_DURATION = 10 + +BALL_OUT_FREQUENCY = $02 +BALL_OUT_CONTROL = $06 +BALL_OUT_VOLUME = $0C +BALL_OUT_DURATION = 15 + +PADDLE_HIT_FREQUENCY = $1F +PADDLE_HIT_CONTROL = $0C +PADDLE_HIT_VOLUME = $0C +PADDLE_HIT_DURATION = 5 + +;; RAM Constants + +PADDLE1_POS_Y = $0080 +PADDLE2_POS_Y = $0081 + +BALL_POS_X = $0082 +BALL_POS_Y = $0083 +BALL_DIR_X = $0084 +BALL_DIR_Y = $0085 +BALL_SPEED = $0086 + +SPEED_COUNTER = $0087 + +SCORE1 = $0089 +SCORE2 = $008A + +TEMP1 = $008B +TEMP2 = $008C + +FRAME_COUNTER = $008D +SOUND_DURATION = $008E + + ORG $F800 + +Start: + SEI + CLD + LDX #$FF + TXS + LDA #$00 + +ClearRAM: + STA 0,X + DEX + BNE ClearRAM + +InitRAM: + LDA #COMMON_POS_Y + STA PADDLE1_POS_Y + STA PADDLE2_POS_Y + STA BALL_POS_Y + + LDA #BALL_INITIAL_POS_X + STA BALL_POS_X + + LDA #BALL_INITIAL_BALL_SPEED + STA BALL_SPEED + +InitRegisters: + LDA #INITIAL_SWABCNT + STA SWACNT + STA SWBCNT + + LDA #INITIAL_CTRLPF + STA CTRLPF + + LDA #INITIAL_NUSIZ01 + STA NUSIZ0 + STA NUSIZ1 + + LDA #BLACK + STA COLUBK + + LDA #WHITE + STA COLUPF + STA COLUP0 + STA COLUP1 + + STA HMCLR + STA CXCLR + +EnableVSync: + STA WSYNC + LDA #ON_BIT + STA VSYNC + +SkipVSyncScanlines + STA WSYNC + STA WSYNC + STA WSYNC + +InitVBlankTimer: + LDA #VBLANK_TIME + STA TIM64T + +DisableVSync: + LDA #OFF_BIT + STA VSYNC + +UpdateMovableObjectPositions: + LDA #SCORE1_POS_X + LDX #PLAYER0_OFFSET + JSR UpdatePositionX + + LDA #SCORE2_POS_X + LDX #PLAYER1_OFFSET + JSR UpdatePositionX + + LDA #PADDLE1_POS_X + LDX #MISSILE0_OFFSET + JSR UpdatePositionX + + LDA #PADDLE2_POS_X + LDX #MISSILE1_OFFSET + JSR UpdatePositionX + + LDA BALL_POS_X + LDX #BALL_OFFSET + JSR UpdatePositionX + + STA WSYNC + STA HMOVE + +WaitVBlankTimer: + LDA INTIM + BNE WaitVBlankTimer + + STA WSYNC + STA WSYNC + + LDA #OFF_BIT + STA VBLANK + +LoadScores: + LDA SCORE1 + ASL + ASL + ASL + STA TEMP1 + + LDA SCORE2 + ASL + ASL + ASL + STA TEMP2 + + LDY #SCORE_SCANLINES + +DrawScores: + STA WSYNC + + LDX TEMP1 + LDA NUMBERS_BITMAP,X + STA GRP0 + + LDX TEMP2 + LDA NUMBERS_BITMAP,X + STA GRP1 + + INC TEMP1 + INC TEMP2 + + DEY + BNE DrawScores + +StartVisibleScanlines: + LDA PADDLE1_POS_Y + STA TEMP1 + + LDA PADDLE2_POS_Y + STA TEMP2 + + LDX #VISIBLE_SCANLINES + LDY BALL_POS_Y + +DecreaseVisibleScanlines: + STA WSYNC + DEC TEMP1 + DEC TEMP2 + DEY + +DrawPaddle1: + LDA TEMP1 + CMP #PADDLES_HEIGHT_SCANLINE_DIFF + + PHP + PLA + ASL + + STA ENAM0 + +DrawPaddle2: + LDA TEMP2 + CMP #PADDLES_HEIGHT_SCANLINE_DIFF + + PHP + PLA + ASL + + STA ENAM1 + +DrawBall: + CPY #BALL_HEIGHT_SCANLINE_DIFF + + PHP + PLA + ASL + + STA ENABL + +CheckEndVisibleScanlines: + DEX + BNE DecreaseVisibleScanlines + +EnableVBlank: + LDA #ON_BIT + STA VBLANK + +InitOverscanTimer + LDA #OVERSCAN_TIME + STA TIM64T + +CheckJ0Up + LDA SWCHA + AND #J0_UP + BNE CheckJ0Down + + LDA PADDLE1_POS_Y + CMP #MIN_PADDLE_POS_Y + BEQ CheckJ0Down + + DEC PADDLE1_POS_Y + DEC PADDLE1_POS_Y + +CheckJ0Down: + LDA SWCHA + AND #J0_DOWN + BNE CheckJ1Up + + LDA PADDLE1_POS_Y + CMP #MAX_PADDLE_POS_Y + BEQ CheckJ1Up + + INC PADDLE1_POS_Y + INC PADDLE1_POS_Y + +CheckJ1Up: + LDA SWCHA + AND #J1_UP + BNE CheckJ1Down + + LDA PADDLE2_POS_Y + CMP #MIN_PADDLE_POS_Y + BEQ CheckJ1Down + + DEC PADDLE2_POS_Y + DEC PADDLE2_POS_Y + +CheckJ1Down: + LDA SWCHA + AND #J1_DOWN + BNE CheckJ0Button + + LDA PADDLE2_POS_Y + CMP #MAX_PADDLE_POS_Y + BEQ CheckJ0Button + + INC PADDLE2_POS_Y + INC PADDLE2_POS_Y + +CheckJ0Button: + LDA INPT4 + BPL CheckExistingBallDirection + +CheckJ1Button: + LDA INPT5 + BMI MoveBall + +CheckExistingBallDirection: + LDA BALL_DIR_X + BNE MoveBall + +SetBallDirectionX: + LDA FRAME_COUNTER + AND #BALL_DIRECTION_COUNT + + TAX + LDA BALL_DIRECTIONS_TABLE,X + STA BALL_DIR_X + +SetBallDirectionY: + LDA FRAME_COUNTER + LSR + LSR + AND #BALL_DIRECTION_COUNT + + TAX + LDA BALL_DIRECTIONS_TABLE,X + STA BALL_DIR_Y + +MoveBall: + LDA SPEED_COUNTER + CLC + ADC BALL_SPEED + STA SPEED_COUNTER + +CheckBallSpeed: + LDA SPEED_COUNTER + SEC + SBC #$40 + BCS UpdateBallSpeed + + JMP DecreaseSoundCounter + +UpdateBallSpeed: + STA SPEED_COUNTER + +UpdateBallDirectionX: + LDA BALL_POS_X + CLC + ADC BALL_DIR_X + STA TEMP1 + +UpdateBallDirectionY: + LDA BALL_POS_Y + CLC + ADC BALL_DIR_Y + STA TEMP2 + +CheckPaddle1Collision: + LDA TEMP1 + CMP #PADDLE1_POS_X-1 + BCC CheckPaddle2Collision + + CMP #PADDLE1_POS_X+4 + BCS CheckPaddle2Collision + + LDA PADDLE1_POS_Y + SEC + SBC #4 + CMP TEMP2 + BCS CheckPaddle2Collision + + CLC + ADC #35 + CMP TEMP2 + BCC CheckPaddle2Collision + + LDA TEMP2 + SEC + SBC PADDLE1_POS_Y + JSR HitPaddle + + JMP CheckBallSpeed + +CheckPaddle2Collision: + LDA TEMP1 + CMP #PADDLE2_POS_X-1 + BCC CheckWallCollisionX + + CMP #PADDLE2_POS_X+4 + BCS CheckWallCollisionX + + LDA PADDLE2_POS_Y + SBC #4 + CMP TEMP2 + BCS CheckWallCollisionX + + CLC + ADC #35 + CMP TEMP2 + BCC CheckWallCollisionX + LDA TEMP2 + SBC PADDLE2_POS_Y + JSR HitPaddle + LDA #0 + SEC + SBC BALL_DIR_X + STA BALL_DIR_X + JMP CheckBallSpeed + +CheckWallCollisionX: + LDA TEMP2 + CMP #2 + BCC CheckWallCollisionY + + CMP #181 + BCC CheckBallPosition + +CheckWallCollisionY: + LDA #0 + SEC + SBC BALL_DIR_Y + STA BALL_DIR_Y + +PlayWallCollisionSoundEffect: + LDA #WALL_COLLISION_FREQUENCY + STA AUDF0 + LDA #WALL_COLLISION_CONTROL + STA AUDC0 + LDA #WALL_COLLISION_VOLUME + STA AUDV0 + LDA #WALL_COLLISION_DURATION + STA SOUND_DURATION + JMP CheckBallSpeed + +CheckBallPosition: + LDA TEMP1 + CMP #2 + BCC CheckScore2 + + CMP #157 + BCC UpdateBallPositionX + +CheckScore1: + LDA SCORE1 + CMP #MAX_SCORE + BEQ RestartGame + INC SCORE1 + JMP RestartBallPosition + +CheckScore2: + LDA SCORE2 + CMP #MAX_SCORE + BEQ RestartGame + INC SCORE2 + +RestartBallPosition: + LDA #BALL_INITIAL_POS_X + STA TEMP1 + LDA #COMMON_POS_Y + STA TEMP2 + LDA #OFF_BIT + STA BALL_DIR_X + STA BALL_DIR_Y + LDA #BALL_INITIAL_BALL_SPEED + STA BALL_SPEED + +PlayBallOutSoundEffect: + LDA #BALL_OUT_FREQUENCY + STA AUDF0 + LDA #BALL_OUT_CONTROL + STA AUDC0 + LDA #BALL_OUT_VOLUME + STA AUDV0 + LDA #BALL_OUT_DURATION + STA SOUND_DURATION + +UpdateBallPositionX: + LDA TEMP1 + STA BALL_POS_X + +UpdateBallPositionY: + LDA TEMP2 + STA BALL_POS_Y + +DecreaseSoundCounter: + DEC SOUND_DURATION + BNE DisableBall + + LDA #OFF_BIT + STA AUDV0 + +DisableBall: + LDA #OFF_BIT + STA ENABL + +WaitOverscanTimer: + LDA INTIM + BNE WaitOverscanTimer + STA WSYNC + + INC FRAME_COUNTER + JMP EnableVSync + +RestartGame: + JMP Start + +UpdatePositionX: + STA WSYNC + SEC + LDY $80 + +.DivLoop: + SBC #15 + BCS .DivLoop + +.AdjustFinePosition: + TAY + LDA FINE_ADJUST_TABLE-$F1,Y + STA HMP0,X + STA RESP0,X + RTS + +DetectPageCrossing: + IF (>.DivLoop) != (>.AdjustFinePosition) + ECHO "ERROR: PAGE CROSSING" + ERR + ENDIF + + ORG $FEF1 + +HitPaddle: + PHA + +.PlayPaddleHitSoundEffect + LDA #PADDLE_HIT_FREQUENCY + STA AUDF0 + LDA #PADDLE_HIT_CONTROL + STA AUDC0 + LDA #PADDLE_HIT_VOLUME + STA AUDV0 + LDA #PADDLE_HIT_DURATION + STA SOUND_DURATION + +.IncreaseBallBALL_SPEED + INC BALL_SPEED + INC BALL_SPEED + PLA + +.CheckFirstPaddleCollisionRange + CMP #PADDLE_FIRST_HIT_HEIGHT_OFFSET + BPL .CheckSecondPaddleCollisionRange + + LDA #PADDLE_FIRST_HIT_DIR_X + STA BALL_DIR_X + + LDA #PADDLE_FIRST_HIT_DIR_Y + STA BALL_DIR_Y + RTS + +.CheckSecondPaddleCollisionRange: + CMP #PADDLE_SECOND_HIT_HEIGHT_OFFSET + BCS .CheckThirdPaddleCollisionRange + + LDA #PADDLE_SECOND_HIT_DIR_X + STA BALL_DIR_X + + LDA #PADDLE_SECOND_HIT_DIR_Y + STA BALL_DIR_Y + RTS + +.CheckThirdPaddleCollisionRange: + CMP #PADDLE_THIRD_HIT_HEIGHT_OFFSET + BCS .CheckFourthPaddleCollisionRange + + LDA #PADDLE_THIRD_HIT_DIR_X + STA BALL_DIR_X + + LDA #PADDLE_THIRD_HIT_DIR_Y + STA BALL_DIR_Y + RTS + +.CheckFourthPaddleCollisionRange: + CMP #PADDLE_FOURTH_HIT_HEIGHT_OFFSET + BCS .CheckFifthPaddleCollisionRange + + LDA #PADDLE_FOURTH_HIT_DIR_X + STA BALL_DIR_X + + LDA #PADDLE_FOURTH_HIT_DIR_Y + STA BALL_DIR_Y + RTS + +.CheckFifthPaddleCollisionRange: + CMP #PADDLE_FIFTH_HIT_HEIGHT_OFFSET + BCS .CheckSixthPaddleCollisionRange + + LDA #PADDLE_FIFTH_HIT_DIR_X + STA BALL_DIR_X + + LDA #PADDLE_FIFTH_HIT_DIR_Y + STA BALL_DIR_Y + RTS + +.CheckSixthPaddleCollisionRange: + CMP #PADDLE_SIXTH_HIT_HEIGHT_OFFSET + BCS .CheckSeventhCollisionRange + + LDA #PADDLE_SIXTH_HIT_DIR_X + STA BALL_DIR_X + + LDA #PADDLE_SIXTH_HIT_DIR_Y + STA BALL_DIR_Y + RTS + +.CheckSeventhCollisionRange: + LDA #PADDLE_SEVENTH_HIT_DIR_X + STA BALL_DIR_X + + LDA #PADDLE_SEVENTH_HIT_DIR_Y + STA BALL_DIR_Y + RTS + +FINE_ADJUST_TABLE: + .BYTE $70 ; 7 px to left + .BYTE $60 ; 6 px to left + .BYTE $50 ; 5 px to left + .BYTE $40 ; 4 px to left + .BYTE $30 ; 3 px to left + .BYTE $20 ; 2 px to left + .BYTE $10 ; 1 px to left + .BYTE $00 ; No adjustment + .BYTE $F0 ; 1 px to right + .BYTE $E0 ; 2 px to right + .BYTE $D0 ; 3 px to right + .BYTE $C0 ; 4 px to right + .BYTE $B0 ; 5 px to right + .BYTE $A0 ; 6 px to right + .BYTE $90 ; 7 px to right + +BALL_DIRECTIONS_TABLE: + .BYTE $FE ; -2 + .BYTE $FF ; -1 + .BYTE $01 ; 0 + .BYTE $02 ; 1 + +NUMBERS_BITMAP: + .BYTE %11111111 ; 0 + .BYTE %11000011 + .BYTE %11000011 + .BYTE %11000011 + .BYTE %11000011 + .BYTE %11000011 + .BYTE %11111111 + .BYTE %00000000 + + .BYTE %00010000 ; 1 + .BYTE %00010000 + .BYTE %00010000 + .BYTE %00110000 + .BYTE %00110000 + .BYTE %00110000 + .BYTE %00110000 + .BYTE %00000000 + + .BYTE %11111110 ; 2 + .BYTE %00000010 + .BYTE %00000010 + .BYTE %11111110 + .BYTE %11000000 + .BYTE %11000000 + .BYTE %11111110 + .BYTE %00000000 + + .BYTE %11111110 ; 3 + .BYTE %00000010 + .BYTE %00000010 + .BYTE %11111110 + .BYTE %00000110 + .BYTE %00000110 + .BYTE %11111110 + .BYTE %00000000 + + .BYTE %10000010 ; 4 + .BYTE %10000010 + .BYTE %10000010 + .BYTE %11111110 + .BYTE %00000110 + .BYTE %00000110 + .BYTE %00000110 + .BYTE %00000000 + + .BYTE %11111110 ; 5 + .BYTE %10000000 + .BYTE %10000000 + .BYTE %11111110 + .BYTE %00000110 + .BYTE %00000110 + .BYTE %11111110 + .BYTE %00000000 + + .BYTE %11111110 ; 6 + .BYTE %10000000 + .BYTE %10000000 + .BYTE %11111110 + .BYTE %11000110 + .BYTE %11000110 + .BYTE %11111110 + .BYTE %00000000 + + .BYTE %11111110 ; 7 + .BYTE %00000010 + .BYTE %00000010 + .BYTE %00000010 + .BYTE %00000110 + .BYTE %00000110 + .BYTE %00000110 + .BYTE %00000000 + + .BYTE %11111110 ; 8 + .BYTE %10000010 + .BYTE %10000010 + .BYTE %11111110 + .BYTE %11000110 + .BYTE %11000110 + .BYTE %11111110 + .BYTE %00000000 + + .BYTE %11111110 ; 9 + .BYTE %10000010 + .BYTE %10000010 + .BYTE %11111110 + .BYTE %00000110 + .BYTE %00000110 + .BYTE %11111110 + .BYTE %00000000 + + ORG $FFFC + .WORD Start + .WORD Start \ No newline at end of file diff --git a/vcs.h b/vcs.h new file mode 100644 index 0000000..1950c8c --- /dev/null +++ b/vcs.h @@ -0,0 +1,200 @@ +; VCS.H +; Version 1.06, 06/SEP/2020 + +VERSION_VCS = 106 + +; THIS IS *THE* "STANDARD" VCS.H +; THIS FILE IS EXPLICITLY SUPPORTED AS A DASM-PREFERRED COMPANION FILE +; The latest version can be found at https://dasm-assembler.github.io/ +; +; 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 https://dasm-assembler.github.io/ +; +; Many thanks to the people who have contributed. If you find an issue with the +; contents, or would like ot add something, please report as an issue at... +; https://github.com/dasm-assembler/dasm/issues + +; +; Latest Revisions... +; 1.06 05/SEP/2020 Modified header/license and links to new versions +; 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