Category : Pascal Source Code
Archive   : CMPLTPAS.ZIP
Filename : GAMER.ASM

 
Output of file : GAMER.ASM contained in archive : CMPLTPAS.ZIP
;===========================================================================
;
; G A M E R - Assembly language joystick support for Turbo Pascal
;
;===========================================================================
;
; by Jeff Duntemann 12 February 1988
; with thanks to Ted Mirecki for additional insights
;
; From: COMPLETE TURBO PASCAL 5.0 by Jeff Duntemann
; Scott, Foresman & Co., Inc. 1988 ISBN 0-673-38355-5
;
;
; GAMER is a single assembly-language source file that contains both
; STICK.ASM and BUTTON.ASM, which are given separately elsewhere in
; COMPLETE TURBO PASCAL, 3E. The purpose of GAMER is to show how multiple
; assembly language procedures may be combined into a single machine-code
; module to lessen program clutter.
;
; The idea is to create a Turbo Pascal unit incorporating the routines in
; this module. The unit source file is GAMEBORD.PAS. The headers of both
; routines must be laid out in the interface section of GAMEBORD.PAS, and
; the .OBJ file containing the routines must be loaded into the
; implementation section of GAMEBORD.PAS using the $L compiler directive:
;
; INTERFACE
;
; FUNCTION Button(StickNumber,ButtonNumber : Integer) : Boolean;
;
; PROCEDURE Stick(StickNumber : Integer;
; VAR X : INTEGER;
; VAR Y : INTEGER);
;
; IMPLEMENTATION
;
; {$L GAMER}
; FUNCTION Button; EXTERNAL;
; PROCEDURE Stick; EXTERNAL;
;
;
;
; GAMEBORD.PAS is given elsewhere in COMPLETE TURBO PASCAL, 3E
;
;
; To reassemble/relink GAMER:
;-------------------------------------
; Assemble this file with MASM. "C>MASM GAMER;"
;
;


CODE SEGMENT BYTE PUBLIC ; THE SEGMENT IS BYTE-ALIGNED
ASSUME CS:CODE
PUBLIC BUTTON,STICK ; THE TWO ACCESSIBLE PROCS IN THIS MODULE



;===========================================================================
; B U T T O N - Function to return the state of the joystick buttons
;===========================================================================
;
; The full function header follows:
;
; FUNCTION BUTTON(StickNumber,ButtonNumber : Integer) : Boolean;
;
; StickNumber specifies which joystick to read from, and ButtonNumber
; specifies which of the two buttons on that joystick to read. If the
; specified button is down, BUTTON returns a Boolean value of TRUE.
;
; Yes, this is the long way 'round; assembly language is in no way required
; to read four bits from an ordinary 8088 I/O port. BUTTON exists only as
; practice in creating assembly language external functions.
;
; The button information is obtained by reading I/O port $201. The high
; four bits represent the state of the four buttons (two for each of the
; two possible joysticks) at the instant the port is read. A LOW bit
; represents a button DOWN. This is why the byte read from the port is
; inverted via NOT before the selected bit is tested.
;
; Here is a map of the button bits as returned by port $201:
;
; |7 6 5 4 3 2 1 0|
; | | | |
; | | | - - - - - - -> Button #1, joystick #1
; | | - - - - - - - -> Button #2, joystick #1
; | - - - - - - - - -> Button #1, joystick #2
; - - - - - - - - - -> Button #2, joystick #2
;
; Remember that the return value from this function is passed to the runtime
; code in the AL register.
;
;
; This structure defines the layout of BUTTON's parameters on the stack:
;
ONSTACK1 STRUC
OLDBP DW ? ;TOP OF STACK
RETADDR DD ? ;FAR RETURN ADDRESS
BTN_NO DW ? ;BUTTON NUMBER
STIK_NO DW ? ;STICK NUMBER
ONSTACK1 ENDS

BUTTON PROC FAR ;ALL PROCS IN A UNIT ARE FAR PROCS
PUSH BP ;SAVE PREVIOUS VALUE OF BP ON STACK
MOV BP,SP ;SP BECOMES NEW VALUE OF BP

