Joystick assembler routine

Basic and Machine Language

Moderator: Moderators

naujoks
Vic 20 Drifter
Posts: 35
Joined: Tue Aug 16, 2005 6:25 am

Joystick assembler routine

Post by naujoks »

Hello everybody, I'm trying to get into VIC-20 assembly programming and wanted to find a joystick routine.
It's surprisingly diffcult to find one!

Eventually I did find one on here:

joy_dir = $F7
joy1 = $911F
joy2 = $9120

LDA #$7F
STA $9122 ;set DDR for input

LDA joy1
AND #$3C
STA joy_dir
LDA joy2
AND #$80
ORA joy_dir
STA joy_dir

LDA #$FF
STA $9122
RTS

I assumed in practise this works like this:

joy_dir = $F7
joy1 = $911F
joy2 = $9120

LDA #$7F
STA $9122 ;set DDR for input

get LDA joy1
AND #$3C
STA joy_dir
LDA joy2
AND #$80
ORA joy_dir
STA joy_dir

JMP get

LDA #$FF
STA $9122
RTS

I didn't have any info on which values the joy_dir register would take when you move the joystick, so I wrote a little program which I thought would read the values.
I came up with: no input #188, left #172, right #60, up #184, down #180. Is that correct so far?

I used the above routine in my program like this:

get LDA joy1
AND #$3C
STA joy_dir
LDA joy2
AND #$80
ORA joy_dir
STA joy_dir

CMP #188
BEQ get

CMP #180 ; Joystick up?
BNE *+5
JMP up

CMP #172 ; Joystick left?
BNE *+5
JMP left

JMP get

Trouble is, it doesn't work as expected.
It's to move a little character across the screen, but by pressing the joystick left one, it's moving it over not just once, but as if the joystick is pressed to the left all the time.
Worse still, when pressing the joystick up, nothing happens at all.

Could someone tell me what I might be doing wrong? Thank you!
User avatar
srowe
Vic 20 Scientist
Posts: 1340
Joined: Mon Jun 16, 2014 3:19 pm

Re: Joystick assembler routine

Post by srowe »

naujoks wrote: I didn't have any info on which values the joy_dir register would take when you move the joystick, so I wrote a little program which I thought would read the values.
I came up with: no input #188, left #172, right #60, up #184, down #180. Is that correct so far?
I've not had time to try your code out but I've had a look at my FORTH implementation to refresh my memory.

Remember each direction is a bit in a VIA register

Code: Select all

VIA1PA2		= $911F		; VIA 1 DRA, no handshake
					; bit	function
					; ---	--------
					;  7	serial ATN out
					;  6	cassette switch
					;  5	joystick fire, light pen
					;  4	joystick left, paddle X fire
					;  3	joystick down
					;  2	joystick up
					;  1	serial DATA in
					;  0	serial CLK in

VIA2PB		= $9120		; VIA 2 DRB, keyboard column
					; bit	function
					; ---	--------
					;  7	joystick right, paddle Y fire
					;  3	cassette write line
Also the bit value goes from 1 to 0 so rather than comparing absolute values you should AND each direction.
User avatar
beamrider
Vic 20 Scientist
Posts: 1452
Joined: Sun Oct 17, 2010 2:28 pm
Location: UK

Re: Joystick assembler routine

Post by beamrider »

Welcome to try my routine....

Use like this...

jsr ReadPhysicalJoystick

;joystickFireButtonLatch - non zero - if fire pressed since last cleared

lda lastJoystickRead
and #JOY_PORT_LEFT
bne @left
lda lastJoystickRead
and #JOY_PORT_RIGHT
bne @right
lda lastJoystickRead
and #JOY_PORT_UP
bne @up
lda lastJoystickRead
and #JOY_PORT_DOWN
bne @down
; else---
jmp @none

@left: jmp HandleLeft
@right: jmp HandleRight
@up: jmp HandleUp
@down: jmp HandleDown
@none: jmp Nothing


Code: Select all

;*********************************************************************
; JOYSTICK
;
; Joystick Ports
JOY_PORT_DDR     = 37139
JOY_PORT         = 37137
JOY_PORT_SW3_DDR = 37154      
JOY_PORT_SW3     = 37152      

; Joystick Switches
JOY_PORT_UP =    %00000100
JOY_PORT_DOWN =  %00001000
JOY_PORT_LEFT =  %00010000
JOY_PORT_FIRE =  %00100000
JOY_PORT_RIGHT = %10000000

JOY_PORT_READ_MASK = JOY_PORT_UP|JOY_PORT_DOWN|JOY_PORT_LEFT|JOY_PORT_FIRE
JOY_PORT_READ_MASK_SW3 = JOY_PORT_RIGHT

