Jump to content



1

Reading the paddle controlers


10 replies to this topic

#1 Primordial Ooze OFFLINE  

Primordial Ooze

    Dragonstomper

  • 504 posts
  • Quacker Blaster Lead Programmer
  • Location:United States of America

Posted Sun Mar 29, 2009 3:45 PM

Could someone please post some sample code on reading the paddle controllers and setting the missiles position based on its readout.

Sincerely,

6502Pong

#2 Wickeycolumbus OFFLINE  

Wickeycolumbus

    River Patroller

  • 4,063 posts
  • Location:Michigan

Posted Sun Mar 29, 2009 3:48 PM

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 by Wickeycolumbus, Sun Mar 29, 2009 3:52 PM.


#3 Nukey Shay ONLINE  

Nukey Shay

    Sheik Yerbouti

  • 20,458 posts
  • Location:The land of Gorch

Posted Sun Mar 29, 2009 5:03 PM

View PostWickeycolumbus, on Sun Mar 29, 2009 1:48 PM, said:

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.

#4 Nukey Shay ONLINE  

Nukey Shay

    Sheik Yerbouti

  • 20,458 posts
  • Location:The land of Gorch

Posted Sun Mar 29, 2009 5:16 PM

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.

#5 Primordial Ooze OFFLINE  

Primordial Ooze

    Dragonstomper

  • 504 posts
  • Quacker Blaster Lead Programmer
  • Location:United States of America

Posted Mon Mar 30, 2009 9:07 AM

View PostWickeycolumbus, on Sun Mar 29, 2009 4:48 PM, said:

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

Attached Files



#6 SpiceWare ONLINE  

SpiceWare

    Quadrunner

  • 5,987 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Mon Mar 30, 2009 9:43 AM

I have a Paddle Demo for the Atari VCS up at my website, it includes the source code.

Edited by SpiceWare, Mon Mar 30, 2009 9:45 AM.


#7 Primordial Ooze OFFLINE  

Primordial Ooze

    Dragonstomper

  • 504 posts
  • Quacker Blaster Lead Programmer
  • Location:United States of America

Posted Mon Mar 30, 2009 10:02 AM

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

#8 Wickeycolumbus OFFLINE  

Wickeycolumbus

    River Patroller

  • 4,063 posts
  • Location:Michigan

Posted Mon Mar 30, 2009 12:50 PM

Your kernel is taking up too many cycles.

BTW, please post zipped .asm files instead of posting the source for the entire game.

#9 Nukey Shay ONLINE  

Nukey Shay

    Sheik Yerbouti

  • 20,458 posts
  • Location:The land of Gorch

Posted Mon Mar 30, 2009 3:30 PM

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.


#10 Thomas Jentzsch OFFLINE  

Thomas Jentzsch

    Thrust, Jammed, SWOOPS!

  • 16,745 posts
  • Always left from right here!
  • Location:Düsseldorf, Germany

Posted Tue Mar 31, 2009 12:46 AM

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


#11 Wickeycolumbus OFFLINE  

Wickeycolumbus

    River Patroller

  • 4,063 posts
  • Location:Michigan

Posted Tue Mar 31, 2009 1:59 PM

View PostThomas Jentzsch, on Tue Mar 31, 2009 2:46 AM, said:

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 :thumbsup:
I remember you posting that when I was writing Vong, but I never really understood it. It makes sense now though :)

Edited by Wickeycolumbus, Tue Mar 31, 2009 2:00 PM.





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users