;-------------------------------------------------------------------
; THE BULK OF THIS ROUTINE SETS UP A TEST MASK BY WHICH ONE SINGLE
; BIT OUT OF THE FOUR BUTTON BITS IS TESTED.
;-------------------------------------------------------------------

MOV BL,010H ;START WITH HIGH BIT IN BIT 4
CMP [BP].STIK_NO,2 ;ARE WE TESTING FOR JOYSTICK #2?
JNE WHICH ;IF NOT, GO ON TO TEST FOR WHICH BUTTON,
SHL BL,1 ; OTHERWISE SHIFT TWO POSITIONS LEFTWARD
SHL BL,1 ; SO THAT THE MASK IS ON BIT 6 FOR STICK 2

WHICH: CMP [BP].BTN_NO,2 ;ARE WE TESTING FOR BUTTON #2?
JNE READEM ;IF NOT, MASK IS CORRECT; GO READ PORT
SHL BL,1 ;OTHERWISE, SHIFT 1 BIT LEFT FOR BUTTON 2

;------------------------------------------------------------------------
; THE BIT MASK IS NOW CORRECT. HERE THE BUTTON BITS ARE READ FROM PORT
; $201 AND TESTED AGAINST THE MASK. NOTE THAT THE BITS AS READ FROM
; THE PORT MUST BE INVERTED SO THAT THE Z FLAG IS SET RATHER THAN CLEARED
; ON AN ACTIVE BUTTON BIT. (BITS ARE ACTIVE **LOW**, REMEMBER!)
;------------------------------------------------------------------------

READEM: MOV DX,0201H ;SET UP 16-BIT ADDRESS FOR PORT READ
IN AL,DX ;READ BUTTON BITS FROM PORT $201
NOT AL ;MUST INVERT BITS FOR PROPER SENSE
; OF THE Z FLAG AFTER TESTING
TEST AL,BL ;SEE IF THE DESIRED BIT IS HIGH;
JNZ PUSHED ;IF SO, BUTTON IS PUSHED,
MOV AL,0 ;SO MOVE BOOLEAN FALSE INTO AL
JMP BDONE ;AND GET OUT OF HERE

PUSHED: MOV AL,1 ;BUTTON DOWN; MOVE BOOLEAN TRUE INTO AL

BDONE: MOV SP,BP ;RESTORE PRIOR STACK POINTER & BP
POP BP ; IN CONVENTIONAL RETURN
RET 6

BUTTON ENDP



;===========================================================================
; S T I C K - Procedure to read either joystick
;===========================================================================
;
; The procedure header follows:
;
; PROCEDURE STICK(StickNumber : Integer VAR X,Y : Integer);
;
; StickNumber specifies which joystick to read from, and the X and Y
; parameters return integers proportional to the joystick's position
; at the moment the stick is sampled. These integers will vary from
; stick to stick depending on the resistance of the potentiometers
; used within the stick, but will typically from from 3 to 150.
;
; The IBM standard game controller board consists of two pairs of
; one-shots, which output a pulse when triggered by an I/O write to
; I/O port $201. The length of this pulse is determined by an RC
; time constant circuit the resistance portion of which is the
; potentiometer in the joystick. As the handle is moved around, the
; two potentiometers (one for X, one for Y) run up and back, changing
; resistance as they go.
;
; To read one of the two joysticks, a dummy value (which may be anything
; at all) is written to I/O port $201. Port $201 must then be polled
; continuously, incrementing a register at each polling event. When
; the bit corresponding to that stick's X or Y coordinate changes state,
; the count in the register is returned as that coordinate value at the
; time the stick was sampled.
;
; Here is a map of the joystick bits as returned by port $201:
;
; |7 6 5 4 3 2 1 0|
; | | | |
; | | | - - - - - - -> X coordinate, joystick #1
; | | - - - - - - - -> Y coordinate, joystick #1
; | - - - - - - - - -> X coordinate, joystick #2
; - - - - - - - - - -> Y coordinate, joystick #2
;
; One thing to keep in mind is that a bit goes LOW when sampled, and
; you must test for a HIGH on that bit to indicate that the one-shot has
; timed out.
;
;
;
; This structure defines STICK's parameters on the stack.
;
ONSTACK2 STRUC
OLDBP2 DW ? ;TOP OF STACK
RETADDR2 DD ? ;FAR RETURN ADDRESS
YADDR2 DD ? ;FAR ADDRESS OF X VALUE
XADDR2 DD ? ;FAR ADDRESS OF Y VALUE
STIK_NO2 DW ? ;STICK NUMBER
ONSTACK2 ENDS

