Difference between revisions of "Reading Controllers"

From veswiki
Jump to: navigation, search
(Reading the four console buttons)
(Reading the four console buttons)
 
Line 137: Line 137:
 
readbuts:      ins  0                    ; $00C1 - read buttons
 
readbuts:      ins  0                    ; $00C1 - read buttons
 
                 com                      ; Invert port data, 1 now means pushed
 
                 com                      ; Invert port data, 1 now means pushed
                 ni  $0f                 ; Just keep button data
+
                 ni  $0F                 ; Just keep button data
 
                 bz  readbuts            ;  
 
                 bz  readbuts            ;  
 
                 lr  $4, A                ; Button indata now in r4
 
                 lr  $4, A                ; Button indata now in r4
  
                 li  $ff                 ; Set r5 to $FF and decrease it
+
                 li  $FF                 ; Set r5 to $FF and decrease it
 
                 lr  5, A                ;  
 
                 lr  5, A                ;  
 
debounce:      ds  5                    ;  
 
debounce:      ds  5                    ;  
 
                 bnz  debounce            ;  
 
                 bnz  debounce            ;  
  
                 br  delay                ; Also do a delay, for some reason
+
                 br  delay                ; Also do a delay (for some reason)
  
 
                 ; Delay routine is located earlier in the code:
 
                 ; Delay routine is located earlier in the code:
  
delay:          li  $ff                ;$008f - parameter in r5, uses r6
+
delay:          li  $FF                  ;$008F - parameter in r5, uses r6
                 lr  6, A               ;
+
                 lr  6, A                 ;
dlyloop:        ds  6                   ;
+
dlyloop:        ds  6                   ;
                 bnz  dlyloop             ;
+
                 bnz  dlyloop             ;
                 ds  5                   ; Loops another time if value is set in r5
+
                 ds  5                   ; Loops another time if value is set in r5
                 bnz  delay               ;
+
                 bnz  delay               ;
  
                 pop                     ;
+
                 pop                       ;
 
</pre>
 
</pre>
  

Latest revision as of 18:58, 6 August 2020

Wait for controller movement

The simplest use of hand controller is to just pause and wait for a movement, this subroutine does just that, you call it with:

; Add this subroutine call to your code:

	pi	wait.4.controller.input

; Movement from either Hand Controller will continue the program


; here's the actual subroutine, copy and paste to your program where convenient

wait.4.controller.input:
	; see if one of the hand controllers has moved
	clr						; clear accumulator 
	outs	0					; enable input from both hand controllers
	outs	1					; clear latch of port of right hand controller
	outs	4					; clear latch of port of left hand controller
	ins	1					; fetch inverted data from right hand controller
	com						; invert controller data (a %1 now means active)
	bnz	wait.4.controller.input.end		; if no movement then input is 0 -> no branch
	; check the other controller
	ins	4					; fetch inverted data from left hand controller
	com						; invert controller data (if bit is 1 it means active)
	bz	wait.4.controller.input			; if there's no indata repeat

wait.4.controller.input.end:
	pop						; return from subroutine, controller data in A

Controller directions in the register

After the hand controller data has been read from the port latch a 1 means inactive and 0 means active. It's common to want the 1 showing active signal therefore it's inverted with the com opcode as seen above. This is not a necessary step, port data could just as easily be used and save a machine cycle.

The 8 bits are stored in Accumulator (A) and the bits mean this:

        direction
bit  0  right
bit  1  left
bit  2  backward
bit  3  forward
bit  4  counterclockwise
bit  5  clockwise
bit  6  pull up
bit  7  push down


Port-data
%00000001  right
%00000010  left
%00000100  backward
%00001000  forward
%00010000  counterclockwise
%00100000  clockwise
%01000000  pull up
%10000000  push down

Combinations are possible to:
%10000010  push down + left

There are combinations that are impossible with a normal fully functional controller since they are opposite directions:
%11000000  push down + pull up

The "Jet Stick" however could do this as the fire button is parallel to the push down function.

After reading the controller/s it's handy to store it in a register (or in available RAM) for use later
unless checking directly which direction was chosen.
Imagine you have written a game where you can move forward, backward, right or left with the right hand controller.
If we store the result of the controller in register 8, this is how to do it:

Store result for later use

store.right.controller.input:
	
	clr
	outs	0
	outs	1						; check right hand controller
	ins	1
	com							; re-invert controller data
	lr	8, A						; store result in register 8

store.right.controller.input.end:


Later in the program we can load the movement and mask away the directions we're interested in.


	; 	program program
	; 	...
	
	lr	A, 8						; copy register 8 to Ackumulator
	ni	%00001111					; AND result and only keep the last nibble
	lr	8, A						; back up result in r8 again

	;	...
	;	program continues


We now have one of these bit patterns in r8:

%00000000	no movement
%00000001	right
%00000010	left
%00000100	backward
%00000101	backward + right
%00000110	backward + left
%00001000	forward
%00001001	forward + right
%00001010	forward + left

Nothing else is possible with your normal controller unless something is broken.

The controller value can then be compared to the values above to decide what to do next, move the player perhaps.

Reading the four console buttons

There's a routine in the Channel F firmware that can be used directly if needed.
It starts at $00C1, stores the result in register 4, register 5 and 6 are also used.

Port 0 needs to be cleared at least once in the code before reading buttons:

                clr
                outs	0
readbuts:       ins  0                    ; $00C1 - read buttons
                com                       ; Invert port data, 1 now means pushed
                ni   $0F                  ; Just keep button data
                bz   readbuts             ; 
                lr   $4, A                ; Button indata now in r4

                li   $FF                  ; Set r5 to $FF and decrease it
                lr   5, A                 ; 
debounce:       ds   5                    ; 
                bnz  debounce             ; 

                br   delay                ; Also do a delay (for some reason)

                ; Delay routine is located earlier in the code:

delay:          li   $FF                  ;$008F - parameter in r5, uses r6
                lr   6, A                 ;
dlyloop:        ds   6                    ;
                bnz  dlyloop              ;
                ds   5                    ; Loops another time if value is set in r5
                bnz  delay                ;

                pop                       ;


In your code you can now use the button data to check which buttons/combos are set.

	lr	A, 4				; load button result into Ackumulator again
	ni	%00000010			; mask out button #2
	bnz	main.buttons.used.two		; not zero means button 2 was pressed
	lr	A, 4				; load read result into A again
	ni	%00000001			; check if it was button #1
	bnz	main.buttons.used.one		; if that's not 0 it means button 1 was held

	br	main.continue			; continue program

The intelligent reader has already figured out the rest of the inputs available:

-----4321
%00000001  button 1
%00000010  button 2
%00000011
%00000100  button 3
%00000101
%00000110
%00000111
%00001000  button 4
%00001001
%00001010
%00001011
%00001100  button 4 + 3
%00001101
%00001110
%00001111   all buttons pressed

Quickest controller read

readController:
	clr
	outs	0
	outs	1
	ins	1
	pop

This one only reads data for right controller as port read is faster on the CPU where right controller is hooked up. Data is not inverted, for an active movement the bit is set to 0, any masking is done in the main program if needed.


Conclusion

Read right hand controller this way:

	clr
	outs	0
	outs	1
	ins	1
	com		

Read left hand controller this way:

	clr
	outs	4
	ins	4
	com

Read buttons with:

	clr
	outs	0
	ins	0
	com

	; you may need to debounce as described above

And you have the result in A