Primordial Ooze Posted March 29, 2009 Share Posted March 29, 2009 Could someone please post some sample code on reading the paddle controllers and setting the missiles position based on its readout. Sincerely, 6502Pong Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted March 29, 2009 Share Posted March 29, 2009 (edited) SpiceWare wrote these great macros: MAC READ_PADDLE_1 lda INPT0 ; 3 - always 9 bpl .save ; 2 3 .byte $2c ; 4 0 .save sty Paddle1 ; 0 3 ENDM MAC READ_PADDLE_2 lda INPT1 ; 3 - always 9 bpl .save ; 2 3 .byte $2c ; 4 0 .save sty Paddle2 ; 0 3 ENDM call them in your kernel and use Paddle1 and Paddle2 for the sprite's position. You also have to assign Paddle1 and 2 a location in RAM. EDIT: you also have to charge/discharge the paddle cap. At the beginning of the frame, store $82 to VBLANK. Then just before your kernel, store $00 to VBLANK. After the Kernel, store $82 again Edited March 29, 2009 by Wickeycolumbus Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted March 29, 2009 Share Posted March 29, 2009 SpiceWare wrote these great macros It should be mentioned that the Y register is assumed to hold the scanline counter in those macros (hence, sty Paddle1&2). The "always 9" mentioned is the cycle time taken by each macro...9 cycles regardless of if the branch is taken. Basically...the more times that these macros execute in a display frame, the higher resolution of the value. 1 Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted March 29, 2009 Share Posted March 29, 2009 BTW once you've got the values, they can be used to dictate the horizontal position of a sprite the same way that you'd do it for most anything...commonly by using a divide-by-15 routine to adjust HMxx value and delay loop time for RESxx. Quote Link to comment Share on other sites More sharing options...
Primordial Ooze Posted March 30, 2009 Author Share Posted March 30, 2009 SpiceWare wrote these great macros: MAC READ_PADDLE_1 lda INPT0; 3 - always 9 bpl .save; 2 3 .byte $2c; 4 0 .save sty Paddle1 ; 0 3 ENDM MAC READ_PADDLE_2 lda INPT1; 3 - always 9 bpl .save; 2 3 .byte $2c; 4 0 .save sty Paddle2 ; 0 3 ENDM call them in your kernel and use Paddle1 and Paddle2 for the sprite's position. You also have to assign Paddle1 and 2 a location in RAM. EDIT: you also have to charge/discharge the paddle cap. At the beginning of the frame, store $82 to VBLANK. Then just before your kernel, store $00 to VBLANK. After the Kernel, store $82 again I did what you said with the $82 VBLANK, $00 VBLANK, $82 VBLANK stuff and it still doesn't work. I added the paddle reading code from the Stella Advance Programmers Guide and when i use the -lc Paddles option in Stella, the screen rolls but when i omit the -lc option it just stretches the missiles and ball. Any ideas? Sincerely, 6502Pong 6502Pong.zip Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted March 30, 2009 Share Posted March 30, 2009 (edited) I have a Paddle Demo for the Atari VCS up at my website, it includes the source code. Edited March 30, 2009 by SpiceWare Quote Link to comment Share on other sites More sharing options...
Primordial Ooze Posted March 30, 2009 Author Share Posted March 30, 2009 Ok, that didn't solve my problem as my kernal is very different then yours. processor 6502 ; Then we have to include the "vcs.h" file ; that includes all the "convenience names" ; for all the special atari memory locations... include "vcs.h" include "macro.h" ;************************************************************************** SEG.U vars ; tells dasm that the proceding instructions are variable declarations ORG $80 ; tells dasm to start placing our variables in memory location 0080 missile0x = $80 ; player0's x position missile0y = $81 ; player0's y position visiblemissile0line = $82 ; current visible line for player 0 missile1x = $83 ; player0's x position missile1y = $84 ; player0's y position visiblemissile1line = $85 ; current visible line for player 0 ballx = $86 ; ball's x position bally = $87 ; ball's y position ballvx = $88 ; ball's x velocity ballvy = $89 ; ball's y velocity visibleballline = $8a ; line where ball is drawn leftplayerscore = $8b ; left player's score rightplayerscore = $8c ; right player's score SEG code ; tell DASM where in the memory to place ; all the code that follows...$F000 is the preferred ; spot where it goes to make an atari program ORG $F800 ; we'll call the start of our program "Start". Start sei ; Disable Any Interrupts cld ; Clear BCD math bit. ldx #$FF ; put X to the top... txs ; ...and use it reset the stack pointer ; Clear RAM and all TIA registers lda #0 ; Put Zero into A, X is at $FF Clear sta 0,x ; Now, this doesn't mean what you think... dex ; decrement X (decrease X by one) bne Clear ; if the last command resulted in something ; that's "N"ot "Equal" to Zero, branch back ; to "Clear" ;--------------------- ; One Time Initiations lda #$00 sta COLUBK ; set the background color to black lda #$0F sta COLUPF ; set the playfield color to white sta COLUP0 ; set player 0's color to white sta COLUP1 ; set player 1's color to white lda #%00100001 ; turn on playfield reflections and make the ball 4 ticks wide sta CTRLPF lda #%00010000 sta NUSIZ0 ; set player 0 width to 4 ticks wide sta NUSIZ1 ; set player 1 width to 4 ticks wide ;--------------------- ; Start New Game StartNewGame lda #2 sta missile0x ; player0's initial x position lda #150 sta missile1x ; player1's initial x position lda #95 sta missile0y ; player0's initial y position sta missile1y ; player1's initial y position sta bally ; ball's initial y position lda #75 sta ballx ; ball's initial x position lda #0 sta leftplayerscore ; set the left player's score to 0 sta rightplayerscore ; set the right player's score to 0 GameLoop ;*********************** VERTICAL SYNC HANDLER lda #$82 sta VBLANK ; perform a vertical blank and discharge the caps ; on the paddle controllers lda #2 sta VSYNC ; Sync it up you damn dirty television! ; and that vsync on needs to be held for three scanlines... ; count with me here, sta WSYNC ; one... (our program waited for the first scanline to finish...) sta WSYNC ; two... sta WSYNC ; three... lda #43 ;load 43 (decimal) in the accumulator sta TIM64T ;and store that in the timer lda #0 ; Zero out the VSYNC sta VSYNC ; cause that time is over ;*************************** Paddle Input ; Here we check for left and right paddle ; paddle controller input and check if ; the reset game switch is depressed lda #%00000001 ; a 0 in bit D0 means the reset switch was pressed bit SWCHB ; was the reset switch pressed? bne SkipResetSwitchPressed; if bit D0 isn't equal to 0 then jump to SkipResetSwitchPressed jmp StartNewGame ; if it was then start a new game SkipResetSwitchPressed lda missile0x ; load the millile 0's position into the accumulator ldx #2 ; set the sprite to be positioned as missile 0 jsr PositionSprite ; jump to our Position Sprite Subroutine to position player 0 sta WSYNC ; wait for sync lda ballx ; load the ball's x position into the acumulator ldx #4 ; set the sprite to be positioned to ball jsr PositionSprite ; jump to our Position Sprite Subroutine to position ball sta WSYNC ;wait for sync lda missile1x ; load player 1's x position into the accumulator ldx #3 ; set the sprite to be positioned as missile 1 jsr PositionSprite ; jump to our Position Sprite Subroutine to position player 1 ButtonNotPressed ;*********************** VERTICAL BLANK WAIT-ER WaitForVblankEnd lda INTIM ; load timer... bne WaitForVblankEnd ; killing time if the timer's not yet zero ldy #191 ; Y is going to hold how many lines we have to do ; ...we're going to count scanlines here. theoretically ; since this example is ass simple, we could just repeat ; the timer trick, but often its important to know ; just what scan line we're at. sta WSYNC ; We do a WSYNC just before that so we don't turn on sta VBLANK ; End the VBLANK period with the zero and start charging ; the paddle controllers capasitors ;*********************** Scan line Loop ScanLoop lda INPT0 ; read the charge from the first paddle controller bmi paddle0 ; if paddle 0 is charged .byte $2c ; paddle 0 wasn't charged so waste 2 cycles paddle0 sty missile0y ; then set player 0's y position ; based on it's readout lda INPT1 ; read the charge from the first paddle controller bmi paddle1 ; if paddle 1 is charged .byte $2c ; paddle 1 wasn't charged so waste 2 cycles paddle1 sty missile1y ; then set player 1's y position ; based on it's readout lda #2 sta WSYNC ; Wait for the previous line to finish cpy missile0y ; is Missile 0's y position the same as the current scanline? bne SkipActivateMissile0; if it isn't then don't set Missile 0's visible lines lda #20 ; otherwise set Missile 0's visible lines to 20 sta visiblemissile0line ; and store it in the visiblemissile0line SkipActivateMissile0 lda visiblemissile0line ; if the visiblemissile0line is zero beq FinishMissile0 ; don't draw Missile 0 lda #2 ; otherwise set the accumulator to 2 dec visiblemissile0line ; and decrement the visiblemissile0line by 1 FinishMissile0 sta ENAM0 ; enable/disable Missile 0 ; if the visiblemissile0line is non zero, ; we're drawing it cpy bally ; is ball's y position the same as the current scanline? bne SkipActivateBall ; if it isn't then don't set ball's visible lines lda #8 ; otherwise set the ball's visible lines to 4 sta visibleballline ; and store it in the visibleballline SkipActivateBall lda visibleballline ; if the visibleballline is zero beq FinishBall ; don't draw the ball lda #2 ; otherwise set the accumulator to 2 dec visibleballline ; and decrement the visibleballline by 1 FinishBall sta ENABL ; enable/disable the ball ; if visibleballline is non, zero, ; we're drawing it cpy missile1y ; is Missile 1's y position the same as the current scanline? bne SkipActivateMissile1; if it isn't then don't set Missile 1's visible lines lda #20 ; otherwise set Missile 1's visible lines to 20 sta visiblemissile1line ; and store it in the visiblemissile1line SkipActivateMissile1 lda visiblemissile1line ; if the visibleballline is zero beq FinishMissile1 ; don't draw Missile 1 lda #2 ; otherwise set the accumulator to 2 dec visiblemissile1line ; and decrement the visiblemissile1line by 1 FinishMissile1 sta ENAM1 ; enable/disable Missile 1 ; if the visibleballline is non zero, ; we're drawing it dey ; subtract one off the line counter thingy bne ScanLoop ; and repeat if we're not finished with all the scanlines. lda #2 ;#2 for the VBLANK... sta WSYNC ;Finish this final scanline. lda #$82 ;sta VBLANK ; Make TIA output invisible for the overscan, ; (and keep it that way for the vsync and vblank) ;***************************** OVERSCAN CALCULATIONS ;I'm just gonna count off the 30 lines of the overscan. ;You could do more program code if you wanted to. ldx #30 ;store 30 OverScanWait sta WSYNC ; wait for VSync dex ; decrement the x register bne OverScanWait ; if it hasn't been 30 scanlines jump to OverScanWait jmp GameLoop ;Continue this loop forver! Back to the code for the vsync etc PositionSprite sta HMCLR sec sta WSYNC PositionSpriteLoop sbc #15 bcs PositionSpriteLoop eor #7 asl asl asl asl sta.wx HMP0,X sta RESP0,X sta WSYNC sta HMOVE rts ;************************************************************************* ; Interrupt Vectors ORG $FFFA InterruptVectors .word Start ; NMI .word Start ; RESET .word Start ; IRQ I removed the last VBLANK from my previous code and still am having problems. Any ideas? Sincerely, 6502Pong Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted March 30, 2009 Share Posted March 30, 2009 Your kernel is taking up too many cycles. BTW, please post zipped .asm files instead of posting the source for the entire game. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted March 30, 2009 Share Posted March 30, 2009 Yup...best case (where the shortest path is always taken) ends up using 70 cycles + 3 for WSYNC. Worst case (where the longest path is always taken) ends up using a whopping 100 cycles + 3 for WSYNC. It's probably a good idea to keep cycle time listed in areas that are time-critical. For kernel use, also a running total of cycle times for best-case/worst case scenarios. Commonly, this is preceded by the @ symbol in the comments. Here's your kernel with timing listed. A WSYNC resets the count, so begin there and wrap if a branch to earlier lines occur... ScanLoop ; this tag is reached @50/80 cycles. lda INPT0 ;3 @53/83 read the charge from the first paddle controller bmi paddle0 ;2 @55/85 if paddle 0 is charged .byte $2c ;4 @59/89 paddle 0 wasn't charged so waste 2 cycles paddle0 sty missile0y ;3 @59/89 then set player 0's y position ; based on it's readout lda INPT1 ;3 @62/92 read the charge from the first paddle controller bmi paddle1 ;2 @64/94 if paddle 1 is charged .byte $2c ;4 @68/98 paddle 1 wasn't charged so waste 2 cycles paddle1 sty missile1y ;3 @68/98 then set player 1's y position ; based on it's readout lda #2 ;2 @70/100! sta WSYNC ;Wait for the previous line to finish ;-------------------------- cpy missile0y ;3 @3 is Missile 0's y position the same as the current scanline? bne SkipActivateMissile0 ;2 @5 if it isn't then don't set Missile 0's visible lines lda #20 ;2 @7 otherwise set Missile 0's visible lines to 20 sta visiblemissile0line ;3 @10 and store it in the visiblemissile0line SkipActivateMissile0 lda visiblemissile0line ;3 @9/13 if the visiblemissile0line is zero beq FinishMissile0 ;2 @11/15 don't draw Missile 0 lda #2 ;2 @13/17 otherwise set the accumulator to 2 dec visiblemissile0line ;5 @18/22 and decrement the visiblemissile0line by 1 FinishMissile0 sta ENAM0 ;3 @15/25 enable/disable Missile 0 ; if the visiblemissile0line is non zero, ; we're drawing it cpy bally ;3 @18/28 is ball's y position the same as the current scanline? bne SkipActivateBall ;2 @20/30 if it isn't then don't set ball's visible lines lda #8 ;2 @22/32 otherwise set the ball's visible lines to 4 sta visibleballline ;3 @25/35 and store it in the visibleballline SkipActivateBall lda visibleballline ;3 @24/38 if the visibleballline is zero beq FinishBall ;2 @26/40 don't draw the ball lda #2 ;2 @28/42 otherwise set the accumulator to 2 dec visibleballline ;5 @33/47 and decrement the visibleballline by 1 FinishBall sta ENABL ;3 @30/50 enable/disable the ball ; if visibleballline is non, zero, ; we're drawing it cpy missile1y ;3 @33/53 is Missile 1's y position the same as current scanline? bne SkipActivateMissile1 ;2 @35/55 if it isn't then don't set Missile 1's visible lines lda #20 ;2 @37/57 otherwise set Missile 1's visible lines to 20 sta visiblemissile1line ;3 @40/60 and store it in the visiblemissile1line SkipActivateMissile1 lda visiblemissile1line ;3 @39/63 if the visibleballline is zero beq FinishMissile1 ;2 @41/65 don't draw Missile 1 lda #2 ;2 @43/67 otherwise set the accumulator to 2 dec visiblemissile1line ;5 @48/72 and decrement the visiblemissile1line by 1 FinishMissile1 sta ENAM1 ;3 @45/75 enable/disable Missile 1 ; if the visibleballline is non zero, ; we're drawing it dey ;2 @47/77 subtract one off the line counter thingy bne ScanLoop ;2 @49/79 and repeat if we're not finished with all the scanlines. Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted March 31, 2009 Share Posted March 31, 2009 You can save one more cycle, if you make sure that the *address* of e.g. paddle1 is an 1 byte opcode, e.g. $ea (nop) or $d8 (cld). MAC READ_PADDLE_1 lda INPT0 ; 3 - always 8 bmi .save+1 ; 2/3 .save sty paddle1 ; 3/2 ENDM Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted March 31, 2009 Share Posted March 31, 2009 (edited) You can save one more cycle, if you make sure that the *address* of e.g. paddle1 is an 1 byte opcode, e.g. $ea (nop) or $d8 (cld). MAC READ_PADDLE_1 lda INPT0 ; 3 - always 8 bmi .save+1; 2/3 .save sty paddle1; 3/2 ENDM Thats very clever I remember you posting that when I was writing Vong, but I never really understood it. It makes sense now though Edited March 31, 2009 by Wickeycolumbus Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.