📄 sgdi.asm
字号:
.286
page 58, 132
name SGDI
title SGDI Driver for Standard Game Adapter Card
subttl This Program is Public Domain Material.
; SGDI.EXE
;
; Usage:
; SDGI
;
; This program loads a TSR which patches INT 15 so arbitrary game programs
; can read the joystick in a portable fashion.
;
;
; We need to load cseg in memory before any other segments!
cseg segment para public 'code'
cseg ends
; Initialization code, which we do not need except upon initial load,
; goes in the following segment:
Initialize segment para public 'INIT'
Initialize ends
; UCR Standard Library routines which get dumped later on.
.xlist
include stdlib.a
includelib stdlib.lib
.list
sseg segment para stack 'stack'
sseg ends
zzzzzzseg segment para public 'zzzzzzseg'
zzzzzzseg ends
CSEG segment para public 'CODE'
assume cs:cseg, ds:nothing
wp equ <word ptr>
byp equ <byte ptr>
Int15Vect dd 0
PSP dw ?
; Port addresses for a typical joystick card:
JoyPort equ 201h
JoyTrigger equ 201h
; Data structure to hold information about each pot.
; (mainly for calibration and normalization purposes).
Pot struc
PotMask db 0 ;Pot mask for hardware.
DidCal db 0 ;Is this pot calibrated?
min dw 5000 ;Minimum pot value
max dw 0 ;Max pot value
center dw 0 ;Pot value in the middle
Pot ends
; Variables for each of the pots. Must initialize the masks so they
; mask out all the bits except the incomming bit for each pot.
Pot0 Pot <1>
Pot1 Pot <2>
Pot2 Pot <4>
Pot3 Pot <8>
; The IDstring address gets passed back to the caller on a testpresence
; call. The four bytes before the IDstring must contain the serial number
; and current driver number.
SerialNumber db 0,0,0
IDNumber db 0
IDString db "Standard SGDI Driver",0
db "Public Domain Driver Written by Randall L. Hyde",0
;============================================================================
;
; ReadPots- AH contains a bit mask to determine which pots we should read.
; Bit 0 is one if we should read pot 0, bit 1 is one if we should
; read pot 1, bit 2 is one if we should read pot 2, bit 3 is one
; if we should read pot 3. All other bits will be zero.
;
; This code returns the pot values in SI, BX, BP, and DI for Pot 0, 1,
; 2, & 3.
;
ReadPots proc near
sub bp, bp
mov si, bp
mov di, bp
mov bx, bp
; Wait for any previous signals to finish up before trying to read this
; guy. It is possible that the last pot we read was very short. However,
; the trigger signal starts timers running for all four pots. This code
; terminates as soon as the current pot times out. If the user immediately
; reads another pot, it is quite possible that the new pot's timer has
; not yet expired from the previous read. The following loop makes sure we
; aren't measuring the time from the previous read.
mov dx, JoyPort
mov cx, 400h
Wait4Clean: in al, dx
and al, 0Fh
loopnz Wait4Clean
; Okay, read the pots. The following code triggers the 558 timer chip
; and then sits in a loop until all four pot bits (masked with the pot mask
; in AL) become zero. Each time through this loop that one or more of these
; bits contain zero, this loop increments the corresponding register(s).
mov dx, JoyTrigger
out dx, al ;Trigger pots
mov dx, JoyPort
mov cx, 1000h ;Don't let this go on forever.
PotReadLoop: in al, dx
and al, ah
jz PotReadDone
shr al, 1
adc si, 0 ;Increment SI if pot 0 still active.
shr al, 1
adc bx, 0 ;Increment BX if pot 1 still active.
shr al, 1
adc bp, 0 ;Increment BP if pot 2 still active.
shr al, 1
adc di, 0 ;Increment DI if pot 3 still active.
loop PotReadLoop ;Stop, eventually, if funny hardware.
and si, 0FFFh ;If we drop through to this point,
and bx, 0FFFh ; one or more pots timed out (usually
and bp, 0FFFh ; because they are not connected).
and di, 0FFFh ; The reg contains 4000h, set it to 0.
PotReadDone:
ret
ReadPots endp
;----------------------------------------------------------------------------
;
; Normalize- BX contains a pointer to a pot structure, AX contains
; a pot value. Normalize that value according to the
; calibrated pot.
;
; Note: DS must point at cseg before calling this routine.
assume ds:cseg
Normalize proc near
push cx
; Sanity check to make sure the calibration process went okay.
cmp [bx].Pot.DidCal, 0 ;Is this pot calibrated?
je BadNorm ;If not, quit.
mov dx, [bx].Pot.Center ;Do a sanity check on the
cmp dx, [bx].Pot.Min ; min, center, and max
jbe BadNorm ; values to make sure
cmp dx, [bx].Pot.Max ; min < center < max.
jae BadNorm
; Clip the value if it is out of range.
cmp ax, [bx].Pot.Min ;If the value is less than
ja MinOkay ; the minimum value, set it
mov ax, [bx].Pot.Min ; to the minimum value.
MinOkay:
cmp ax, [bx].Pot.Max ;If the value is greater than
jb MaxOkay ; the maximum value, set it
mov ax, [bx].Pot.Max ; to the maximum value.
MaxOkay:
; Scale this guy around the center:
cmp ax, [bx].Pot.Center ;See if less than or greater
jb Lower128 ; than centered value.
; Okay, current reading is greater than the centered value, scale the reading
; into the range 128..255 here:
sub ax, [bx].Pot.Center
mov dl, ah ;Multiply by 128
mov ah, al
mov dh, 0
mov al, dh
shr dl, 1
rcr ax, 1
mov cx, [bx].Pot.Max
sub cx, [bx].Pot.Center
jz BadNorm ;Prevent division by zero.
div cx ;Compute normalized value.
add ax, 128 ;Scale to range 128..255.
cmp ah, 0
je NormDone
mov ax, 0ffh ;Result must fit in 8 bits!
jmp NormDone
; If the reading is below the centered value, scale it into the range
; 0..127 here:
Lower128: sub ax, [bx].Pot.Min
mov dl, ah
mov ah, al
mov dh, 0
mov al, dh
shr dl, 1
rcr ax, 1
mov cx, [bx].Pot.Center
sub cx, [bx].Pot.Min
jz BadNorm
div cx
cmp ah, 0
je NormDone
mov ax, 0ffh
jmp NormDone
; If something went wrong, return zero as the normalized value.
BadNorm: sub ax, ax
NormDone: pop cx
ret
Normalize endp
assume ds:nothing
;============================================================================
; INT 15h handler functions.
;============================================================================
;
; Although these are defined as near procs, they are not really procedures.
; The MyInt15 code jumps to each of these with BX, a far return address, and
; the flags sitting on the stack. Each of these routines must handle the
; stack appropriately.
;
;----------------------------------------------------------------------------
; BIOS- Handles the two BIOS calls, DL=0 to read the switches, DL=1 to
; read the pots. For the BIOS routines, we'll ignore the cooley
; switch (the hat) and simply read the other four switches.
BIOS proc near
cmp dl, 1 ;See if switch or pot routine.
jb Read4Sw
je ReadBIOSPots
; If not a valid BIOS call, jump to the original INT 15 handler and
; let it take care of this call.
pop bx
jmp cs:Int15Vect ;Let someone else handle it!
; BIOS read switches function.
Read4Sw: push dx
mov dx, JoyPort
in al, dx
and al, 0F0h ;Return only switch values.
pop dx
pop bx
iret
; BIOS read pots function.
ReadBIOSPots: pop bx ;Return a value in BX!
push si
push di
push bp
mov ah, 0Fh ;Read all four pots.
call ReadPots
mov ax, si
mov cx, bp ;BX already contains pot 1 reading.
mov dx, di
pop bp
pop di
pop si
iret
BIOS endp
;----------------------------------------------------------------------------
;
; ReadPot- On entry, DL contains a pot number to read.
; Read and normalize that pot and return the result in AL.
assume ds:cseg
ReadPot proc near
;;;;;;;;;; push bx ;Already on stack.
push ds
push cx
push dx
push si
push di
push bp
mov bx, cseg
mov ds, bx
; If dl = 0, read and normalize the value for pot 0, if not, try some
; other pot.
cmp dl, 0
jne Try1
mov ah, Pot0.PotMask ;Get bit for this pot.
call ReadPots ;Read pot 0.
lea bx, Pot0 ;Pointer to pot data.
mov ax, si ;Get pot 0 reading.
call Normalize ;Normalize to 0..FFh.
jmp GotPot ;Return to caller.
; Test for DL=1 here (read and normalize pot 1).
Try1: cmp dl, 1
jne Try2
mov ah, Pot1.PotMask
call ReadPots
mov ax, bx
lea bx, Pot1
call Normalize
jmp GotPot
; Test for DL=2 here (read and normalize pot 2).
Try2: cmp dl, 2
jne Try3
mov ah, Pot2.PotMask
call ReadPots
lea bx, Pot2
mov ax, bp
call Normalize
jmp GotPot
; Test for DL=3 here (read and normalize pot 3).
Try3: cmp dl, 3
jne BadPot
mov ah, Pot3.PotMask
call ReadPots
lea bx, Pot3
mov ax, di
call Normalize
jmp GotPot
; Bad value in DL if we drop to this point. The standard game card
; only supports four pots.
BadPot: sub ax, ax ;Pot not available, return zero.
GotPot: pop bp
pop di
pop si
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -