home *** CD-ROM | disk | FTP | other *** search
/ Jason Aller Floppy Collection / 91.img / PERI_50.ZIP / PERI.PGM / USEREXIT.ASM < prev    next >
Assembly Source File  |  1990-08-20  |  25KB  |  1,079 lines

  1. cseg    segment para public 'code'
  2. org    100h
  3. userexit proc far
  4.  
  5.     ; This program is an example of a memory-resident routine that is
  6.     ; used to contain user breakpoints and user exits from Periscope.
  7.     ; This program is attached to an unused interrupt vector so that it
  8.     ; can be called from Periscope. The allowable range of vectors is
  9.     ; 60H to FFH. This routine must be loaded into memory before Periscope
  10.     ; is run. When PS.COM is run, be sure to specify the '/I:nn' installa-
  11.     ; tion option, where nn is the interrupt vector.
  12.  
  13.     ; On entry, register AH contains a function number set by Periscope. For
  14.     ; the user breakpoints, (BU 1 through 8), AH will be from 1 to 8. For
  15.     ; the user exits (/U nn), AH will be from 9 to FFH. Note: F0 through FF
  16.     ; are reserved for use by Periscope. The reserved functions are:
  17.     ; F0 -- invoked after each command is entered, so that your code can
  18.     ;   modify the command line as needed.
  19.     ; F1 -- invoked before a short boot (QS), so that your code can perform
  20.     ;   any required cleanup
  21.     ; F2 -- invoked before a normal boot (QB)
  22.     ; F3 -- invoked before a long boot (QL)
  23.  
  24.     ; On entry, DS:SI points to a table containing the current program's
  25.     ; register values and other information. The information available is:
  26.     ;
  27.     ; [SI+00H] -- AX    [SI+02H] -- BX        [SI+04H] -- CX
  28.     ; [SI+06H] -- DX    [SI+08H] -- SP        [SI+0AH] -- BP
  29.     ; [SI+0CH] -- SI    [SI+0EH] -- DI        [SI+10H] -- DS
  30.     ; [SI+12H] -- ES    [SI+14H] -- SS        [SI+16H] -- CS
  31.     ; [SI+18H] -- IP    [SI+1AH] -- FLAGS
  32.     ;
  33.     ; [SI+1CH] -- Segment of address entered on user exit command line
  34.     ; [SI+1EH] -- Offset of address entered on user exit command line
  35.     ; [SI+20H] through [SI+69H] -- Current Periscope command, terminated
  36.     ;   with a carriage return and a nul.
  37.     ; [SI+6AH] through [SI+B3H] -- Previous Periscope command, starting
  38.     ;   with a carriage return, and ending with a carriage return and a nul.
  39.     ;   This field should not be modified.
  40.     ; [SI+B4H] -- Byte value of last error. Zero if no error has occurred.
  41.     ; [SI+B5H] -- Byte position in command line of last error.
  42.     ;
  43.     ; These last six fields are used by some user service routines to pass
  44.     ; information back and forth.
  45.  
  46.     ; On entry, ES:BX points to a user service routine in Periscope. This
  47.     ; routine is accessed via a far call. Register AH is used to indicate
  48.     ; the function desired. When using this routine, all registers are
  49.     ; preserved. The functions available are:
  50.     ;
  51.     ; AH=1 -- display nul-terminated string at DS:SI. This function
  52.     ; uses the standard Periscope display handler to display a string
  53.     ; on the screen. The maximum length of the string is 83 characters,
  54.     ; including a carriage return, line feed, and nul. The string must end
  55.     ; with a nul (binary zero)!
  56.     ;
  57.     ; AH=2 -- get command string into [SI+20H]. This function uses the
  58.     ; standard Periscope keyboard handler to get an input string. The
  59.     ; maximum length of the string is 74 characters, including a carriage
  60.     ; return and a nul. Note that the new string is passed back at the
  61.     ; same location as when the User Exit was first activated.
  62.  
  63.     ; AH=3 -- search symbol table for nul-terminated string passed in
  64.     ; [SI+20H]. This function returns the segment in [SI+1CH] and the
  65.     ; offset in [SI+1EH]. If no symbol is found, the Carry flag is set.
  66.  
  67.     ; AH=4 -- search symbol table for symbol whose address is stored
  68.     ; at [SI+1CH]:[SI+1EH]. The name is returned in [SI+20H]. If no
  69.     ; symbol is found, the Carry flag is set.
  70.  
  71.     ; AH=5 -- download and execute code on a Periscope remote driver.
  72.     ; DS:SI points to a string whose length (0-64) is in the first byte.
  73.     ; The following bytes are the code that is to be executed on the
  74.     ; remote machine.
  75.  
  76.     ; AH=6 -- upload string from a Periscope remote driver. ES:DI points
  77.     ; to a string whose length (0-64) is returned in the first byte.
  78.     ; The following bytes are the data that is passed up from the remote
  79.     ; system.
  80.  
  81.     ; AH=7 -- read a byte from a Periscope remote driver. ES:DI points
  82.     ; to the memory location to be read. The value is returned in AL.
  83.  
  84.     ; AH=8 -- write the byte in AL to a Periscope remote driver. ES:DI
  85.     ; points to the memory location to be written.
  86.  
  87.     ; On return from a USER BREAKPOINT, AL indicates whether or not the
  88.     ; routine got a 'hit'. If AL=1, then Periscope assumes a hit and stops.
  89.     ; Any other value is assumed not to be a hit and Periscope continues
  90.     ; the GT command, unless another breakpoint (e.g. BW) is taken.
  91.  
  92.     ; On return from a USER EXIT, AL indicates whether the exit code has
  93.     ; set a command to be executed by Periscope. If AL=2, Periscope reads
  94.     ; the command line passed back from the user exit. The command line
  95.     ; must start with a semi-colon and end with a carriage return.
  96.  
  97.     ; The values of registers other than AX, BX, SI, DS and ES on entry to
  98.     ; the program are undefined.
  99.  
  100.     ; If your code will require more than 32 words of stack space, you
  101.     ; should switch to your own internal stack. Be sure that Periscope's
  102.     ; original stack is in place before returning to Periscope. All other
  103.     ; registers may be modified as needed.
  104.  
  105.     assume cs:cseg,ds:cseg,ss:nothing,es:nothing
  106.  
  107. start:    jmp transient        ; go to start-up code
  108.  
  109. intno    equ 60h         ; use interrupt 60h
  110. cr    equ 13            ; carriage return
  111. lf    equ 10            ; line feed
  112.  
  113. even
  114. pservice dd 0            ; periscope service routine's location
  115.  
  116. signature db 'P','S'            ; signature required by PS.COM - must be just
  117.                 ; before interrupt entry point!
  118.  
  119. resident:            ; interrupt entry point
  120.                 ; choose function based on value in ah
  121.     push si
  122.     mov si,offset pservice
  123.     mov cs:[si],bx        ; save service routine offset
  124.     mov cs:[si+2],es    ; save service routine segment
  125.     pop si
  126.  
  127.     cld            ; up periscope!
  128.  
  129.     cmp ah,1        ; ah=1?
  130.     jz send1        ; yes - demo user breakpoint
  131.  
  132.     cmp ah,2        ; ah=2?
  133.     jz send2        ; yes - test cs for range set by /u a
  134.  
  135.     cmp ah,9        ; ah=9?
  136.     jz send9        ; yes - demo user exit
  137.  
  138.     cmp ah,0ah        ; ah=a?
  139.     jz senda        ; yes - set cs range for use by 'bu 2'
  140.  
  141.     cmp ah,0bh        ; ah=b?
  142.     jz sendb        ; yes - display BASIC style string
  143.  
  144.     cmp ah,0eh        ; ah=e?
  145.     jz sende        ; yes - another user exit
  146.  
  147.     cmp ah,52h        ; ah=52h?
  148.     jz send52        ; yes - execute code on remote ps
  149.  
  150.     cmp ah,53h        ; ah=53h?
  151.     jz send53        ; yes - read/write memory on remote ps
  152.  
  153.     cmp ah,87h        ; ah=87h?
  154.     jz send87        ; yes - display 8087/80287 status
  155.  
  156.     cmp ah,88h        ; ah=88h?
  157.     jz send88        ; yes - display dos memory allocation
  158.  
  159.     cmp ah,0f0h        ; ah=f0 - ff?
  160.     jae special
  161.  
  162. exit:    iret            ; return to Periscope
  163.  
  164. special:jz sendf0        ; yes - process command line
  165.  
  166.     cmp ah,0f1h        ; ah=f1?
  167.     jz sendf1        ; yes - intercept short boot
  168.  
  169.     cmp ah,0f2h        ; ah=f2?
  170.     jz sendf2        ; yes - intercept normal boot
  171.  
  172.     cmp ah,0f3h        ; ah=f3?
  173.     jz sendf3        ; yes - intercept long boot
  174.  
  175.     iret
  176.  
  177. send1:    jmp func1        ; jump table - inelegant, but fast
  178. send2:    jmp func2
  179. send9:    jmp func9
  180. senda:    jmp funca
  181. sendb:    jmp funcb
  182. sende:    jmp funce
  183. send52: jmp func52
  184. send53: jmp func53
  185. send87: jmp func87
  186. send88: jmp func88
  187. sendf0: jmp funcf0
  188. sendf1: jmp funcf1
  189. sendf2: jmp funcf2
  190. sendf3: jmp funcf3
  191.  
  192.  
  193. indos    dd 0            ; pointer to in-dos flag
  194.  
  195. func1:                ; function 1
  196.     ; This is an example of a user breakpoint to check for dos availability.
  197.     ; It is invoked by specifying 'BU 1' and then using 'GT'.
  198.  
  199.     les di,cs:indos     ; get pointer to in-dos flag
  200.     cmp byte ptr es:[di],0    ; dos avail?
  201.     jnz exit1        ; no
  202.  
  203.     test word ptr [si+26],0200h ; interrupts enabled?
  204.     jz exit1        ; no
  205.  
  206.     mov al,1        ; yes - it's a hit
  207.  
  208. exit1:    jmp exit
  209.  
  210. lowcs    dw 0            ; low value for cs test
  211. highcs    dw 0            ; high value for cs test
  212.  
  213. func2:                ; function 2
  214.     ; This is an example of a user *breakpoint* that checks the value of the
  215.     ; CS register versus a range set by user *exit* '/u a'.
  216.  
  217.     mov bx,[si+16h]     ; user's cs in bx
  218.     cmp bx,cs:lowcs     ; too low?
  219.     jb exit2        ; yes
  220.  
  221.     cmp bx,cs:highcs    ; too high?
  222.     ja exit2        ; yes
  223.  
  224.     mov al,1        ; got one
  225.  
  226. exit2:    jmp exit
  227.  
  228. commline  db ';dd 0:0',cr       ; ps command line - must start with a semi-colon
  229.                 ; and end with a carriage return
  230.  
  231. commlen equ 8            ; length of command line
  232.  
  233. func9:                ; function 9
  234.     ; This is an example of a user exit that stuffs a command into
  235.     ; Periscope's command line.
  236.  
  237.     mov di,si
  238.     add di,20h        ; point to ps command line
  239.     push ds
  240.     pop es            ; es:di point to ps command line
  241.  
  242.     push cs
  243.     pop ds
  244.     mov si,offset commline    ; ds:si point to new command
  245.  
  246.     mov cx,commlen        ; length must be <= 72 bytes!
  247.     rep movsb        ; copy command
  248.  
  249.     mov al,2        ; indicate that this is a command
  250.  
  251. exit9:    jmp exit
  252.  
  253. funca:                ; function a
  254.     ; This user *exit* sets the range of the CS register for use by the
  255.     ; user *breakpoint* 'bu 2'.
  256.  
  257.     mov ax,[si+1ch]     ; get segment (low cs)
  258.     mov cs:lowcs,ax
  259.     mov ax,[si+1eh]     ; get offset (high cs)
  260.     mov cs:highcs,ax
  261.  
  262.     push cs
  263.     pop ds            ; ds=cs
  264.  
  265.     mov ax,lowcs        ; get low cs value
  266.     mov si,offset csval1
  267.     call convert        ; convert hex to ascii
  268.  
  269.     mov ax,highcs        ; get high cs value
  270.     mov si,offset csval2
  271.     call convert        ; convert hex to ascii
  272.  
  273.     mov si,offset csmsg
  274.     mov ah,1        ; display message
  275.     call [pservice]     ; call service routine
  276.  
  277. exita:    jmp exit
  278.  
  279. convert proc near        ; convert hex number in ax to ascii at [si]
  280.     push ax
  281.     xchg ah,al
  282.     call convertbyte    ; convert lo byte
  283.     pop ax
  284.                 ; convert hi byte
  285. convertbyte:
  286.     push bx
  287.     push cx
  288.     mov ah,0
  289.     mov bx,offset hextable
  290.     mov cl,4
  291.     shl ax,cl
  292.     shr al,cl
  293.     xlat
  294.     xchg ah,al
  295.     xlat
  296.     mov [si],ax
  297.     inc si
  298.     inc si
  299.     pop cx
  300.     pop bx
  301.     ret
  302. convert endp
  303.  
  304. hextable db '0123456789ABCDEF'  ; hex conversion table
  305. csmsg    db 'CS range is from '
  306. csval1    db '.... to '
  307. csval2    db '....',cr,lf,0
  308.  
  309. funcb:                ; function b
  310.     ; This user exit displays a BASIC string for Quick Basic.
  311.     ; It is called using '/ub <name>'
  312.  
  313.     mov bx,[si+1eh]     ; get symbol offset
  314.     cmp bx,0        ; offset zero?
  315.     jz funcb2        ; must not be a basic variable
  316.  
  317.     mov ds,[si+1ch]     ; get symbol segment
  318.     mov si,bx        ; ds:si point to symbol
  319.     mov cx,[si]        ; get length in cx
  320.     mov si,[si+2]        ; get offset in si
  321.  
  322.     push cs
  323.     pop es            ; es=cs
  324.     mov di,offset outline
  325.  
  326.     push cx
  327.     push di
  328.     mov al,' '
  329.     mov cx,80
  330.     rep stosb        ; clear outline
  331.     pop di
  332.     pop cx
  333.  
  334.     jcxz funcb2        ; zero length - exit
  335.     cmp cx,80        ; 1-80?
  336.     jbe funcb1        ; yes
  337.  
  338.     mov cx,80        ; limit it
  339.  
  340. funcb1: rep movsb        ; copy name to outline
  341.  
  342.     mov si,offset outline
  343.  
  344. funcb3: mov ah,1
  345.     push cs
  346.     pop ds            ; ds=cs
  347.     call [pservice]     ; display it
  348.  
  349. exitb:    jmp exit
  350.  
  351. funcb2: mov si,offset nofind
  352.     jmp funcb3
  353.  
  354. nofind db 'Unknown symbol',cr,lf,0
  355.  
  356. funce:                ; function e (aka funky)
  357.     ; This is an example of a user exit that gets a symbol name and
  358.     ; then attempts to search the symbol table. If the symbol search
  359.     ; by name is successful, the symbol table is searched by address.
  360.  
  361.     push cs
  362.     pop ds
  363.  
  364.     mov si,offset prompt
  365.     mov ah,1        ; display message
  366.     call [pservice]     ; call service routine
  367.  
  368.     mov ah,2        ; get input string
  369.     call [pservice]     ; call service routine
  370.  
  371.     mov ah,3        ; search symbol table by name
  372.     call [pservice]     ; call service routine
  373.     jnc funce1        ; found it
  374.  
  375.     mov si,offset nofind1
  376.     mov ah,1        ; display message
  377.     call [pservice]     ; call service routine
  378.     jmp exite        ; quit
  379.  
  380. funce1: mov si,offset find1
  381.     mov ah,1        ; display message
  382.     call [pservice]     ; call service routine
  383.  
  384.     mov ah,4        ; search symbol table by address
  385.     call [pservice]     ; call service routine
  386.     jnc funce2        ; found it
  387.  
  388.     mov si,offset nofind2
  389.     jmp funce3
  390.  
  391. funce2: mov si,offset find2
  392.  
  393. funce3: mov ah,1        ; display message
  394.     call [pservice]     ; call service routine
  395.  
  396. exite:    jmp exit
  397.  
  398. prompt    db 'Symbol name? ',0
  399. nofind1 db 'Symbol not found by name',cr,lf,0
  400. find1    db 'Symbol found by name',cr,lf,0
  401. nofind2 db 'Symbol not found by address',cr,lf,0
  402. find2    db 'Symbol found by address',cr,lf,0
  403.  
  404. func52:             ; function 52
  405.     ; This is an example of a user exit that downloads some code to
  406.     ; a periscope remote driver and then runs that code. The routine
  407.     ; then reads the results of the code that was run.
  408.  
  409.     mov ax,cs
  410.     mov ds,ax
  411.     mov si,offset codesample; ds:si point to code string to be passed
  412.  
  413.     mov ah,5        ; download code
  414.     call [pservice]     ; call service routine
  415.  
  416.     mov ax,cs
  417.     mov es,ax
  418.     mov di,offset uplen
  419.  
  420.     mov ah,6        ; upload string from remote
  421.     call [pservice]     ; call service routine
  422.     cmp uplen,1        ; got 1 byte?
  423.     jnz exit52        ; no - error
  424.  
  425.     mov al,upstring     ; use first byte only
  426.     mov si,offset modetype
  427.     call convertbyte    ; convert hex to ascii
  428.  
  429.     mov ah,1
  430.     mov si,offset modemsg
  431.     call [pservice]     ; display result
  432.  
  433. exit52: jmp exit
  434.  
  435. codesample proc near
  436.     db offset endcode-$    ; length of code
  437.     mov al,1
  438.     stosb            ; output 1 byte
  439.     mov ah,0fh
  440.     int 10h         ; get video state
  441.     stosb            ; return byte in al
  442.     ret            ; must be a near return!
  443. endcode equ $-1
  444. codesample endp
  445.  
  446. uplen    db 0
  447. upstring db 64 dup(0)        ; keep this after uplen
  448.  
  449. modemsg db 'The current video mode on the remote system is '
  450. modetype db '??H.',cr,lf,0
  451.  
  452. func53:             ; function 53
  453.     ; This is an example of a user exit that reads memory on
  454.     ; a periscope remote driver.
  455.  
  456.     mov ax,cs
  457.     mov ds,ax
  458.  
  459.     xor di,di
  460.     mov es,di        ; point to 0:0 (int 0)
  461.  
  462.     mov ah,7        ; read memory
  463.     call [pservice]     ; call service routine
  464.  
  465.     mov si,offset readvalue
  466.     call convertbyte    ; convert hex to ascii
  467.  
  468.     mov ah,1
  469.     mov si,offset readmsg
  470.     call [pservice]     ; display result
  471.  
  472. exit53: jmp exit
  473.  
  474. readmsg db 'The value at 0:0 is '
  475. readvalue db '??H.',cr,lf,0
  476.  
  477. func87:             ; function 87 - display 8087/80287 status
  478.     push cs
  479.     pop ds            ; ds=cs
  480.  
  481.     push ds
  482.     pop es            ; es=ds
  483.     call p330        ; clear output line
  484.  
  485.     wait            ; wait for 8087
  486. ;    fstenv npdcrtl        ; save ndp environment
  487.     db 0d9h,036h
  488.     dw offset ndpctrl
  489.  
  490.     wait            ; wait for 8087
  491. ;    fldenv ndpctrl        ; restore it
  492.     db 0d9h,026h
  493.     dw offset ndpctrl
  494.  
  495.     call p200        ; display control info
  496.     call p210        ; display status line
  497.     call p220        ; display ip, opcode, and dp
  498.     call p230        ; display tag words
  499.  
  500. exit87: jmp exit
  501.  
  502. func88:             ; function 88 - display dos memory allocation
  503.  
  504.     push cs
  505.     pop ds            ; ds=cs
  506.     cmp dosver,2        ; dos 2.x?
  507.     jz exit88        ; yes - exit
  508.  
  509.     xor di,di
  510.     mov priorseg,di
  511.     mov pspseg,di
  512.     mov ax,dosmemseg    ; get start seg for dos memory alloc blocks
  513.     mov lastseg,ax
  514.     call p110        ; get segment for dos
  515.     jc exit88        ; error
  516.  
  517.     mov dx,es
  518.     inc dx
  519.     mov pspseg,dx
  520.     mov si,offset command
  521.     mov di,offset outline+6
  522.     push cs
  523.     pop es            ; es=cs
  524.     mov cx,14
  525.     rep movsb        ; copy command over
  526.     jmp p104        ; continue
  527.  
  528. exit88: jmp exit
  529.  
  530. p101:    push cs
  531.     pop ds            ; ds=cs
  532.     xor di,di
  533.     mov es,priorseg
  534.     cmp byte ptr es:[di],5ah    ; end?
  535.     jz exit88        ; yes
  536.  
  537.     call p110        ; get segment
  538.     jc exit88        ; error
  539.  
  540.     mov dx,es
  541.     inc dx
  542.     mov pspseg,dx
  543.     mov ds,dx        ; ds=prior es
  544.     mov si,2ch
  545.     lodsw            ; get environment
  546.     cmp ax,0        ; nul?
  547.     jz exit88        ; yes - exit
  548.  
  549.     mov ds,ax
  550.     xor si,si
  551.  
  552. p102:    lodsb            ; search for nul
  553.     cmp al,0
  554.     jnz p102
  555.  
  556.     lodsb            ; got one - look for second
  557.     cmp al,0
  558.     jnz p102
  559.  
  560.     lodsw            ; look for 1,0
  561.  
  562.     mov cx,80        ; max length
  563.     mov di,offset outline
  564.     push cs
  565.     pop es            ; es=cs
  566.  
  567.     mov al,' '
  568.     push cx
  569.     rep stosb        ; clear output area
  570.     pop cx
  571.     mov di,offset outline+6
  572.  
  573. p103:    lodsb            ; get char
  574.     cmp al,0        ; end?
  575.     jz p104         ; yes
  576.  
  577.     stosb            ; save char
  578.     loop p103        ; continue
  579.  
  580. p104:    push cs
  581.     pop ds            ; get orig ds back
  582.  
  583.     mov ax,pspseg
  584.     mov si,offset outline
  585.     call convert        ; convert psp
  586.  
  587.     mov ah,1
  588.     mov si,offset outline
  589.     call [pservice]     ; display line
  590.     jmp p101
  591.  
  592. p110    proc near
  593.     mov ax,lastseg
  594.     xor di,di        ; be sure
  595.  
  596. p111:    mov es,ax        ; get segment
  597.     add ax,es:[di+3]    ; add next segment into ax
  598.     inc ax            ; plus one
  599.     mov bx,es:[di+1]    ; get psp seg
  600.     mov cx,es        ; get current segment
  601.     cmp byte ptr es:[di],4dh; mem alloc block?
  602.     jz p112         ; yes
  603.  
  604.     cmp byte ptr es:[di],5ah ; end of chain?
  605.     jnz p113        ; no - error
  606.  
  607. p112:    inc cx            ; current segment plus one
  608.     cmp bx,cx        ; psp seg?
  609.     jnz p111        ; no - keep on
  610.  
  611.     mov lastseg,ax
  612.     mov priorseg,es
  613.     clc
  614.     ret
  615.  
  616. p113:    stc
  617.     ret
  618. p110    endp
  619.  
  620. dosver    db 0
  621. dosmemseg dw 0
  622. lastseg dw 0
  623. priorseg dw 0
  624. pspseg    dw 0
  625. command db 'COMMAND.COM',cr,lf,0
  626.  
  627. funcf0:             ; function f0
  628.     ; This is an example of a reserved user exit. If a user exit is
  629.     ; installed, function F0H is activated after each command is entered,
  630.     ; but before it is processed by Periscope. At this time, the user exit
  631.     ; can modify the command as desired, using the command area defined
  632.     ; above. No registers need to be set -- just modify the command line
  633.     ; as desired.
  634.  
  635.     add si,20h        ; point to ps command line
  636.     mov ax,[si]        ; get first word
  637.     cmp ax,'..'             ; double dot?
  638.     jnz exitf0        ; no
  639.  
  640.     mov word ptr [si],'dd'  ; yes - convert it to dd
  641.  
  642. exitf0: jmp exit
  643.  
  644. funcf1:             ; function f1
  645.     ; This is an example of a reserved user exit. If a user exit is
  646.     ; installed, function F1H is activated before a short boot.
  647.  
  648.     call beep        ; beep once
  649.     jmp exit
  650.  
  651. funcf2:             ; function f2
  652.     ; This is an example of a reserved user exit. If a user exit is
  653.     ; installed, function F2H is activated before a normal boot.
  654.  
  655.     call beep        ; beep twice
  656.     call beep
  657.     jmp exit
  658.  
  659. funcf3:             ; function f3
  660.     ; This is an example of a reserved user exit. If a user exit is
  661.     ; installed, function F3H is activated before a long boot.
  662.  
  663.     call beep        ; beep three times
  664.     call beep
  665.     call beep
  666.     jmp exit
  667.  
  668. beep    proc near
  669.     push ax
  670.     push bx
  671.     push cx
  672.     push es
  673.     pushf
  674.     sti
  675.  
  676.     xor ax,ax
  677.     mov es,ax
  678.     mov bx,46ch        ; offset of low timer word
  679.  
  680.     mov al,0b6h
  681.     out 43h,al        ; set timer
  682.     mov al,33h
  683.     out 42h,al
  684.     jmp $+2         ; wait
  685.  
  686.     mov al,3
  687.     out 42h,al
  688.     in al,61h
  689.     mov ah,al        ; save orig value
  690.     or al,3
  691.     jmp $+2         ; wait
  692.  
  693.     call beepa        ; sync it
  694.  
  695.     out 61h,al        ; speaker on
  696.     call beepa        ; wait 1
  697.  
  698.     mov al,33h
  699.     out 42h,al
  700.     jmp $+2
  701.  
  702.     mov al,6
  703.     out 42h,al
  704.     call beepa        ; wait 1
  705.  
  706.     mov al,ah
  707.     out 61h,al        ; back to initial value
  708.  
  709.     popf
  710.     pop es
  711.     pop cx
  712.     pop bx
  713.     pop ax
  714.     ret
  715.  
  716. beepa:    mov cx,es:[bx]        ; get timer value
  717.  
  718. beepb:    jmp $+2
  719.     cmp cx,es:[bx]        ; same?
  720.     jz beepb        ; yes - wait
  721.  
  722.     ret
  723. beep    endp
  724.  
  725.     ; control word equates
  726. nbic    equ 1000h        ; ic - bit 12
  727. nbrc    equ 0c00h        ; rc - bits 10,11
  728. nbpc    equ 0300h        ; pc - bits 8,9
  729. nbpm    equ 0020h        ; pm - bit 5
  730. nbum    equ 0010h        ; um - bit 4
  731. nbom    equ 0008h        ; om - bit 3
  732. nbzm    equ 0004h        ; zm - bit 2
  733. nbdm    equ 0002h        ; dm - bit 1
  734. nbim    equ 0001h        ; im - bit 0
  735.  
  736.     ; status word equates
  737. nbby    equ 8000h        ; busy
  738. nbc3    equ 4000h        ; cond code 3
  739. nbtop    equ 3800h        ; top of stack
  740. nbc2    equ 0400h        ; cond code 2
  741. nbc1    equ 0200h        ; cond code 1
  742. nbc0    equ 0100h        ; cond code 0
  743. nbes    equ 0080h        ; err status
  744.  
  745.     ; control word text
  746. ndpc1    db 'Ctrl: Infin=',0
  747. ndpc2    db '  Round=',0
  748. ndpc3    db '  Prec=',0
  749. ndpc4    db '  Flags=',0
  750.  
  751.     ; status word text
  752. ndps1    db 'Stat: Cond=',0
  753. ndps2    db '   Stacktop=',0
  754.  
  755.     ; misc text
  756. ndpip    db 'IP=',0
  757. ndpop    db 'Opcode=',0
  758. ndpdp    db 'DP=',0
  759. ndptag    db 'Tag: ',0
  760. ndpflags db 'PrecUndrOverZeroDen Inv ' ; possible flags
  761. ndpbusy db 'Busy'
  762. ndperr    db 'Err '
  763. ndpinf0 db 'Proj'
  764. ndpinf1 db 'Aff '
  765. ndprnd    db 'NearDownUp  Chop'   ; round types
  766. ndpprec db 'Short?????Long Temp ' ; precision types
  767. ndptval db 'ValidZero InfinEmpty' ; tag values
  768.  
  769.     ; ndp save area
  770. ndpctrl dw 0            ; save area - control word
  771. ndpstat dw 0            ; status word
  772. ndptagw dw 0            ; tag word
  773. ndpip1    dw 0            ; inst ptr 1
  774. ndpip2    dw 0            ; inst ptr 2
  775. ndpdp1    dw 0            ; data ptr 1
  776. ndpdp2    dw 0            ; data ptr 2
  777.  
  778. outline db 80 dup(' ')          ; output work line
  779.     db cr,lf,0
  780.  
  781. p200    proc near        ; display control info
  782.     mov ax,ndpctrl
  783.     mov si,offset ndpc1
  784.     call p300        ; copy control header
  785.     mov si,offset ndpinf0    ; assume projective
  786.     test ax,nbic        ; proj?
  787.     jz p201         ; yes
  788.  
  789.     mov si,offset ndpinf1    ; no
  790.  
  791. p201:    movsw            ; copy infinity type
  792.     movsw
  793.  
  794.     mov si,offset ndpc2
  795.     call p300        ; copy round header
  796.     mov si,offset ndprnd    ; assume near
  797.  
  798.     mov bx,ax        ; get word in bx
  799.     and bx,nbrc        ; clear other bits
  800.     xchg bh,bl        ; times four as is
  801.     add si,bx
  802.     movsw            ; copy round type
  803.     movsw
  804.  
  805.     mov si,offset ndpc3
  806.     call p300        ; copy precision header
  807.     mov si,offset ndpprec
  808.     mov bx,ax
  809.     and bx,nbpc
  810.     xchg bh,bl
  811.     mov cx,bx
  812.     shl bx,1        ; times 2
  813.     shl bx,1        ; times 4
  814.     add bx,cx        ; times 5
  815.     add si,bx
  816.     movsw            ; copy precision type
  817.     movsw
  818.     movsb
  819.  
  820.     call p320        ; display flags
  821.     call p340        ; print line
  822.     ret
  823. p200    endp
  824.  
  825. p210    proc near        ; display status info
  826.     mov ax,ndpstat
  827.     mov si,offset ndps1
  828.     call p300        ; copy status header
  829.     test ax,nbc3        ; cc3 on?
  830.     call p310        ; print result
  831.     test ax,nbc2        ; cc2 on?
  832.     call p310
  833.     test ax,nbc1
  834.     call p310
  835.     test ax,nbc0
  836.     call p310
  837.  
  838.     mov si,offset ndps2
  839.     call p300        ; copy stacktop header
  840.     mov bx,ax
  841.     and bx,nbtop
  842.     shr bx,1
  843.     shr bx,1
  844.     shr bx,1        ; in bh
  845.     add bh,'0'              ; make ascii
  846.     mov [di],bh
  847.     inc di
  848.     inc di
  849.     inc di
  850.  
  851.     test ax,nbby        ; busy?
  852.     jnz p211        ; yes
  853.  
  854.     add di,4        ; no
  855.     jmp short p212
  856.  
  857. p211:    mov si,offset ndpbusy
  858.     movsw
  859.     movsw
  860.  
  861. p212:    inc di
  862.     inc di
  863.  
  864.     test ax,nbes        ; error?
  865.     jnz p213        ; yes
  866.  
  867.     inc di
  868.     inc di
  869.     inc di
  870.     jmp short p214
  871.  
  872. p213:    mov si,offset ndperr
  873.     movsw
  874.     movsb
  875.  
  876. p214:    inc di
  877.     call p320        ; display flags
  878.     call p340        ; display line
  879.     ret
  880. p210    endp
  881.  
  882. p220    proc near        ; display ip, opcode, and dp
  883.     mov si,offset ndpip
  884.     call p300        ; copy ip header
  885.     mov ax,ndpip2        ; get ip
  886.     mov cx,4
  887.     rol ax,cl        ; address in low 4 bits
  888.     call p350        ; display nibble
  889.     mov ax,ndpip1        ; get lower part of ip
  890.     call p360        ; display word
  891.  
  892.     mov si,offset ndpop
  893.     call p300        ; copy opcode header
  894.     mov ax,ndpip2
  895.     and ax,07ffh        ; clear out ip part
  896.     or ax,0d800h        ; make it an esc instruction
  897.     call p360        ; display word
  898.  
  899.     mov si,offset ndpdp
  900.     call p300        ; copy dp header
  901.     mov ax,ndpdp2        ; get dp
  902.     mov cx,4
  903.     rol ax,cl        ; address in low 4 bits
  904.     call p350        ; display nibble
  905.     mov ax,ndpdp1        ; get lower part of dp
  906.     call p360        ; display word
  907.  
  908.     call p340        ; display line
  909.     ret
  910. p220    endp
  911.  
  912. p230    proc near        ; display tag word
  913.     mov si,offset ndptag
  914.     call p300        ; copy tag header
  915.     mov ax,ndptagw        ; get tag word
  916.     mov cx,8
  917.  
  918. p231:    rol ax,1
  919.     rol ax,1        ; get next tag word
  920.     push ax
  921.     and ax,3
  922.     mov bx,ax
  923.     shl ax,1
  924.     shl ax,1
  925.     add bx,ax        ; times five
  926.     mov si,offset ndptval    ; point to tag values
  927.     add si,bx
  928.     movsw
  929.     movsw
  930.     movsb            ; copy to output
  931.     inc di
  932.     inc di            ; two spaces
  933.     pop ax
  934.     loop p231
  935.  
  936.     call p340        ; display line
  937.     ret
  938. p230    endp
  939.  
  940. p300    proc near        ; copy to output line
  941.     push ax
  942.  
  943. p301:    lodsb            ; get byte
  944.     cmp al,0        ; end?
  945.     jz p305         ; yes
  946.  
  947.     stosb            ; no - save it
  948.     jmp p301        ; continue
  949.  
  950. p305:    pop ax
  951.     ret
  952. p300    endp
  953.  
  954. p310    proc near        ; print 0 if zr, else 1
  955.     mov bl,'0'
  956.     jz p315
  957.  
  958.     mov bl,'1'
  959.  
  960. p315:    mov [di],bl
  961.     inc di
  962.     ret
  963. p310    endp
  964.  
  965. p320    proc near        ; display flags
  966.     mov si,offset ndpc4
  967.     call p300        ; copy flags header
  968.     mov si,offset ndpflags
  969.     mov bx,nbpm        ; start w/ pm
  970.     mov cx,6        ; six flags
  971.  
  972. p321:    test ax,bx        ; bit on?
  973.     jnz p322        ; yes
  974.  
  975.     add si,4        ; next name
  976.     add di,4
  977.     jmp short p323
  978.  
  979. p322:    movsw            ; yes - copy it
  980.     movsw
  981.  
  982. p323:    inc di            ; skip one
  983.     shr bx,1        ; next test
  984.     loop p321
  985.     ret
  986.  
  987. p320    endp
  988.  
  989. p330    proc near        ; clear output line
  990.     mov di,offset outline
  991.     push di
  992.     mov cx,80/2        ; length
  993.     mov ax,'  '             ; spaces
  994.     rep stosw        ; init to spaces
  995.     pop di
  996.     ret
  997. p330    endp
  998.  
  999. p340    proc near        ; print output line
  1000.     mov ah,1        ; use periscope display
  1001.     mov si,offset outline    ; ds:si point to string
  1002.     call [pservice]     ; call periscope service routine
  1003.     call p330
  1004.     ret
  1005. p340    endp
  1006.  
  1007. p350    proc near        ; display nibble
  1008.     push ax
  1009.     and ax,0fh
  1010.     cmp ax,9        ; 0 to 9?
  1011.     ja p351         ; no - a to f
  1012.  
  1013.     add ax,'0'              ; convert to ascii
  1014.     jmp short p352
  1015.  
  1016. p351:    add ax,55        ; a - f
  1017.  
  1018. p352:    stosb            ; save byte
  1019.     pop ax
  1020.     ret
  1021. p350    endp
  1022.  
  1023. p360    proc near        ; display word
  1024.     mov bx,4        ; counter
  1025.  
  1026. p361:    rol ax,cl        ; move to low nibble
  1027.     call p350        ; display it
  1028.     dec bx
  1029.     jnz p361        ; not done
  1030.  
  1031.     inc di
  1032.     inc di            ; two spaces
  1033.     ret
  1034. p360    endp
  1035.  
  1036. transient:            ; end of resident code and
  1037.                 ; start of transient code
  1038.  
  1039.     cld            ; up periscope!
  1040.  
  1041.     ; init variables for function 88
  1042.     mov ah,30h
  1043.     int 21h         ; get DOS version
  1044.     mov dosver,al
  1045.  
  1046.     push es
  1047.     mov ah,52h
  1048.     mov bx,cs
  1049.     int 21h         ; get dos memory block pointer
  1050.     mov ax,es:[bx-2]
  1051.     mov dosmemseg,ax
  1052.     pop es
  1053.  
  1054.     mov ah,34h        ; set in-dos pointer
  1055.     int 21h
  1056.     mov si,offset indos
  1057.     mov [si],bx        ; save offset
  1058.     mov [si+2],es        ; and segment for user breakpoint 1
  1059.  
  1060.     xor ax,ax
  1061.     mov es,ax
  1062.     mov di,intno        ; get int number
  1063.     shl di,1
  1064.     shl di,1        ; times 4
  1065.  
  1066.     cli            ; no interrupts
  1067.     mov ax,offset resident    ; point interrupt to resident code
  1068.     stosw            ; set offset
  1069.     mov ax,ds
  1070.     stosw            ; and segment
  1071.     sti            ; interrupts back on
  1072.  
  1073.     mov dx,offset transient
  1074.     int 27h         ; stay resident
  1075.  
  1076. userexit endp
  1077. cseg    ends
  1078. end    userexit
  1079.