; stored in lastJoystickRead
JOY_PORT_MOVING_MSK = JOY_PORT_UP|JOY_PORT_DOWN|JOY_PORT_LEFT|JOY_PORT_RIGHT


;------------------------------ imports -----------------------------

; ------------------------------ exports  -----------------------------
.global ReadPhysicalJoystick
.global lastJoystickRead
.global joystickFireButtonLatch
.global WaitForFire

; ------------------------------ Vars  -----------------------------
forceFirebuttonRelease: 		.byte 0
lastJoystickRead: 				.byte 0
joystickFireButtonLatch: 		.byte 0

; ------------------------------ WaitForFire -----------------------------
;-- Blocking wait for fire button
WaitForFire:

		lda #0
		sta joystickFireButtonLatch

@loop:

		jsr ReadPhysicalJoystick
		lda joystickFireButtonLatch
		beq @loop
		rts

; ------------------------------ ReadPlayerJoystick -----------------------------
;--  Reads joystick and leaves a result in the global lastJoystickRead and Accumulator
ReadPhysicalJoystick:
								
		lda JOY_PORT_DDR
		pha
		lda JOY_PORT_SW3_DDR ; will mess up keyboard if not restored...
		pha

		lda #0
		sta JOY_PORT_DDR
		sta JOY_PORT_SW3_DDR

		lda JOY_PORT
		eor #$FF ; convert closed to be represented as '1'
		and #JOY_PORT_READ_MASK  
		sta lastJoystickRead


		lda JOY_PORT_SW3
		eor #$FF
		and #JOY_PORT_READ_MASK_SW3  
		ora lastJoystickRead
		sta lastJoystickRead

		; see if we need to let go
		lda forceFirebuttonRelease
		beq @normal

		; reaquire actual joystick value
		lda lastJoystickRead
		and #JOY_PORT_FIRE
		bne @notReleased

@released:

		; ignore the fire button as not yet let go
		lda #0
		sta forceFirebuttonRelease
		lda lastJoystickRead
		jmp @normal

@notReleased:

		; ignore the fire button as not yet let go
		lda lastJoystickRead
		and #<(~JOY_PORT_FIRE)	
		sta lastJoystickRead
		jmp @normal 

@normal:

		; use to allow latching of the fire button with more frequent calling of this 
		; routine..
		lda lastJoystickRead
		and #JOY_PORT_FIRE
		ora joystickFireButtonLatch
		sta joystickFireButtonLatch

		pla
		sta JOY_PORT_SW3_DDR ; will mess up keyboard if not restored...
		pla
		sta JOY_PORT_DDR

		; return with current value in accumulator
		lda lastJoystickRead
		rts


naujoks
Vic 20 Drifter
Posts: 35
Joined: Tue Aug 16, 2005 6:25 am

Re: Joystick assembler routine

Post by naujoks »

Thank you for your help!
The FORTH implementation doesn't seem to offer me any help, unfortunately.

Beamrider, your routine looks good, but there are bits in there which I and CBM prg Studio don't understand, subsequently it throws some errors.
Would you be kind enough to let me know what various lines do?
1.
JOY_PORT_READ_MASK = JOY_PORT_UP|JOY_PORT_DOWN|JOY_PORT_LEFT|JOY_PORT_FIRE (this is something that I'm not familiar with, though CBM prg Studio doesn't flag it)

2.
; ------------------------------ exports -----------------------------
.global ReadPhysicalJoystick
.global lastJoystickRead
.global joystickFireButtonLatch
.global WaitForFire

This block gets marked as "Invalid instruction or Macro" in the first line, and then subsequently duplicate label.

It's probably just a question of semantics and your assembler does it differently from CBM prg Studio. Perhaps you know how CBM prg Studio handles this? Otherwise if you let me know what kind of function this is, I can try and find out the equivalent myself.

Thank you!!!!
naujoks
Vic 20 Drifter
Posts: 35
Joined: Tue Aug 16, 2005 6:25 am

Re: Joystick assembler routine

Post by naujoks »

PS: It might be easier if you tell me which crossassembler you're using, and I can check it out myself.
User avatar
beamrider
Vic 20 Scientist
Posts: 1452
Joined: Sun Oct 17, 2010 2:28 pm
Location: UK

Re: Joystick assembler routine

Post by beamrider »

I use CA65

You can probably ignore the global directives and the other lines you queried are defining constants that's all.
naujoks
Vic 20 Drifter
Posts: 35
Joined: Tue Aug 16, 2005 6:25 am

Re: Joystick assembler routine

Post by naujoks »

Thanks, I'll try to work through it.
Just out of interest, if this line
JOY_PORT_READ_MASK = JOY_PORT_UP|JOY_PORT_DOWN|JOY_PORT_LEFT|JOY_PORT_FIRE
defines a variable, what does it actually define?
User avatar
beamrider
Vic 20 Scientist
Posts: 1452
Joined: Sun Oct 17, 2010 2:28 pm
Location: UK

