home *** CD-ROM | disk | FTP | other *** search
- comment ^
-
- JOYSTICK.ASM, part of Emil Gilliam's Guide to Game Port Programming.
- By Emil Gilliam, 10/30/93.
-
- (C) Copyright 1993 Emil Gilliam. All rights reserved. This is freeware,
- not public domain. Read the legal information in JOYSTICK.TXT, which must be
- included with this file. Emil Gilliam will not be held liable for any damages
- or losses that result, directly, or indirectly, from the use or inability to
- use this source code. The legal information in JOYSTICK.TXT also applies to
- this file.
-
- This is a collection of routines for: Reading the status of controller(s)
- connected to the game port, determining whether or not there is a game port,
- and determining whether or not controller(s) are connected to the game port.
- The routines are meant to be called from C, in small model. The routines
- read_1_joystick and read_2_joysticks won't work in protected mode without
- modification, since they perform the sin of using segment registers to
- temporarily hold values (for speed, so I sorta have an excuse ;-) ).
-
- Feel free to modify these routines and use them for anything you want, but
- don't distribute a modified version of this source without my permission, and
- distribute this file with the accompanying files JOYSTICK.TXT and FILE_ID.DIZ,
- under the conditions described in JOYSTICK.TXT. If you use them in a program
- which you are distributing around, especially a shareware or commercial
- program, some credit would be nice (please let me know so I can brag that
- someone actually used this code ;-) ).
-
- Here's a list of the procedures in this file:
-
- int button_status();
- void read_1_joystick(int *x, int *y);
- void read_2_joysticks(int *x1, int *y1, int *x2, int *y2);
- int detect_game_port();
-
- read_1_joystick and read_2_joysticks now have a bug fix (SI and DI were not
- saved and ES was not saved correctly), thanks to Kip Cooley at the Diamond Bar
- BBS (909) 923-1031 (1:218/101). detect_game_port now has a little
- optimization in it, thanks to David Kirschbaum, "Toad Hall," at the Federal
- Post BBS (1:3634/2). Thanks, guys!
-
- ^
-
- .model small,c
- .code
-
- ;------------------------------------------------------------------------------;
- ; Handy little macro to get the timer 0 value into AX ;
- ;------------------------------------------------------------------------------;
-
- get_timer_0_value macro
- mov al,0 ;Latch timer 0
- out 43h,al
- jmp $+2 ;Wait for the hardware to respond
- in al,40h ;Get LSB
- mov ah,al
- jmp $+2
- in al,40h ;Get MSB
- xchg ah,al ;Put LSB and MSB into their proper places
- endm
-
- ;------------------------------------------------------------------------------;
- ; ;
- ; int button_status() ;
- ; ;
- ; This function returns the status of the joystick buttons in bits 0-3 of ;
- ; the return value. (The rest of the bits are 0.) 0 means a button is ;
- ; not being pressed; 1 means a button is being pressed. Note that this is ;
- ; the opposite of the meaning of the bits in the joystick port (where 1 ;
- ; means that a button is not being pressed, and 0 means that it is being ;
- ; pressed). ;
- ; ;
- ;------------------------------------------------------------------------------;
-
- public button_status
- button_status proc
-
- mov dx,201h ;Game port
- in al,dx ;Get a value from it
- ;Note: Those are really the only two lines you need to read the status of the
- ;joystick; the rest of the stuff here is just to make the button status bits
- ;go into bits 0-3, and the top 8 bits of AX 0, and to make 1 stand for a button
- ;being pressed instead of 0.
-
- not al ;Make 1 stand for a button-press
- mov cl,4
- shr al,cl ;Put it into the lower 4 bits of AX
- mov ah,0
-
- ret
-
- button_status endp
-
- ;------------------------------------------------------------------------------;
- ; ;
- ; void read_1_joystick(int *x, int *y) ;
- ; ;
- ; This procedure reads the x and y coordinates of joystick A and puts them ;
- ; them into the words pointed to by x and y (which are near pointers; DS ;
- ; is assumed to point to the data segment upon entry to this procedure). ;
- ; 0FFFFh is returned as a coordinate of a bit in the joystick port that ;
- ; never responded. This feature can make read_1_joystick useful as a ;
- ; joystick-detecting routine. Call read_1_joystick, and if either ;
- ; coordinate is returned as 0FFFFh, joystick A is not connected. Use this ;
- ; procedure instead of read_2_joysticks if you're only going to be reading ;
- ; joystick A because it's more accurate (since it only has to time 2 bits ;
- ; in the joystick port at once) and the code size is smaller. ;
- ; ;
- ; Now SI and DI are saved. (Thanks to Kip Cooley! See above...) ;
- ; ;
- ; ;
- ;------------------------------------------------------------------------------;
-
- public read_1_joystick
- read_1_joystick proc
-
- push bp ;Save BP
- mov bp,sp ;Set up stack framepointer
-
- pushf ;Save the flags
- push es ;Save ES
- push si ;Save SI
- push di ;Save DI
-
- cli ;Disable interrupts which might mess up our
- ; timing
-
- mov bx,-1 ;We're using BX and ES to hold the x and y
- mov es,bx ; coordinates
-
- mov dx,201h ;Joystick port
-
- get_timer_0_value ;Get the timer value
- mov di,ax ;Save it
-
- out dx,al ;Fire the joystick one-shots (doesn't matter
- ; what's in AX
-
- in al,dx ;Get the original joystick value
- and al,00000011b ;Get just the bits for the joystick A location
- mov cl,al
-
- r1j_loop:
- get_timer_0_value ;Get the timer value
- mov si,di ;Get the original timer value into SI
- sub si,ax ;Get the elapsed time into SI
- cmp si,1FF0h ;Has enough time passed yet?
- ja r1j_done ;Yes
-
- in al,dx ;Get the joystick coordinate bits
- and al,00000011b ;Get just the bits for the joystick A location
-
- cmp al,cl ;Is the value the same as the last time?
- je r1j_loop ;Yes
-
- xchg al,cl ;New value goes into CL
- xor al,cl ;Get the bits that have changed
-
- test al,1 ;Has the joystick A x-coordinate bit changed?
- jz r1j_loop_2
- mov bx,si ;Yes, we now have the joystick A x-coordinate
-
- r1j_loop_2:
- test al,2 ;Has the joystick A y-coordinate bit changed?
- jz r1j_loop
- mov es,si ;Yes, we now have the joystick A y-coordinate
- ; (Yeah, I know, it's a sin to use a segment
- ; register for holding a value like that, but I
- ; couldn't care less unless I had to convert
- ; this for protected mode...)
- jmp r1j_loop
-
- r1j_done:
- mov cl,4
-
- mov si,[bp+4] ;Get address of joystick A x-coordinate
- or bx,bx ;Is BX -1? (If so, don't shift right 4 bits)
- js r1j_done_2
- shr bx,cl ;Convert timings to 16/1193180's of a second
- r1j_done_2:
- mov [si],bx ;Save the joystick A x-coordinate
-
- mov si,[bp+6] ;Get address of joystick A y-coordinate
- mov ax,es
- or ax,ax
- js r1j_done_3
- shr ax,cl
- r1j_done_3:
- mov [si],ax ;Save the joystick A y-coordinate
-
- pop di ;Restore DI
- pop si ;Restore SI
- pop es ;Restore ES
- popf ;Restore the interrupt flag
-
- pop bp ;Restore BP
- ret ;We're outta here!
-
- read_1_joystick endp
-
- ;------------------------------------------------------------------------------;
- ; ;
- ; void read_2_joysticks(int *x1, int *y1, int *x2, int *y2) ;
- ; ;
- ; This function reads the x and y coordinates of joysticks A and B and ;
- ; puts them into the words pointed by x1, y1, x2, and y2 (which are near ;
- ; pointers; DS is assumed to be the data segment where these words are). ;
- ; 0FFFFh is returned as the coordinate for a bit in the joystick port ;
- ; never responded. This can make read_2_joysticks useful as a joystick- ;
- ; detecting procedure. If 0FFFFh is returned as either coordinate of a ;
- ; joystick, it can be assumed that that joystick isn't connected. ;
- ; ;
- ; The code here was written for speed and can be 4 times as fast as the ;
- ; code in the ROM BIOS for doing the same thing! The reason is that the ;
- ; ROM BIOS code usually times the 4 joystick bits separately (it will fire ;
- ; the joystick one-shots, time that one bit, fire them again, and so on). ;
- ; This routine fires the joystick one-shots ONCE and times all 4 bits at ;
- ; once! Of course, this brings up some obvious difficulties, namely that ;
- ; every time the value given by the joystick port changes, the routine ;
- ; has to test for each bit that could have possibly changed and handle ;
- ; each one separately. On slower computers, this would result in a loss ;
- ; of accuracy. But that's too bad! If you're a masochist and you need ;
- ; both speed and more accuracy on slower machines, you can modify this ;
- ; routine to push onto the stack timer chip values and joystick port ;
- ; values with each change of the joystick port value, and then sort ;
- ; through all this stuff after all the timing-critical stuff is over. ;
- ; ;
- ; Now SI, DI, and ES are saved properly, thanks to Kip Cooley (see above). ;
- ; Previously, ES wasn't saved properly since it was pushed after it was ;
- ; set to -1. ;
- ; ;
- ;------------------------------------------------------------------------------;
-
- public read_2_joysticks
- read_2_joysticks proc
-
- push bp ;Save BP
- mov bp,sp ;Set up stack framepointer
-
- mov bx,-1 ;Make some workspace on the stack
- push bx ;Start out with coordinate values of -1
- push bx ;If the corresponding bits in the joystick port
- ; don't change, these will stay -1
-
- pushf ;Save the flags
- push es ;Save ES
- push si ;Save SI
- push di ;Save DI
-
- mov es,bx
-
- cli ;Disable interrupts which might mess up our
- ; timing
-
- mov dx,201h ;Joystick port
-
- get_timer_0_value ;Get the timer value
- mov di,ax ;Save it
-
- out dx,al ;Fire the joystick one-shots (doesn't matter
- ; what's in AX
-
- in al,dx ;Get the original joystick value
- and al,00001111b ;Ignore the button bits
- mov cl,al
-
- r2j_loop:
- get_timer_0_value ;Get the timer value
- mov si,di ;Get the original timer value into SI
- sub si,ax ;Get the elapsed time into SI
- cmp si,1FF0h ;Has enough time passed yet?
- ja r2j_done ;Yes
-
- in al,dx ;Get the joystick coordinate bits
- and al,00001111b ;Ignore the button bits
-
- cmp al,cl ;Is the value the same as the last time?
- je r2j_loop ;Yes
-
- xchg al,cl ;New value goes into CL
- xor al,cl ;Get the bits that have changed
-
- test al,1 ;Has the joystick A x-coordinate bit changed?
- jz r2j_loop_2
- mov bx,si ;Yes, we now have the joystick A x-coordinate
-
- r2j_loop_2:
- test al,2 ;Has the joystick A y-coordinate bit changed?
- jz r2j_loop_3
- mov es,si ;Yes, we now have the joystick A y-coordinate
-
- r2j_loop_3:
- test al,4 ;Has the joystick B x-coordinate bit changed?
- jz r2j_loop_4
- mov [bp-4],si ;Yes, we now have the joystick B x-coordinate
-
- r2j_loop_4:
- test al,8 ;Has the joystick B y-coordinate bit changed?
- jz r2j_loop
- mov [bp-2],si ;Yes, we now have the joystick B y-coordinate
- jmp r2j_loop
-
- r2j_done:
- mov cl,4
-
- mov si,[bp+4] ;Get address of joystick A x-coordinate
- or bx,bx ;Don't shift BX by 4 bits if BX is -1
- js r2j_done_2
- shr bx,cl ;Convert timings to 16/1193180's of a second
- r2j_done_2:
- mov [si],bx ;Save the joystick A x-coordinate
-
- mov si,[bp+6] ;Get address of joystick A y-coordinate
- mov ax,es
- or ax,ax
- js r2j_done_3
- shr ax,cl
- r2j_done_3:
- mov [si],ax ;Save the joystick A y-coordinate
-
- mov si,[bp+8] ;Get address of joystick B x-coordinate
- mov ax,[bp-4]
- or ax,ax
- js r2j_done_4
- shr ax,cl
- r2j_done_4:
- mov [si],ax ;Save the joystick B x-coordinate
-
- mov si,[bp+10] ;Get address of joystick B y-coordinate
- mov ax,[bp-2]
- or ax,ax
- js r2j_done_5
- shr ax,cl
- r2j_done_5:
- mov [si],ax ;Save the joystick B y-coordinate
-
- pop di ;Restore DI
- pop si ;Restore SI
- pop es ;Restore ES
- popf ;Restore interrupt flag
-
- add sp,4 ;Discard temporary workspace on the stack
- pop bp ;Restore BP
- ret ;We're outta here!
-
- read_2_joysticks endp
-
- ;------------------------------------------------------------------------------;
- ; ;
- ; int detect_game_port() ;
- ; ;
- ; This function determines whether or not a there is a game port ;
- ; (regardless of whether or not controllers are actually connected to it ;
- ; or not). It returns 0FFFFh if there is a game port and 0 if there is ;
- ; no game port. This may not be very reliable (see JOYSTICK.TXT) so it ;
- ; might be better just to call read_1_joystick or read_2_joysticks to ;
- ; detect whether or not joysticks are connected, because it's not much ;
- ; use knowing that there's a game port but no controller connected (other ;
- ; than for diagnostic purposes). ;
- ; ;
- ; Now there's a little optimization in here, thanks to David Kirschbaum ;
- ; (see above). ;
- ; ;
- ;------------------------------------------------------------------------------;
-
- public detect_game_port
- detect_game_port proc
-
- mov dx,201h ;Game port number
- in al,dx
- cmp al,0FFh
- mov ax,0 ;Assume no game port (must use MOV AX,0 instead
- ; of XOR AX,AX since XOR AX,AX would change
- ; the flags set by CMP AL, 0FFh)
-
- je detect_ret ;Jump if no game port
- not ax ;Set AX to 0FFFFh since there is a game port
-
- detect_ret:
- ret ;Return
-
- detect_game_port endp
-
- end
-