From 5e5fed618875ada8b4419b6e3e1822c6b07c809f Mon Sep 17 00:00:00 2001 From: Lukas Krickl Date: Sat, 13 Jan 2018 20:04:02 +0100 Subject: [PATCH] Initial commit --- include/macro.h | 176 +++++++++++++++++++++++++++++ include/vcs.h | 200 +++++++++++++++++++++++++++++++++ main.asm | 293 ++++++++++++++++++++++++++++++++++++++++++++++++ makefile | 5 + 4 files changed, 674 insertions(+) create mode 100644 include/macro.h create mode 100644 include/vcs.h create mode 100644 main.asm create mode 100644 makefile diff --git a/include/macro.h b/include/macro.h new file mode 100644 index 0000000..29c34e3 --- /dev/null +++ b/include/macro.h @@ -0,0 +1,176 @@ +; 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 diff --git a/include/vcs.h b/include/vcs.h new file mode 100644 index 0000000..d584a33 --- /dev/null +++ b/include/vcs.h @@ -0,0 +1,200 @@ +; 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 diff --git a/main.asm b/main.asm new file mode 100644 index 0000000..b4444ac --- /dev/null +++ b/main.asm @@ -0,0 +1,293 @@ + + 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 diff --git a/makefile b/makefile new file mode 100644 index 0000000..ed48942 --- /dev/null +++ b/makefile @@ -0,0 +1,5 @@ +all: + dasm main.asm -f3 -v5 -o./bin/game.bin + +clean: + rm ./bin/*.bin -- 2.30.2