Re: Joystick assembler routine

Post by beamrider »

It performs a bitwise OR on the values to define a MASK that selects the relevant bits for reading all the joystick directions.
naujoks
Vic 20 Drifter
Posts: 35
Joined: Tue Aug 16, 2005 6:25 am

Re: Joystick assembler routine

Post by naujoks »

I see, so do you think
JOY_PORT_READ_MASK = JOY_PORT_UP OR JOY_PORT_DOWN OR JOY_PORT_LEFT OR JOY_PORT_FIRE

would do the same thing in CBM Studio?

It also doesn't like this line:
and #<(~JOY_PORT_FIRE)
User avatar
beamrider
Vic 20 Scientist
Posts: 1452
Joined: Sun Oct 17, 2010 2:28 pm
Location: UK

Re: Joystick assembler routine

Post by beamrider »

not sure - depends if the OR is a logical or bitwise operator. You should be able to use + in this instance instead.

the other line just takes the lower 8 bits - I'm not sure why it's there without revisiting the code Try removing the '<'. In any case the value would be ~%00100000 = %11011111

btw, these are the kind of niggles that made me switch away from CbmPrg
naujoks
Vic 20 Drifter
Posts: 35
Joined: Tue Aug 16, 2005 6:25 am

Re: Joystick assembler routine

Post by naujoks »

I can't seem to find the CA65 to download anywhere, would be so kind an point me in the right direction?
User avatar
beamrider
Vic 20 Scientist
Posts: 1452
Joined: Sun Oct 17, 2010 2:28 pm
Location: UK

Re: Joystick assembler routine

Post by beamrider »

naujoks
Vic 20 Drifter
Posts: 35
Joined: Tue Aug 16, 2005 6:25 am

Re: Joystick assembler routine

Post by naujoks »

I've found a routine which I've disassembled like this:

LDA $911F
EOR #$FF
AND #$3C
LDX #$7F
SEI
STX $9122
LDY $9120
BMI jump
ORA #$02
jump LDX #$FF
STX $9122
CLI
LSR A
STA $90

$90 holds direction:
up: 2
down: 4
left: 8
right: 1
fire: 16

down-left: 12
up-left: 10
up-right: 3
down-right: 5

It seems to work so far. One thing it does is move my little character right across the screen, even when it press the joystick very briefly. It seems read even that short press as pressing it hundreds of time. As my program grows, I expect the natural slow down prevent it from interpreting the one press of the joystick as a holding down, but it would be interesting to find out if there's a way of clearing the input after a very shot amount of time.
User avatar
srowe
Vic 20 Scientist
Posts: 1340
Joined: Mon Jun 16, 2014 3:19 pm

Re: Joystick assembler routine

Post by srowe »

You probably want to 'de-bounce' by storing the value from the previous call and only acting when the value is different in a later call.

Code: Select all

        LDA #0

loop    STA prev
        JSR joy
        LDA $90
        CMP prev
        BNE move
        JMP loop
User avatar
GreyGhost
Vic 20 Nerd
Posts: 525
Joined: Wed Oct 05, 2005 11:10 pm

Re: Joystick assembler routine

Post by GreyGhost »

That first one routine looks like it was written by me a while ago. It should work correctly but I haven't played around with the Vic 20 for a few years now. The routine in it's entirety looked like this:

Code: Select all

joy_dir = $f7           ;could be any location in RAM
joy1    = $911F
joy2    = $9120


joy_moves 
   JSR joy_stick        ;check joystick
   LDA joy_dir
   CMP #$b8             ; up
   BEQ chk_up
   CMP #$ac             ; left
   BEQ chk_left
   CMP #$b4             ; down   
   BEQ chk_down
   CMP #$3c             ; right
   BEQ chk_right
   JMP joy_moves

joy_stick
   LDA #$7f             ;
   STA $9122            ;set DDR for input
   LDA joy1
   AND #$3c
   STA joy_dir
   LDA joy2
   AND #$80
   ORA joy_dir               	
   STA joy_dir
   LDA #$ff
   STA $9122	
   RTS	


Directions Are As Follows:
              Dec Hex                            Dec Hex
=========================================================
No Movement = 188($bc)          Button Pressed = 156($9c)
UP          = 184($b8)          Up             = 152($98)
Up/Right    = 56 ($38)          Up/Right       = 24 ($18)
Right       = 60 ($3c)          Right          = 28 ($1c)
Down/Right  = 52 ($34)          Down/Right     = 20 ($14)
Down        = 180($b4)          Down           = 148($94)
Down/Left   = 164               Down/Left      = ???
Left        = 172               left           = 140
Up/Left     = 168               Up/Left        = 136
Rob
Post Reply