; EQUATES FOR ONE-SHOT BITS FOR STICKS 1 & 2

STICK_X EQU 1
STICK_Y EQU 2


STICK PROC FAR
PUSH BP ;SAVE CALLER'S BP
MOV BP,SP ;STACK POINTER BECOMES NEW BP
PUSH DS

; GET THE X AXIS VALUE FIRST

MOV AH,STICK_X ; MOVE IN THE X TEST BIT
CMP [BP].STIK_NO2,2 ; SEE IF WE'RE TESTING STICK #1 OR #2
JNE TEST_X
SHL AH,1 ; SHIFT BIT NUMBERS 2 LEFT FOR STICK #2
SHL AH,1
TEST_X: MOV AL,1 ; INITIALIZE OUTPUT VALUE
MOV DX,201H ; SET PORT ADDRESS
MOV BX,0 ; AND KEEPING THE RUNUP COUNT IN BX
MOV CX,BX ; LOOP 64K TIMES MAX
OUT DX,AL ; TRIGGER THE ONE-SHOTS
AGAIN_X: IN AL,DX ; READ THE ONE-SHOT BITS
TEST AL,AH ; TEST FOR A HIGH BIT 0
JE DELAY ; WE'RE DONE IF BIT 0 IS HIGH
INC BX ; OTHERWISE INCREMENT BX AND LOOP AGAIN
LOOP AGAIN_X
MOV BX,-1 ; SET X=-1 IF NO RESPONSE

; DELAY HERE TO LET THE OTHER THREE PULSES MAX OUT

DELAY: MOV CX,512
WAIT: LOOP WAIT

; NOW WE GET THE Y AXIS VALUE

MOV AH,STICK_Y ; MOVE IN THE Y TEST BIT
CMP [BP].STIK_NO2,2 ; SEE IF WE'RE TESTING STICK #1 OR #2
JNE TEST_Y
SHL AH,1 ; SHIFT BIT NUMBERS 2 LEFT FOR STICK #2
SHL AH,1

TEST_Y: MOV SI,0 ; KEEP THE RUNUP COUNT FOR Y IN SI
MOV CX,SI ; SET LOOP LIMIT TO 64K
OUT DX,AL ; FIRE THE ONE-SHOTS AGAIN
AGAIN_Y: IN AL,DX ; READ THE ONE-SHOT BITS
TEST AL,AH ; TEST FOR A HIGH BIT 1
JE DONE ; WE'RE DONE IF BIT 1 IS HIGH
INC SI ; OTHERWISE INCREMENT SI AND LOOP AGAIN
LOOP AGAIN_Y
MOV SI,-1 ; SET Y=-1 IF NO RESPONSE

; MOVE RETURN VALUES FROM REGISTERS INTO VAR PARAMETERS X & Y

DONE: LDS DI,[BP].XADDR2 ;ADDR OF X INTO DS:DI
MOV [DI],BX ;X VALUE FROM BX TO DS:DI
LDS DI,[BP].YADDR2 ;DITTO FOR Y VALUE FROM SI
MOV [DI],SI

; IT'S OVER...NOW CLEAN UP THE STACK AND LEAVE

POP DS
MOV SP,BP ; CLEAN UP STACK AND LEAVE
POP BP ; RESTORE CALLER'S BP

RET 10

STICK ENDP



CODE ENDS
END


  3 Responses to “Category : Pascal Source Code
Archive   : CMPLTPAS.ZIP
Filename : GAMER.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/