View Single Post
Old 19 March 2017, 19:50   #6
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
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

Last edited by MickGyver; 09 June 2018 at 09:10. Reason: Bug fixes and changes to the code, read post
MickGyver is offline  
 
Page generated in 0.04386 seconds with 11 queries