home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Jason Aller Floppy Collection
/
91.img
/
PERI_50.ZIP
/
PERI.PGM
/
USEREXIT.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-08-20
|
25KB
|
1,079 lines
cseg segment para public 'code'
org 100h
userexit proc far
; This program is an example of a memory-resident routine that is
; used to contain user breakpoints and user exits from Periscope.
; This program is attached to an unused interrupt vector so that it
; can be called from Periscope. The allowable range of vectors is
; 60H to FFH. This routine must be loaded into memory before Periscope
; is run. When PS.COM is run, be sure to specify the '/I:nn' installa-
; tion option, where nn is the interrupt vector.
; On entry, register AH contains a function number set by Periscope. For
; the user breakpoints, (BU 1 through 8), AH will be from 1 to 8. For
; the user exits (/U nn), AH will be from 9 to FFH. Note: F0 through FF
; are reserved for use by Periscope. The reserved functions are:
; F0 -- invoked after each command is entered, so that your code can
; modify the command line as needed.
; F1 -- invoked before a short boot (QS), so that your code can perform
; any required cleanup
; F2 -- invoked before a normal boot (QB)
; F3 -- invoked before a long boot (QL)
; On entry, DS:SI points to a table containing the current program's
; register values and other information. The information available is:
;
; [SI+00H] -- AX [SI+02H] -- BX [SI+04H] -- CX
; [SI+06H] -- DX [SI+08H] -- SP [SI+0AH] -- BP
; [SI+0CH] -- SI [SI+0EH] -- DI [SI+10H] -- DS
; [SI+12H] -- ES [SI+14H] -- SS [SI+16H] -- CS
; [SI+18H] -- IP [SI+1AH] -- FLAGS
;
; [SI+1CH] -- Segment of address entered on user exit command line
; [SI+1EH] -- Offset of address entered on user exit command line
; [SI+20H] through [SI+69H] -- Current Periscope command, terminated
; with a carriage return and a nul.
; [SI+6AH] through [SI+B3H] -- Previous Periscope command, starting
; with a carriage return, and ending with a carriage return and a nul.
; This field should not be modified.
; [SI+B4H] -- Byte value of last error. Zero if no error has occurred.
; [SI+B5H] -- Byte position in command line of last error.
;
; These last six fields are used by some user service routines to pass
; information back and forth.
; On entry, ES:BX points to a user service routine in Periscope. This
; routine is accessed via a far call. Register AH is used to indicate
; the function desired. When using this routine, all registers are
; preserved. The functions available are:
;
; AH=1 -- display nul-terminated string at DS:SI. This function
; uses the standard Periscope display handler to display a string
; on the screen. The maximum length of the string is 83 characters,
; including a carriage return, line feed, and nul. The string must end
; with a nul (binary zero)!
;
; AH=2 -- get command string into [SI+20H]. This function uses the
; standard Periscope keyboard handler to get an input string. The
; maximum length of the string is 74 characters, including a carriage
; return and a nul. Note that the new string is passed back at the
; same location as when the User Exit was first activated.
; AH=3 -- search symbol table for nul-terminated string passed in
; [SI+20H]. This function returns the segment in [SI+1CH] and the
; offset in [SI+1EH]. If no symbol is found, the Carry flag is set.
; AH=4 -- search symbol table for symbol whose address is stored
; at [SI+1CH]:[SI+1EH]. The name is returned in [SI+20H]. If no
; symbol is found, the Carry flag is set.
; AH=5 -- download and execute code on a Periscope remote driver.
; DS:SI points to a string whose length (0-64) is in the first byte.
; The following bytes are the code that is to be executed on the
; remote machine.
; AH=6 -- upload string from a Periscope remote driver. ES:DI points
; to a string whose length (0-64) is returned in the first byte.
; The following bytes are the data that is passed up from the remote
; system.
; AH=7 -- read a byte from a Periscope remote driver. ES:DI points
; to the memory location to be read. The value is returned in AL.
; AH=8 -- write the byte in AL to a Periscope remote driver. ES:DI
; points to the memory location to be written.
; On return from a USER BREAKPOINT, AL indicates whether or not the
; routine got a 'hit'. If AL=1, then Periscope assumes a hit and stops.
; Any other value is assumed not to be a hit and Periscope continues
; the GT command, unless another breakpoint (e.g. BW) is taken.
; On return from a USER EXIT, AL indicates whether the exit code has
; set a command to be executed by Periscope. If AL=2, Periscope reads
; the command line passed back from the user exit. The command line
; must start with a semi-colon and end with a carriage return.
; The values of registers other than AX, BX, SI, DS and ES on entry to
; the program are undefined.
; If your code will require more than 32 words of stack space, you
; should switch to your own internal stack. Be sure that Periscope's
; original stack is in place before returning to Periscope. All other
; registers may be modified as needed.
assume cs:cseg,ds:cseg,ss:nothing,es:nothing
start: jmp transient ; go to start-up code
intno equ 60h ; use interrupt 60h
cr equ 13 ; carriage return
lf equ 10 ; line feed
even
pservice dd 0 ; periscope service routine's location
signature db 'P','S' ; signature required by PS.COM - must be just
; before interrupt entry point!
resident: ; interrupt entry point
; choose function based on value in ah
push si
mov si,offset pservice
mov cs:[si],bx ; save service routine offset
mov cs:[si+2],es ; save service routine segment
pop si
cld ; up periscope!
cmp ah,1 ; ah=1?
jz send1 ; yes - demo user breakpoint
cmp ah,2 ; ah=2?
jz send2 ; yes - test cs for range set by /u a
cmp ah,9 ; ah=9?
jz send9 ; yes - demo user exit
cmp ah,0ah ; ah=a?
jz senda ; yes - set cs range for use by 'bu 2'
cmp ah,0bh ; ah=b?
jz sendb ; yes - display BASIC style string
cmp ah,0eh ; ah=e?
jz sende ; yes - another user exit
cmp ah,52h ; ah=52h?
jz send52 ; yes - execute code on remote ps
cmp ah,53h ; ah=53h?
jz send53 ; yes - read/write memory on remote ps
cmp ah,87h ; ah=87h?
jz send87 ; yes - display 8087/80287 status
cmp ah,88h ; ah=88h?
jz send88 ; yes - display dos memory allocation
cmp ah,0f0h ; ah=f0 - ff?
jae special
exit: iret ; return to Periscope
special:jz sendf0 ; yes - process command line
cmp ah,0f1h ; ah=f1?
jz sendf1 ; yes - intercept short boot
cmp ah,0f2h ; ah=f2?
jz sendf2 ; yes - intercept normal boot
cmp ah,0f3h ; ah=f3?
jz sendf3 ; yes - intercept long boot
iret
send1: jmp func1 ; jump table - inelegant, but fast
send2: jmp func2
send9: jmp func9
senda: jmp funca
sendb: jmp funcb
sende: jmp funce
send52: jmp func52
send53: jmp func53
send87: jmp func87
send88: jmp func88
sendf0: jmp funcf0
sendf1: jmp funcf1
sendf2: jmp funcf2
sendf3: jmp funcf3
indos dd 0 ; pointer to in-dos flag
func1: ; function 1
; This is an example of a user breakpoint to check for dos availability.
; It is invoked by specifying 'BU 1' and then using 'GT'.
les di,cs:indos ; get pointer to in-dos flag
cmp byte ptr es:[di],0 ; dos avail?
jnz exit1 ; no
test word ptr [si+26],0200h ; interrupts enabled?
jz exit1 ; no
mov al,1 ; yes - it's a hit
exit1: jmp exit
lowcs dw 0 ; low value for cs test
highcs dw 0 ; high value for cs test
func2: ; function 2
; This is an example of a user *breakpoint* that checks the value of the
; CS register versus a range set by user *exit* '/u a'.
mov bx,[si+16h] ; user's cs in bx
cmp bx,cs:lowcs ; too low?
jb exit2 ; yes
cmp bx,cs:highcs ; too high?
ja exit2 ; yes
mov al,1 ; got one
exit2: jmp exit
commline db ';dd 0:0',cr ; ps command line - must start with a semi-colon
; and end with a carriage return
commlen equ 8 ; length of command line
func9: ; function 9
; This is an example of a user exit that stuffs a command into
; Periscope's command line.
mov di,si
add di,20h ; point to ps command line
push ds
pop es ; es:di point to ps command line
push cs
pop ds
mov si,offset commline ; ds:si point to new command
mov cx,commlen ; length must be <= 72 bytes!
rep movsb ; copy command
mov al,2 ; indicate that this is a command
exit9: jmp exit
funca: ; function a
; This user *exit* sets the range of the CS register for use by the
; user *breakpoint* 'bu 2'.
mov ax,[si+1ch] ; get segment (low cs)
mov cs:lowcs,ax
mov ax,[si+1eh] ; get offset (high cs)
mov cs:highcs,ax
push cs
pop ds ; ds=cs
mov ax,lowcs ; get low cs value
mov si,offset csval1
call convert ; convert hex to ascii
mov ax,highcs ; get high cs value
mov si,offset csval2
call convert ; convert hex to ascii
mov si,offset csmsg
mov ah,1 ; display message
call [pservice] ; call service routine
exita: jmp exit
convert proc near ; convert hex number in ax to ascii at [si]
push ax
xchg ah,al
call convertbyte ; convert lo byte
pop ax
; convert hi byte
convertbyte:
push bx
push cx
mov ah,0
mov bx,offset hextable
mov cl,4
shl ax,cl
shr al,cl
xlat
xchg ah,al
xlat
mov [si],ax
inc si
inc si
pop cx
pop bx
ret
convert endp
hextable db '0123456789ABCDEF' ; hex conversion table
csmsg db 'CS range is from '
csval1 db '.... to '
csval2 db '....',cr,lf,0
funcb: ; function b
; This user exit displays a BASIC string for Quick Basic.
; It is called using '/ub <name>'
mov bx,[si+1eh] ; get symbol offset
cmp bx,0 ; offset zero?
jz funcb2 ; must not be a basic variable
mov ds,[si+1ch] ; get symbol segment
mov si,bx ; ds:si point to symbol
mov cx,[si] ; get length in cx
mov si,[si+2] ; get offset in si
push cs
pop es ; es=cs
mov di,offset outline
push cx
push di
mov al,' '
mov cx,80
rep stosb ; clear outline
pop di
pop cx
jcxz funcb2 ; zero length - exit
cmp cx,80 ; 1-80?
jbe funcb1 ; yes
mov cx,80 ; limit it
funcb1: rep movsb ; copy name to outline
mov si,offset outline
funcb3: mov ah,1
push cs
pop ds ; ds=cs
call [pservice] ; display it
exitb: jmp exit
funcb2: mov si,offset nofind
jmp funcb3
nofind db 'Unknown symbol',cr,lf,0
funce: ; function e (aka funky)
; This is an example of a user exit that gets a symbol name and
; then attempts to search the symbol table. If the symbol search
; by name is successful, the symbol table is searched by address.
push cs
pop ds
mov si,offset prompt
mov ah,1 ; display message
call [pservice] ; call service routine
mov ah,2 ; get input string
call [pservice] ; call service routine
mov ah,3 ; search symbol table by name
call [pservice] ; call service routine
jnc funce1 ; found it
mov si,offset nofind1
mov ah,1 ; display message
call [pservice] ; call service routine
jmp exite ; quit
funce1: mov si,offset find1
mov ah,1 ; display message
call [pservice] ; call service routine
mov ah,4 ; search symbol table by address
call [pservice] ; call service routine
jnc funce2 ; found it
mov si,offset nofind2
jmp funce3
funce2: mov si,offset find2
funce3: mov ah,1 ; display message
call [pservice] ; call service routine
exite: jmp exit
prompt db 'Symbol name? ',0
nofind1 db 'Symbol not found by name',cr,lf,0
find1 db 'Symbol found by name',cr,lf,0
nofind2 db 'Symbol not found by address',cr,lf,0
find2 db 'Symbol found by address',cr,lf,0
func52: ; function 52
; This is an example of a user exit that downloads some code to
; a periscope remote driver and then runs that code. The routine
; then reads the results of the code that was run.
mov ax,cs
mov ds,ax
mov si,offset codesample; ds:si point to code string to be passed
mov ah,5 ; download code
call [pservice] ; call service routine
mov ax,cs
mov es,ax
mov di,offset uplen
mov ah,6 ; upload string from remote
call [pservice] ; call service routine
cmp uplen,1 ; got 1 byte?
jnz exit52 ; no - error
mov al,upstring ; use first byte only
mov si,offset modetype
call convertbyte ; convert hex to ascii
mov ah,1
mov si,offset modemsg
call [pservice] ; display result
exit52: jmp exit
codesample proc near
db offset endcode-$ ; length of code
mov al,1
stosb ; output 1 byte
mov ah,0fh
int 10h ; get video state
stosb ; return byte in al
ret ; must be a near return!
endcode equ $-1
codesample endp
uplen db 0
upstring db 64 dup(0) ; keep this after uplen
modemsg db 'The current video mode on the remote system is '
modetype db '??H.',cr,lf,0
func53: ; function 53
; This is an example of a user exit that reads memory on
; a periscope remote driver.
mov ax,cs
mov ds,ax
xor di,di
mov es,di ; point to 0:0 (int 0)
mov ah,7 ; read memory
call [pservice] ; call service routine
mov si,offset readvalue
call convertbyte ; convert hex to ascii
mov ah,1
mov si,offset readmsg
call [pservice] ; display result
exit53: jmp exit
readmsg db 'The value at 0:0 is '
readvalue db '??H.',cr,lf,0
func87: ; function 87 - display 8087/80287 status
push cs
pop ds ; ds=cs
push ds
pop es ; es=ds
call p330 ; clear output line
wait ; wait for 8087
; fstenv npdcrtl ; save ndp environment
db 0d9h,036h
dw offset ndpctrl
wait ; wait for 8087
; fldenv ndpctrl ; restore it
db 0d9h,026h
dw offset ndpctrl
call p200 ; display control info
call p210 ; display status line
call p220 ; display ip, opcode, and dp
call p230 ; display tag words
exit87: jmp exit
func88: ; function 88 - display dos memory allocation
push cs
pop ds ; ds=cs
cmp dosver,2 ; dos 2.x?
jz exit88 ; yes - exit
xor di,di
mov priorseg,di
mov pspseg,di
mov ax,dosmemseg ; get start seg for dos memory alloc blocks
mov lastseg,ax
call p110 ; get segment for dos
jc exit88 ; error
mov dx,es
inc dx
mov pspseg,dx
mov si,offset command
mov di,offset outline+6
push cs
pop es ; es=cs
mov cx,14
rep movsb ; copy command over
jmp p104 ; continue
exit88: jmp exit
p101: push cs
pop ds ; ds=cs
xor di,di
mov es,priorseg
cmp byte ptr es:[di],5ah ; end?
jz exit88 ; yes
call p110 ; get segment
jc exit88 ; error
mov dx,es
inc dx
mov pspseg,dx
mov ds,dx ; ds=prior es
mov si,2ch
lodsw ; get environment
cmp ax,0 ; nul?
jz exit88 ; yes - exit
mov ds,ax
xor si,si
p102: lodsb ; search for nul
cmp al,0
jnz p102
lodsb ; got one - look for second
cmp al,0
jnz p102
lodsw ; look for 1,0
mov cx,80 ; max length
mov di,offset outline
push cs
pop es ; es=cs
mov al,' '
push cx
rep stosb ; clear output area
pop cx
mov di,offset outline+6
p103: lodsb ; get char
cmp al,0 ; end?
jz p104 ; yes
stosb ; save char
loop p103 ; continue
p104: push cs
pop ds ; get orig ds back
mov ax,pspseg
mov si,offset outline
call convert ; convert psp
mov ah,1
mov si,offset outline
call [pservice] ; display line
jmp p101
p110 proc near
mov ax,lastseg
xor di,di ; be sure
p111: mov es,ax ; get segment
add ax,es:[di+3] ; add next segment into ax
inc ax ; plus one
mov bx,es:[di+1] ; get psp seg
mov cx,es ; get current segment
cmp byte ptr es:[di],4dh; mem alloc block?
jz p112 ; yes
cmp byte ptr es:[di],5ah ; end of chain?
jnz p113 ; no - error
p112: inc cx ; current segment plus one
cmp bx,cx ; psp seg?
jnz p111 ; no - keep on
mov lastseg,ax
mov priorseg,es
clc
ret
p113: stc
ret
p110 endp
dosver db 0
dosmemseg dw 0
lastseg dw 0
priorseg dw 0
pspseg dw 0
command db 'COMMAND.COM',cr,lf,0
funcf0: ; function f0
; This is an example of a reserved user exit. If a user exit is
; installed, function F0H is activated after each command is entered,
; but before it is processed by Periscope. At this time, the user exit
; can modify the command as desired, using the command area defined
; above. No registers need to be set -- just modify the command line
; as desired.
add si,20h ; point to ps command line
mov ax,[si] ; get first word
cmp ax,'..' ; double dot?
jnz exitf0 ; no
mov word ptr [si],'dd' ; yes - convert it to dd
exitf0: jmp exit
funcf1: ; function f1
; This is an example of a reserved user exit. If a user exit is
; installed, function F1H is activated before a short boot.
call beep ; beep once
jmp exit
funcf2: ; function f2
; This is an example of a reserved user exit. If a user exit is
; installed, function F2H is activated before a normal boot.
call beep ; beep twice
call beep
jmp exit
funcf3: ; function f3
; This is an example of a reserved user exit. If a user exit is
; installed, function F3H is activated before a long boot.
call beep ; beep three times
call beep
call beep
jmp exit
beep proc near
push ax
push bx
push cx
push es
pushf
sti
xor ax,ax
mov es,ax
mov bx,46ch ; offset of low timer word
mov al,0b6h
out 43h,al ; set timer
mov al,33h
out 42h,al
jmp $+2 ; wait
mov al,3
out 42h,al
in al,61h
mov ah,al ; save orig value
or al,3
jmp $+2 ; wait
call beepa ; sync it
out 61h,al ; speaker on
call beepa ; wait 1
mov al,33h
out 42h,al
jmp $+2
mov al,6
out 42h,al
call beepa ; wait 1
mov al,ah
out 61h,al ; back to initial value
popf
pop es
pop cx
pop bx
pop ax
ret
beepa: mov cx,es:[bx] ; get timer value
beepb: jmp $+2
cmp cx,es:[bx] ; same?
jz beepb ; yes - wait
ret
beep endp
; control word equates
nbic equ 1000h ; ic - bit 12
nbrc equ 0c00h ; rc - bits 10,11
nbpc equ 0300h ; pc - bits 8,9
nbpm equ 0020h ; pm - bit 5
nbum equ 0010h ; um - bit 4
nbom equ 0008h ; om - bit 3
nbzm equ 0004h ; zm - bit 2
nbdm equ 0002h ; dm - bit 1
nbim equ 0001h ; im - bit 0
; status word equates
nbby equ 8000h ; busy
nbc3 equ 4000h ; cond code 3
nbtop equ 3800h ; top of stack
nbc2 equ 0400h ; cond code 2
nbc1 equ 0200h ; cond code 1
nbc0 equ 0100h ; cond code 0
nbes equ 0080h ; err status
; control word text
ndpc1 db 'Ctrl: Infin=',0
ndpc2 db ' Round=',0
ndpc3 db ' Prec=',0
ndpc4 db ' Flags=',0
; status word text
ndps1 db 'Stat: Cond=',0
ndps2 db ' Stacktop=',0
; misc text
ndpip db 'IP=',0
ndpop db 'Opcode=',0
ndpdp db 'DP=',0
ndptag db 'Tag: ',0
ndpflags db 'PrecUndrOverZeroDen Inv ' ; possible flags
ndpbusy db 'Busy'
ndperr db 'Err '
ndpinf0 db 'Proj'
ndpinf1 db 'Aff '
ndprnd db 'NearDownUp Chop' ; round types
ndpprec db 'Short?????Long Temp ' ; precision types
ndptval db 'ValidZero InfinEmpty' ; tag values
; ndp save area
ndpctrl dw 0 ; save area - control word
ndpstat dw 0 ; status word
ndptagw dw 0 ; tag word
ndpip1 dw 0 ; inst ptr 1
ndpip2 dw 0 ; inst ptr 2
ndpdp1 dw 0 ; data ptr 1
ndpdp2 dw 0 ; data ptr 2
outline db 80 dup(' ') ; output work line
db cr,lf,0
p200 proc near ; display control info
mov ax,ndpctrl
mov si,offset ndpc1
call p300 ; copy control header
mov si,offset ndpinf0 ; assume projective
test ax,nbic ; proj?
jz p201 ; yes
mov si,offset ndpinf1 ; no
p201: movsw ; copy infinity type
movsw
mov si,offset ndpc2
call p300 ; copy round header
mov si,offset ndprnd ; assume near
mov bx,ax ; get word in bx
and bx,nbrc ; clear other bits
xchg bh,bl ; times four as is
add si,bx
movsw ; copy round type
movsw
mov si,offset ndpc3
call p300 ; copy precision header
mov si,offset ndpprec
mov bx,ax
and bx,nbpc
xchg bh,bl
mov cx,bx
shl bx,1 ; times 2
shl bx,1 ; times 4
add bx,cx ; times 5
add si,bx
movsw ; copy precision type
movsw
movsb
call p320 ; display flags
call p340 ; print line
ret
p200 endp
p210 proc near ; display status info
mov ax,ndpstat
mov si,offset ndps1
call p300 ; copy status header
test ax,nbc3 ; cc3 on?
call p310 ; print result
test ax,nbc2 ; cc2 on?
call p310
test ax,nbc1
call p310
test ax,nbc0
call p310
mov si,offset ndps2
call p300 ; copy stacktop header
mov bx,ax
and bx,nbtop
shr bx,1
shr bx,1
shr bx,1 ; in bh
add bh,'0' ; make ascii
mov [di],bh
inc di
inc di
inc di
test ax,nbby ; busy?
jnz p211 ; yes
add di,4 ; no
jmp short p212
p211: mov si,offset ndpbusy
movsw
movsw
p212: inc di
inc di
test ax,nbes ; error?
jnz p213 ; yes
inc di
inc di
inc di
jmp short p214
p213: mov si,offset ndperr
movsw
movsb
p214: inc di
call p320 ; display flags
call p340 ; display line
ret
p210 endp
p220 proc near ; display ip, opcode, and dp
mov si,offset ndpip
call p300 ; copy ip header
mov ax,ndpip2 ; get ip
mov cx,4
rol ax,cl ; address in low 4 bits
call p350 ; display nibble
mov ax,ndpip1 ; get lower part of ip
call p360 ; display word
mov si,offset ndpop
call p300 ; copy opcode header
mov ax,ndpip2
and ax,07ffh ; clear out ip part
or ax,0d800h ; make it an esc instruction
call p360 ; display word
mov si,offset ndpdp
call p300 ; copy dp header
mov ax,ndpdp2 ; get dp
mov cx,4
rol ax,cl ; address in low 4 bits
call p350 ; display nibble
mov ax,ndpdp1 ; get lower part of dp
call p360 ; display word
call p340 ; display line
ret
p220 endp
p230 proc near ; display tag word
mov si,offset ndptag
call p300 ; copy tag header
mov ax,ndptagw ; get tag word
mov cx,8
p231: rol ax,1
rol ax,1 ; get next tag word
push ax
and ax,3
mov bx,ax
shl ax,1
shl ax,1
add bx,ax ; times five
mov si,offset ndptval ; point to tag values
add si,bx
movsw
movsw
movsb ; copy to output
inc di
inc di ; two spaces
pop ax
loop p231
call p340 ; display line
ret
p230 endp
p300 proc near ; copy to output line
push ax
p301: lodsb ; get byte
cmp al,0 ; end?
jz p305 ; yes
stosb ; no - save it
jmp p301 ; continue
p305: pop ax
ret
p300 endp
p310 proc near ; print 0 if zr, else 1
mov bl,'0'
jz p315
mov bl,'1'
p315: mov [di],bl
inc di
ret
p310 endp
p320 proc near ; display flags
mov si,offset ndpc4
call p300 ; copy flags header
mov si,offset ndpflags
mov bx,nbpm ; start w/ pm
mov cx,6 ; six flags
p321: test ax,bx ; bit on?
jnz p322 ; yes
add si,4 ; next name
add di,4
jmp short p323
p322: movsw ; yes - copy it
movsw
p323: inc di ; skip one
shr bx,1 ; next test
loop p321
ret
p320 endp
p330 proc near ; clear output line
mov di,offset outline
push di
mov cx,80/2 ; length
mov ax,' ' ; spaces
rep stosw ; init to spaces
pop di
ret
p330 endp
p340 proc near ; print output line
mov ah,1 ; use periscope display
mov si,offset outline ; ds:si point to string
call [pservice] ; call periscope service routine
call p330
ret
p340 endp
p350 proc near ; display nibble
push ax
and ax,0fh
cmp ax,9 ; 0 to 9?
ja p351 ; no - a to f
add ax,'0' ; convert to ascii
jmp short p352
p351: add ax,55 ; a - f
p352: stosb ; save byte
pop ax
ret
p350 endp
p360 proc near ; display word
mov bx,4 ; counter
p361: rol ax,cl ; move to low nibble
call p350 ; display it
dec bx
jnz p361 ; not done
inc di
inc di ; two spaces
ret
p360 endp
transient: ; end of resident code and
; start of transient code
cld ; up periscope!
; init variables for function 88
mov ah,30h
int 21h ; get DOS version
mov dosver,al
push es
mov ah,52h
mov bx,cs
int 21h ; get dos memory block pointer
mov ax,es:[bx-2]
mov dosmemseg,ax
pop es
mov ah,34h ; set in-dos pointer
int 21h
mov si,offset indos
mov [si],bx ; save offset
mov [si+2],es ; and segment for user breakpoint 1
xor ax,ax
mov es,ax
mov di,intno ; get int number
shl di,1
shl di,1 ; times 4
cli ; no interrupts
mov ax,offset resident ; point interrupt to resident code
stosw ; set offset
mov ax,ds
stosw ; and segment
sti ; interrupts back on
mov dx,offset transient
int 27h ; stay resident
userexit endp
cseg ends
end userexit