page ,132 ;------------------------------------------------------------------------------ ; Module Name: READAXIS.ASM ; ; Assembly language routine for reading joystick axis position ; ; Created: Feb 17th, 1992 ; Author: Peter Wan ; ; Copyright (c) 1992 Advanced Gravis Computer Technology Limited ; ; Public Functions: ; get_loop_count ; read_axis ; Public Data: ; None ; General Description: ; This module contains functions to initialize itself and return ; joystick axis position. ;------------------------------------------------------------------------------ dosseg .model small ;------------------------------------------------------------------------------ ; Port address ;------------------------------------------------------------------------------ GAMEPORT equ 201h ;gameport address TIMER0 equ 40h ;8253 counter timer channel 0 address TIMER_CONTROL equ 43h ;counter timer control register address .data max_loop_count dw ? ;loop count for 3 milliseconds .code ;------------------------------------------------------------------------------ ; get_loop_count ; ; The purpose of this routine is to determine how many iteration of the ; following instruction loop can be accomplished in 3 milliseconds. The number ; of iteration count will be different on computers running at different speed ; or computers with different processing unit. In the read joystick axis ; routine, it uses a similar program loop to determine joystick axis position ; and the count results from this routine will be used to limit axis read time ; up to 3 millesecond maximum. This routine must be called once at ; initialization time. ; ; Entry: ; None ; Returns: ; None ; Error Returns: ; None ; Registers Preserved: ; BX,SI,DI,BP,DS,ES ; Registers Destroyed: ; AX,CX,DX ; Calls: ; None ;------------------------------------------------------------------------------ public _get_loop_count _get_loop_count proc init_count equ <[bp-2]> push bp mov bp,sp sub sp,2 ;2 bytes of local variable mov max_loop_count,0;use loop count of 16 to start with mov dx,GAMEPORT ;gameport address glc3: mov ax,0ff00h add max_loop_count,16 mov cx,max_loop_count cli ;system interrupt must be disabled out TIMER_CONTROL,al;latch count in timer 0 jmp short $+2 in al,TIMER0 ;read low byte of latched count mov init_count,al ;save jmp short $+2 in al,TIMER0 ;read high byte mov init_count+1,al ;save out dx,al ;trigger gameport in al,dx ;delay to allow gameport to switch on glc4: ;the following loop exits only when CX ;reaches zero in al,dx or al,ah loopnz glc4 mov ax,0 jnz $+2 out TIMER_CONTROL,al;latch count in timer 0 sti ;enable system interrupt jmp short $+2 in al,TIMER0 ;read low byte of latched count mov ah,al jmp short $+2 in al,TIMER0 ;read high byte xchg al,ah sub ax,init_count ;subtract count latched before ;entering loop by count just read neg ax cmp ax,7160 ;has it exceed 3 milliseconds? jl glc3 ;no, increment loop count by 16 and ;repeat process mov sp,bp pop bp ret _get_loop_count endp ;------------------------------------------------------------------------------ ; _read_axis ; ; This routine will accept a number from 0 to 3 for returning joystick axis ; position for joystick A-X, A-Y, B-X, B-Y respectively. After bit position ; of requested axis is determined, count reading in counter timer chip channel 0 ; will be read and saved. A write cycle to gameport address 201 hex will ; trigger and toggle all four axis lines from low to high state. The duration ; of these individual line staying high is directly proportional to the ; position of joystick for the individual axis. After the requested axis line ; has returned to the low state, count reading in counter timer chip will be ; read again. The real time count of the duration the requested axis has stayed ; high can be obtained from the difference of the two counts read. Allowance ; for other axis to return to low state must also be provided before next read. ; Therefore, return to calling function can only be done at the end of the ; 3 milliseconds duration. The real time count return to the callind function ; can have a value ranges from 1 to maximum of 7160 depending on the position ; of the joystick, value of capacitors used and threshold voltage set ; on the gamecard. If the requested axis has not returned to the low state ; after 3 milliseconds, it is assumed that no joystick is connected to that ; axis and zero will be returned to the calling function. During the ; 3 milliseconds duration, all interrupts except NMI will be disabled. ; ; Entry: ; [bp+4] = Axis to be read ; 0 = Joystick A - X axis ; 1 = Joystick A - Y axis ; 2 = Joystick B - X axis ; 3 = Joystick B - Y axis ; Returns: ; AX = Count ranges from 1 to maximun of 7160 corresponds to joystick ; position ; Error Returns: ; AX = 0 if no joystick connected ; Registers Preserved: ; BX,SI,DI,BP,DS,ES ; Registers Destroyed: ; AX,CX,DX ; Calls: ; None ;------------------------------------------------------------------------------ public _read_axis _read_axis proc axis equ <[bp+4]> init_count equ <[bp-2]> push bp mov bp,sp sub sp,2 ;2 bytes of local variable sub ax,ax ;determine bit position of axis to be mov ah,1 ;read mov cx,axis shl ah,cl mov cx,max_loop_count;use 3 milliseconds loop count obtian ;at initailization mov dx,GAMEPORT ;gameport address cli ;disable interrupt out TIMER_CONTROL,al;latch count in timer 0 jmp short $+2 in al,TIMER0 ;read low byte of latched count mov init_count,al ;save jmp short $+2 in al,TIMER0 ;read high byte mov init_count+1,al ;save out dx,al ;trigger gameport in al,dx ;delay to allow gameport to switch on ra1: in al,dx ;read gameport test al,ah ;requested axis return to low state or ;3 milliseconds passed? loopnz ra1 ;no mov ax,0 ;return 0 if 3 milliseconds passed and jnz ra3 ;requested axis not yet in low state out TIMER_CONTROL,al;requested axis return to low state ;latch count in timer 0 jmp short $+2 in al,TIMER0 ;read low byte of latched count mov ah,al jmp short $+2 in al,TIMER0 ;read high byte xchg al,ah sub ax,init_count ;obtain real time count of high state neg ax ;duration jcxz ra3 ;requested axis return to low state in ;exactly 3 milliseconds, all other axis ;should also have returned to low state ;by now push ax ;even though the requested axis has mov ah,0ffh ;returned to the low state, other axis ra2: ;may still be in the high state, we in al,dx ;should wait till the end of the or al,ah ;3 milliseconds duration to allow the loopnz ra2 ;other axis to return to high state pop ax ;before returning to the calling ;fucntion ra3: sti ;enable system interrupt mov sp,bp pop bp ret _read_axis endp end