--- /dev/null
+; MACRO.H
+; Version 1.06, 3/SEPTEMBER/2004
+
+VERSION_MACRO = 106
+
+;
+; 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.06 03/SEP/2004 - nice revision of VERTICAL_BLANK (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
+
+ 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
+
+;-------------------------------------------------------
+; 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
+
+;-------------------------------------------------------
+; SKIP_SCANLINES #lines
+;
+; Skip a given # of scanlines.
+; Sets the X register to zero.
+
+ MAC SKIP_SCANLINES
+.LINES SET {1}
+ ldx #.LINES
+.vblank sta WSYNC
+ dex
+ bne .vblank
+ ENDM
+
+; EOF
--- /dev/null
+; 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
--- /dev/null
+
+ processor 6502
+ include "include/vcs.h"
+ include "include/macro.h"
+
+PAL = 0
+NTSC = 1
+
+SYSTEM = NTSC ; change this to PAL or NTSC
+
+; ---------- Variables
+ SEG.U vars
+ ORG $80 ; start of RAM
+
+PATTERN ds 1 ; storage location
+FRAMECOUNT ds 1 ; animation counter location
+SPR1X ds 1 ; x pos si delay when drawing
+SPR1Y ds 1 ; y pos is scanline
+SPR2X ds 1
+SPR2Y ds 1
+
+ SEG ; end of uninitialized segment - start of ROM binary
+ ; ---------- Constants
+
+ SEG.U constants
+
+TIMETOCHANGE = 20 ; speed of animation
+SPRITE1H = 16
+
+ SEG
+; ----------
+ ORG $F000
+
+Reset
+
+ ; clear all ram and registers
+ ldx #0
+ lda #0
+Clear
+ sta 0,x
+ inx
+ bne Clear
+
+ ; Init, run once only!
+ lda #0
+ sta PATTERN ; The binary PF 'pattern'
+
+ lda #$45
+ sta COLUPF ; set colour of playfield
+ ldy #0 ; speed counter
+
+ lda #%00000001
+ sta CTRLPF ; reflect playfield
+
+ ; srptie colours
+ lda #$56
+ sta COLUP0
+ lda #$67
+ sta COLUP1
+
+ ; set up srptie pos
+ lda #20
+ sta SPR1X
+ lda #15
+ sta SPR1Y
+
+ lda #30
+ sta SPR2X
+ lda #15
+ sta SPR2Y
+
+ jsr PlayIntroSong
+
+StartOfFrame
+ ; start of new frame
+ ; start vblank processing
+ inc FRAMECOUNT
+ lda #0
+ sta VBLANK
+
+ lda #2
+ sta VSYNC
+
+ sta WSYNC
+ sta WSYNC
+ sta WSYNC ; 3 scanlines of WSYNC
+
+ lda #0
+ sta VSYNC
+
+
+ ; 37 scanlines of VBLANK
+ ldx #0
+VerticalBlank
+ sta WSYNC
+ inx
+ cpx #37
+ bne VerticalBlank
+
+; game logic here
+ lda SWCHA ; input registr
+ asl ; test bit 0, left joy - right input
+ bcs Player1RightNotPressed ; this operation sets the carry for the fromer bit that fell off
+ ; right pressed code
+ ldx SPR1X
+ inx
+ stx SPR1X
+Player1RightNotPressed
+ asl ; test bit 1, left joy - left input
+ bcs Player1LeftNotPressed
+ ; left pressed code
+ ldx SPR1X
+ dex
+ stx SPR1X
+Player1LeftNotPressed
+ asl ; test bit 1, left joy - down input
+ bcs Player1DownNotPressed
+ ; left pressed code
+ ldx SPR1Y
+ inx
+ stx SPR1Y
+Player1DownNotPressed
+ asl ; test bit 2, left joy - up input
+ bcs Player1UpNotPressed
+ ; left pressed code
+ ldx SPR1Y
+ dex
+ stx SPR1Y
+Player1UpNotPressed
+
+
+
+ ; Do 192 scanlines of colour-changing (our picture)
+ ldx 0
+ ; set up PF to display a wall around the game field
+ lda #%11111111
+ sta PF0
+ sta PF1
+ sta PF2
+Picture
+ stx COLUBK ; ranbow effect on background
+
+Top8LinesWall
+ sta WSYNC
+ inx
+ cpx #8 ; line 8?
+ bne Top8LinesWall ; No? Another loop
+
+ ; now we change the lines
+ lda #%00010000 ; PF0 is mirrored <--- direction, low 4 bits ignored
+ sta PF0
+ lda #0
+ sta PF1
+ sta PF2
+
+ ; again, we don't bother writing PF0-PF2 every scanline - they never change!
+ ldy #0 ; load y with 0, we use y to count sprite tables
+MiddleLinesWall
+ ; push y to save for later
+
+ ; sprite stuff
+ cpx SPR1Y
+ bcc SpriteReset
+ cpy #SPRITE1H
+ beq SpriteReset ; if sprites are bigger than 32, we are done!
+ ; SLEEP 20
+
+ lda SPR1X
+ sec ; Set the carry flag so no borrow will be applied during the division.
+.divideby15 ; Waste the necessary amount of time dividing X-pos by 15!
+ sbc #15
+ bcs .divideby15
+
+ sta RESP0
+
+ lda TurtleSprite,y
+ sta GRP0 ; modify sprite 0 shape
+ iny
+
+ jmp SpriteDone
+SpriteReset
+ ; reset sprite registers to 0
+ lda #0
+ sta GRP0
+ sta GRP1
+SpriteDone
+
+ sta WSYNC
+
+ inx
+ cpx #184
+ bne MiddleLinesWall
+
+ ; Finally, our bottom 8 scanlines - the same as the top 8
+ ; AGAIN, we aren't going to bother writing PF0-PF2 mid scanline!
+
+ lda #%11111111
+ sta PF0
+ sta PF1
+ sta PF2
+
+Bottom8LinesWall
+ sta WSYNC
+ inx
+ cpx #192
+ bne Bottom8LinesWall
+
+ ; ---------------
+
+ lda #%01000010
+ sta VBLANK ; end of screen - start blanking
+
+
+
+ ; 30 scanlines of overscan
+ ldx #0
+Overscan
+ sta WSYNC
+ inx
+ cpx #30
+ bne Overscan
+
+ jmp StartOfFrame
+
+; Plays the Intro noise
+PlayIntroSong
+ lda 2
+ ;sta AUDC0
+ ;sta AUDF0
+ ;sta AUDV0
+ rts
+
+; use jsr to jump here
+; number instructions until return is passed in as y
+; destroys y
+DelayLoop
+ dey
+ bne DelayLoop
+ rts
+
+; This is a table that lets us divide by 15 for sprite positioning
+; -> hardcoded table is a lot faster than computing it!
+Divide15
+.POS SET 0
+ REPEAT 160
+ .byte (.POS / 15) + 1
+.POS SET .POS + 1
+ REPEND
+
+; Sprite data
+TurtleSprite
+ .byte %00011000
+ .byte %01100100
+ .byte %11000011
+ .byte %00001111
+ .byte %00011001
+ .byte %00110000
+ .byte %00110110
+ .byte %01111111
+ .byte %01111111
+ .byte %01111111
+ .byte %01110000
+ .byte %00110000
+ .byte %00111000
+ .byte %00011110
+ .byte %00001111
+ .byte %00000011
+
+ .byte %00001100
+ .byte %00010010
+ .byte %11100011
+ .byte %11111001
+ .byte %11001100
+ .byte %10000110
+ .byte %10110110
+ .byte %11111111
+ .byte %11111111
+ .byte %11111111
+ .byte %00000111
+ .byte %00000110
+ .byte %00001110
+ .byte %00111100
+ .byte %11111000
+ .byte %11100000
+
+ ;------------------------------------------------------------------------------
+ ORG $FFFA
+
+InterruptVectors
+ .word Reset ; NMI
+ .word Reset ; RESET
+ .word Reset ; IRQ
+END