I started experimenting with inline assembly in Blitz Basic 2. Here is an alternative joystick / CD32 gamepad routine written in assembly. You can use it like a normal function, usage example included in code. This function will also read the joystick directions so it can replace all joyx joyy joyb calls, I have no idea if this is any faster though, I haven't tested.
EDIT1: There is a bug somewhere in this routine that causes problems on hardware, port 1 is working fine but not port 2. So I advice you not to use this until I find the bug... Can anybody see the problem? Probably a wrong address or something.
EDIT2: Ok, I found the bug. I had a MOVEQ instead of a MOVE.w instruction and another interesting problem was that when reading both ports, the second port would always return a pressed blue button status. This is because the capacitors used for pins on the joystick ports are so big so it takes up to 300µs for the pin mode change to take effect. Instead of resetting the pins after each port read, I created a macro that resets both ports after reading them, so this macro needs to be called once after reading one or both joystick ports. The code is now updated, I have tested it on my stock A500 and A1200 with cd32 pad + mouse, joystick + mouse, cd32 pad + joystick and cd32 pad + cd32 pad.
EDIT3: Edited the code one more time, POTGO value is now restored to it's previous state after reading joystick port(s). I made a JoyTester program, you can download it below if interested (bootable adf image, tested on A500 and A1200, source included):
http://www.gamephase.net/files/JoyTesterv10.zip
EDIT4: Did some adjustments to the code. I removed the ReadPotgo and RestorePotgo macros (POTGO is "restored" with Poke at end of routine). Commented UNLK a4 at the start of the routine and replaced RTS at end of routine with AsmExit (talked about below).
Code:
; CD32 GAMEPAD ROUTINE FOR BLITZ BASIC 2
#JOY_UP = 8
#JOY_DOWN = 4
#JOY_LEFT = 2
#JOY_RIGHT = 1
#JOY_BUTTON1 = 2048
#JOY_BUTTON2 = 4096
#CD32_RED = 2048
#CD32_BLUE = 4096
#CD32_GREEN = 512
#CD32_YELLOW = 1024
#CD32_LTRIGGER = 128
#CD32_RTRIGGER = 256
#CD32_PLAY = 64
#CD32_GAMEPAD = 16
DEFTYPE .w
Function.w ReadJoy{n}
; UNLK a4 ; Must be at the top of an assembly procedure (a4 is used as local variable base). EDIT: Seems that this is not necessary after all.
BTST #0,d0 ; Test if d0=1 by testing bit 0 (Z=0 if bit 0 is 1)
BNE.b joy1 ; Branch to joy1 if Z=0
; ---------------------------------------------------
; Joy0
MOVEQ #6,d3 ; Button 1 bit (bit 6 (/FIR0) at address $BFE001 which is CIAA PRA)
; also bit 6 of $BFE201 which is CIAA DDRA (data direction of joy0 pin 6)
MOVE.w #10,d4 ; Button 2 bit (joy0 pin 9, POTGOR)
MOVE.w #$f600,d5 ; Used to set POTGO (joy0 pin 5 output low) was f600
MOVEA.l #$dff00a,a0 ; Joystick 0 data address (joy0dat)
BRA directions
; ---------------------------------------------------
joy1:
MOVEQ #7,d3 ; Button 1 bit (bit 7 (/FIR1) at address $BFE001 which is CIAA PRA)
; also bit 7 of $BFE201 which is CIAA DDRA (data direction of joy1 pin 6)
MOVE.w #14,d4 ; Button 2 bit for Joy1 (joy1 pin 9, POTGOR)
MOVE.w #$6f00,d5 ; Used to set POTGO (joy1 pin 5 output low) was 6f00
MOVEA.l #$dff00c,a0 ; Joystick 1 data address (joy1dat)
MOVEQ #0,d0 ; Set d0 to 0
MOVE.w #0,d6 ; Set d6 to 0
; ---------------------------------------------------
directions:
MOVE.w (a0),d0 ; Read joy0dat or joy1dat to d0
MOVE.w d0,d1 ; Copy d0 to d1
LSR.w #1,d1 ; Shift d1 one bit to the right
EOR.w d0,d1 ; Exclusive OR d0 and d1 and store in d1
BTST #8,d1 ; Check joystick up (test bit 8 and set Z to 1 if bit is 0)
SNE d6 ; Set first byte of d7 to %11111111 if Z bit is set
ADD.w d6,d6 ; Add d7 to itself
BTST #0,d1 ; Check joystick down (test bit 0... read above)
SNE d6
ADD.w d6,d6
BTST #9,d0 ; Check joystick left (test bit 9... read above)
SNE d6
ADD.w d6,d6
BTST #1,d0 ; Check joystick right (test bit 1... read above)
SNE d6
ADD.w d6,d6
LSR.w #8,d6 ; Shift d6 8 steps to the right (logical)
ANDI.b #%1111,d6 ; Save only bits 0-3 of d6
; ---------------------------------------------------
; Normal buttons
BTST d3,$bfe001 ; Check button 1 bit at CIAA PRA
BNE.b button2 ; Branch to button2 if button1 is not pressed
BSET #11,d6 ; If button1 is pressed, set bit 13 of d6
button2:
BTST d4,$dff016 ; Check button 2 bit at POTGOR (aka. POTINP)
BNE.b cd32 ; Branch to cd32 if button2 is not pressed
BSET #12,d6 ; If button2 is pressed, set bit 13 of d6
; ---------------------------------------------------
; CD32 buttons
cd32:
BSET d3,$bfe201 ; Set ciaa ddr port a high (configure /fire0 as output) 6=joyport0, 7=joyport1
BCLR d3,$bfe001 ; Set /fire0 low
MOVE.w d5,$dff034 ; Set pin 5 as output low (write to potgo)
MOVEQ #0,d0 ; Set d0 to 0
MOVEQ #8,d1 ; Set d1 to 9, this will be used for the button read loop
BRA in ; jump to in
loop:
TST.b $bfe001 ; Read CIAA PRA multiple times to create a delay so a reliable button status
TST.b $bfe001 ; can be read.
in:
TST.b $bfe001
TST.b $bfe001
TST.b $bfe001
TST.b $bfe001
TST.b $bfe001
TST.b $bfe001
MOVE.w $dff016,d2 ; Read POTGOR to d2
BSET d3,$bfe001 ; Set /fire0 high (clock pulse for shift register)
BCLR d3,$bfe001 ; Set /fire0 low
BTST d4,d2 ; Test bit 10 or 14 of POTGOR (pin 9, CD32 gamepad button data)
BNE.b readnext ; Branch to readnext if pin 9 is 1 (0 means button is pressed)
BSET d1,d0 ; Set bit d1 of d0 if button is pressed
readnext:
DBF d1,loop ; Decrement d1 and jump to loop if d1 > 0
BSET d3,$bfe001 ; Set button1 high
BCLR d3,$bfe201 ; Set ciaa ddr port as input
MOVE.b d0,d1 ; Copy first byte of d0 to d1
ANDI.b #%11,d1 ; Save the lowest two bits of d1
CMPI.b #%01,d1 ; Check if lowest bits equal %01 (cd32 gamepad signature)
BEQ.b cd32ok ; If cd32 signature is ok, branch to cd32ok
MOVE.b #0,d0 ; Clear low byte of d0 since cd32 button readings are wrong
cd32ok:
LSL.w #4,d0 ; Shift d0 four steps to the left
OR.l d6,d0 ; Combine d0 with d6 by using bitwise OR
AsmExit
End Function
BLITZ ; Go into blitz mode
BitMap 0, 320, DispHeight, 5 ; Create a bitmap
PalRGB 0,1,15,15,15
BitMapOutput 0
Slice 0,42,5
Use Palette 0
Show 0, 0, 0
joystick = 0
Repeat
VWait
; Read joy1 (0 for joy0)
joystick = ReadJoy{1}
; Reset POTGO register, call this after reading ports 0 and 1
; So if reading both ports, do that above and then call this once
Poke.w $dff034,$ff00
; Print joystick variable
Locate 0,0 : Print Bin$(joystick)
; CD32 gamepad check
Locate 0,1
If joystick & #CD32_GAMEPAD
Print "CD32 Gamepad Connected! "
Else
Print "Normal joystick connected!"
EndIf
; Direction check
Locate 0,2
If joystick & #JOY_UP
Print "Going up!"
Else
Print " "
EndIf
; Button check
Locate 0,3
If joystick & #CD32_PLAY
Print "Play is pressed!"
Else
Print " "
EndIf
Until Joyb(0)>0