ADFDEBUG.ASM

57.1 KB 651ba55e40f40e28…
;
; adfdebug.asm  January 19, 2000
;
; Copyright (c) 1995-2000 Scandinavian Digital Systems AB
;
;
; Note, MASM v6.11 cannot use "ASSUME CS:", and OFFSET always gives the
; offset to labels segment or group, no segment override is available.
; This makes it hard to write efficient TSR COM-programs, so this program
; is an EXE-program.
;

                INCLUDE <adf.inc>

EXE             GROUP TSRCODE, TSRDATA, PROG, DATA, STACK

                ASSUME DS:EXE, ES:EXE, SS:EXE

INT14_MAXFUNC   EQU 21H

TSRCODE         SEGMENT PARA PUBLIC 'CODE'

; The TSR starts at offset 0

tsr_id          DB 0,13

info_string     DB 'AnDan Software FOSSIL Debug Version ',VERSION
                DB 0

tsr_id_len      EQU $-tsr_id

                ALIGN 2

debug_mode      DB 0    ; =0 --> No output
                        ; =1 --> Output on screen
                        ; =2 --> Output on file

debug_timer     DB 0    ; =1 --> Timing mode

debug_sep       DB 0    ; =0 --> CR, LF
                        ; !=0 --> character

                ALIGN 2

DebFileName     DB 32 DUP(0)

DebBuf          DB 1024 DUP(0)

DebTxtNone      DB 'Nothing',0

                ALIGN 2

OffSP           EQU 32
RegCS           EQU 28
RegIP           EQU 26
RegF            EQU 18
RegAX           EQU 16
RegBX           EQU 14
RegCX           EQU 12
RegDX           EQU 10
RegBP           EQU 8
RegSI           EQU 6
RegDI           EQU 4
RegDS           EQU 2
RegES           EQU 0

RegAH           EQU 17
RegAL           EQU 16
RegBH           EQU 15
RegBL           EQU 14
RegCH           EQU 13
RegCL           EQU 12
RegDH           EQU 11
RegDL           EQU 10

DebRegStart     LABEL WORD

Deb16Reg18      DW 0
Deb16Reg16      LABEL WORD
Deb8Reg16       DB 0
Deb8Reg17       DB 0
Deb16Reg14      LABEL WORD
Deb8Reg14       DB 0
Deb8Reg15       DB 0
Deb16Reg12      LABEL WORD
Deb8Reg12       DB 0
Deb8Reg13       DB 0
Deb16Reg10      LABEL WORD
Deb8Reg10       DB 0
Deb8Reg11       DB 0
Deb16Reg8       DW 0
Deb16Reg6       DW 0
Deb16Reg4       DW 0
Deb16Reg2       DW 0
Deb16Reg0       DW 0

DebRegLen       EQU $-DebRegStart

Deb16RS16       DB 'AX'
Deb8RS16        DB 'AL'
Deb8RS17        DB 'AH'
Deb16RS14       DB 'BX'
Deb8RS14        DB 'BL'
Deb8RS15        DB 'BH'
Deb16RS12       DB 'CX'
Deb8RS12        DB 'CL'
Deb8RS13        DB 'CH'
Deb16RS10       DB 'DX'
Deb8RS10        DB 'DL'
Deb8RS11        DB 'DH'
Deb16RS8        DB 'BP'
Deb16RS6        DB 'SI'
Deb16RS4        DB 'DI'
Deb16RS2        DB 'DS'
Deb16RS0        DB 'ES'


DebStr          MACRO str1:REQ
                LOCAL strlbl1
TSRDATA         SEGMENT WORD PUBLIC 'CODE'
strlbl1         DB str1
                DB 0
TSRDATA         ENDS
                mov si,OFFSET strlbl1
                call DebText
                ENDM

DebSep          MACRO
                call _DebSep
                ENDM

DebStrNone      MACRO
                mov si,OFFSET DebTxtNone
                call DebText
                call _DebSep
                ENDM

                IF 0    ;Not used

Deb8            MACRO str1:REQ,reg:REQ,str2
                LOCAL strlbl1,strlbl2
TSRDATA         SEGMENT WORD PUBLIC 'CODE'
strlbl1         DB str1
                DB 0
                IFNB <str2>
strlbl2         DB str2
                DB 0
                ENDIF
TSRDATA         ENDS
                mov si,OFFSET strlbl1
                call DebText
                mov [@CatStr(Deb8Reg,%reg)],-1
                mov al,[bp+reg]
                call DebBinHex8
                IFNB <str2>
                mov si,OFFSET strlbl2
                call DebText
                ENDIF
                ENDM

Deb16           MACRO str1:REQ,reg:REQ,str2
                LOCAL strlbl1,strlbl2
TSRDATA         SEGMENT WORD PUBLIC 'CODE'
strlbl1         DB str1
                DB 0
                IFNB <str2>
strlbl2         DB str2
                DB 0
                ENDIF
TSRDATA         ENDS
                mov si,OFFSET strlbl1
                call DebText
                mov [@CatStr(Deb16Reg,%reg)],-1
                mov ax,[bp+reg]
                call DebBinHex16
                IFNB <str2>
                mov si,OFFSET strlbl2
                call DebText
                ENDIF
                ENDM

Deb32           MACRO str1:REQ,reg1:REQ,reg2:REQ,str2
                LOCAL strlbl1,strlbl2
TSRDATA         SEGMENT WORD PUBLIC 'CODE'
strlbl1         DB str1
                DB 0
                IFNB <str2>
strlbl2         DB str2
                DB 0
                ENDIF
TSRDATA         ENDS
                mov si,OFFSET strlbl1
                call DebText
                mov [@CatStr(Deb16Reg,%reg1)],-1
                mov ax,[bp+reg1]
                call DebBinHex16
                mov al,':'
                stosb
                mov [@CatStr(Deb16Reg,%reg2)],-1
                mov ax,[bp+reg2]
                call DebBinHex16
                IFNB <str2>
                mov si,OFFSET strlbl2
                call DebText
                ENDIF
                ENDM

                ENDIF   ;Not used

DebCSIP         MACRO str1:REQ,str2
                LOCAL strlbl1,strlbl2
TSRDATA         SEGMENT WORD PUBLIC 'CODE'
strlbl1         DB str1
                DB 0
                IFNB <str2>
strlbl2         DB str2
                DB 0
                ENDIF
TSRDATA         ENDS
                mov si,OFFSET strlbl1
                call DebText
                mov ax,[bp+RegCS]
                call DebBinHex16
                mov al,':'
                stosb
                mov ax,[bp+RegIP]
                call DebBinHex16
                IFNB <str2>
                mov si,OFFSET strlbl2
                call DebText
                ENDIF
                ENDM

DebSSSP         MACRO str1:REQ,str2
                LOCAL strlbl1,strlbl2
TSRDATA         SEGMENT WORD PUBLIC 'CODE'
strlbl1         DB str1
                DB 0
                IFNB <str2>
strlbl2         DB str2
                DB 0
                ENDIF
TSRDATA         ENDS
                mov si,OFFSET strlbl1
                call DebText
                mov ax,ss
                call DebBinHex16
                mov al,':'
                stosb
                mov ax,bp
                add ax,OffSP
                call DebBinHex16
                IFNB <str2>
                mov si,OFFSET strlbl2
                call DebText
                ENDIF
                ENDM

DebFlags        MACRO str1:REQ,str2
                LOCAL strlbl1,strlbl2
TSRDATA         SEGMENT WORD PUBLIC 'CODE'
strlbl1         DB str1
                DB 0
                IFNB <str2>
strlbl2         DB str2
                DB 0
                ENDIF
TSRDATA         ENDS
                mov si,OFFSET strlbl1
                call DebText
                mov ax,[bp+RegF]
                call DebBinHex16
                IFNB <str2>
                mov si,OFFSET strlbl2
                call DebText
                ENDIF
                ENDM

DebOth16        MACRO str1:REQ,reg:REQ
                LOCAL strlbl1,skip
TSRDATA         SEGMENT WORD PUBLIC 'CODE'
strlbl1         DB str1
                DB 0
TSRDATA         ENDS
                cmp [@CatStr(Deb16Reg,%reg)],0
                jnz skip
                mov si,OFFSET strlbl1
                call DebText
                mov ax,[bp+reg]
                call DebBinHex16
skip:
                ENDM

DebOth8         MACRO str1:REQ,str2:REQ,str3:REQ,reg1:REQ,reg2:REQ,reg3:REQ
                LOCAL strlbl1,strlbl2,strlbl3,oth1,oth2,oth3
TSRDATA         SEGMENT WORD PUBLIC 'CODE'
strlbl1         DB str1
                DB 0
strlbl2         DB str2
                DB 0
strlbl3         DB str3
                DB 0
TSRDATA         ENDS
                cmp [@CatStr(Deb16Reg,%reg1)],0
                jnz oth1
                mov si,OFFSET strlbl1
                call DebText
                mov ax,[bp+reg1]
                call DebBinHex16
                jmp oth3
oth1:           cmp [@CatStr(Deb8Reg,%reg2)],0
                jnz oth2
                mov si,OFFSET strlbl2
                call DebText
                mov al,[bp+reg2]
                call DebBinHex8
oth2:           cmp [@CatStr(Deb8Reg,%reg3)],0
                jnz oth3
                mov si,OFFSET strlbl3
                call DebText
                mov al,[bp+reg3]
                call DebBinHex8
oth3:
                ENDM

Deb8s           MACRO reg:REQ,str2
                LOCAL strlbl2
                IFNB <str2>
TSRDATA         SEGMENT WORD PUBLIC 'CODE'
strlbl2         DB '   '
                DB str2
                DB 0
TSRDATA         ENDS
                ENDIF
                mov si,OFFSET @CatStr(Deb8RS,%reg)
                lodsw
                stosw
                mov al,'='
                stosb
                mov [@CatStr(Deb8Reg,%reg)],-1
                mov al,[bp+reg]
                call DebBinHex8
                IFNB <str2>
                mov si,OFFSET strlbl2
                call DebText
                ENDIF
                ENDM

Deb16s          MACRO reg:REQ,str2
                LOCAL strlbl2
                IFNB <str2>
TSRDATA         SEGMENT WORD PUBLIC 'CODE'
strlbl2         DB ' '
                DB str2
                DB 0
TSRDATA         ENDS
                ENDIF
                mov si,OFFSET @CatStr(Deb16RS,%reg)
                lodsw
                stosw
                mov al,'='
                stosb
                mov [@CatStr(Deb16Reg,%reg)],-1
                mov ax,[bp+reg]
                call DebBinHex16
                IFNB <str2>
                mov si,OFFSET strlbl2
                call DebText
                ENDIF
                ENDM

Deb32s          MACRO reg1:REQ,reg2:REQ,str2
                LOCAL strlbl1,strlbl2
TSRDATA         SEGMENT WORD PUBLIC 'CODE'
                IFNB <str2>
strlbl2         DB ' '
                DB str2
                DB 0
                ENDIF
TSRDATA         ENDS
                mov si,OFFSET @CatStr(Deb16RS,%reg1)
                lodsw
                stosw
                mov al,':'
                stosb
                mov si,OFFSET @CatStr(Deb16RS,%reg2)
                lodsw
                stosw
                mov al,'='
                stosb
                mov [@CatStr(Deb16Reg,%reg1)],-1
                mov ax,[bp+reg1]
                call DebBinHex16
                mov al,':'
                stosb
                mov [@CatStr(Deb16Reg,%reg2)],-1
                mov ax,[bp+reg2]
                call DebBinHex16
                IFNB <str2>
                mov si,OFFSET strlbl2
                call DebText
                ENDIF
                ENDM

DebBinHex16:    mov dh,al
                mov al,ah
                call DebBinHex8
                mov al,dh

DebBinHex8:     mov dl,al
                ror al,1
                ror al,1
                ror al,1
                ror al,1
                call DebBinHex4
                mov al,dl

DebBinHex4:     and al,15
                add al,48
                cmp al,58
                jc DebBinHex4a
                add al,7
DebBinHex4a:    stosb
DebText1:       ret

                ALIGN 4

DebText:        lodsb
                and al,al
                jz DebText1
                stosb
                jmp DebText

                ALIGN 4

_DebSep:        mov al,[debug_sep]
                and al,al
                jnz _DebSep1
                mov al,13
                stosb
                mov al,10
_DebSep1:       stosb
                ret

                ALIGN 2

DebOutput:      cmp [debug_mode],2
                jz DebOutput2

                mov ah,0FH
                int 10H               ;Get video mode, active page, num col
                mov bl,3
                mov cx,di
                mov ah,0EH

                ALIGN 2

DebOutput1:     lodsb
                int 10H
                loop DebOutput1
                ret

                ALIGN 2

DebOutput2:     mov dx,OFFSET DebFileName
                mov ax,3D02H
                int 21H
                jnc DebOutput3
                cmp ax,2
                jnz DebOutput5
                xor cx,cx
                mov ah,3CH
                int 21H
                jc DebOutput5
DebOutput3:     mov bx,ax
                xor cx,cx
                xor dx,dx
                mov ax,4202H
                int 21H
                jc DebOutput4
                mov dx,si
                mov cx,di
                mov ah,40H
                int 21H
DebOutput4:     mov ah,3EH
                int 21H
DebOutput5:     ret

                ALIGN 4

DebOthers:      DebStr 'Other regs:'
                DebOth8 ' AX=',' AH=',' AL=',RegAX,RegAH,RegAL
                DebOth8 ' BX=',' BH=',' BL=',RegBX,RegBH,RegBL
                DebOth8 ' CX=',' CH=',' CL=',RegCX,RegCH,RegCL
                DebOth8 ' DX=',' DH=',' DL=',RegDX,RegDH,RegDL
                DebOth16 ' SI=',RegSI
                DebOth16 ' DI=',RegDI
                DebOth16 ' BP=',RegBP
                DebOth16 ' DS=',RegDS
                DebOth16 ' ES=',RegES
                DebFlags ' FLAGS='
                DebSep
                ret

                ALIGN 4

;
; read_838ns
;
; In:  ----
; Out: DX:AX = Value of the free running 838 ns counter.
;
; Registers destroyed: Flags only
;
; Before using, call 'init_838ns' once for initialization.
;
; After using, call 'term_838ns' once for termination.
;
; Each time unit is exactly:
;
; 1/(14318180/12) s = 838.095 ns
;
; When 'read_838ns' is used, the timer channel 0 will be programmed to mode 2
; instead of the standard mode 3, at initialization.
;
; This reprogramming may cause the internal DOS clock to be inaccurate,
; if the program is executed many times (probably about a million times to get
; a few seconds error).
;
; The reprogramming may also cause incompatible problems for other programs,
; depending on mode 3 for channel 0 in the timer IC.
;
; When the program terminates, the timer IC is not reprogrammed to mode 3.
;

ustimer         DB 0

tick_55ms       DW 0

                ALIGN 4

oldint08us      DD 0
                DB 08H,'INT'

sysint08us      PROC FAR

                cli
                cmp cs:[ustimer],0
                jnz sysint08us1
                push ax
                mov al,00110100B        ;Timer 0, Mode 2, 2 byte R/W, Binary
                out 43h,al
                xor al,al
                jmp $+2
                out 40h,al
                jmp $+2
                out 40h,al
                pop ax
                mov cs:[ustimer],255
sysint08us1:    inc cs:[tick_55ms]
                jmp cs:[oldint08us]

sysint08us      ENDP

                ALIGN 4

read_838ns:     mov al,00000100B
                cli
                out 043H,al
                jmp $+2
                in al,040H          ;Read LSB
                jmp $+2
                mov ah,al
                in al,040H          ;Read MSB
                xchg al,ah
                mov dx,cs:[tick_55ms]
                sti
                cmp ax,65535-20
                jb read_838ns1
                cmp dx,cs:[tick_55ms]
                jz read_838ns1
                inc dx
read_838ns1:    not ax              ;timer in DX:AX
                ret

                ALIGN 4

ltoa_tab        DD 1000000000
                DD 100000000
                DD 10000000
                DD 1000000
                DD 100000
                DD 10000
                DD 1000
                DD 100
                DD 10
                DD 1
;
; ltoa  (fixed length, space fill)
;
; In:  DX:AX = 32 bit unsigned integer
;      DS:DI = 10 bytes buffer
;
ltoa:           mov cx,10*256+' '
                mov si,OFFSET ltoa_tab

                ALIGN 4

ltoa1:          xor bl,bl
ltoa2:          sub ax,[si]
                sbb dx,[si+2]
                jc ltoa3
                inc bl
                jmp ltoa2

                ALIGN 4

ltoa3:          add ax,[si]
                adc dx,[si+2]
                add si,4
                and bl,bl
                jz ltoa6
ltoa4:          mov cl,'0'
                or bl,cl
ltoa5:          mov [di],bl
                inc di
                dec ch
                jnz ltoa1
                ret

                ALIGN 4

ltoa6:          cmp ch,1
                jz ltoa4
                mov bl,cl
                jmp ltoa5

                ALIGN 4

func_entry00:   Deb8s RegAH,'Set communications parameters'
                DebSep
                Deb8s RegAL,'Baud rate and param code'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit00:    Deb16s RegAX,'Status'
                DebSep
                ret

                ALIGN 4

func_entry01:   Deb8s RegAH,'Transmit character and wait'
                DebSep
                Deb8s RegAL,'Character'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit01:    Deb16s RegAX,'Status'
                DebSep
                ret

                ALIGN 4

func_entry02:   Deb8s RegAH,'Get received character with wait'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit02:    Deb8s RegAH,'Line status'
                DebSep
                Deb8s RegAL,'Character'
                DebSep
                ret

                ALIGN 4

func_entry03:   Deb8s RegAH,'Return serial port status'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit03:    Deb16s RegAX,'Status'
                DebSep
                ret

                ALIGN 4

func_entry04:   Deb8s RegAH,'Activate port'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit04:    Deb16s RegAX,'Reply 1954'
                DebSep
                Deb8s RegBH,'Rev of FOSSIL'
                DebSep
                Deb8s RegBL,'Max function number'
                DebSep
                ret

                ALIGN 4

func_entry05:   Deb8s RegAH,'Deactivate port'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit05:    DebStrNone
                ret

                ALIGN 4

func_entry06:   Deb8s RegAH,'Raise/lower DTR'
                DebSep
                Deb8s RegAL,'Raise (01) or lower (00)'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit06:    DebStrNone
                ret

                ALIGN 4

func_entry07:   Deb8s RegAH,'Return timer tick information'
                DebSep
                ret

                ALIGN 4

func_exit07:    Deb8s RegAH,'Ticks per second'
                DebSep
                Deb8s RegAL,'Interrupt number'
                DebSep
                Deb16s RegDX,'Milliseconds per tick'
                DebSep
                ret

                ALIGN 4

func_entry08:   Deb8s RegAH,'Flush output buffer'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit08:    DebStrNone
                ret

                ALIGN 4

func_entry09:   Deb8s RegAH,'Purge output buffer'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit09:    DebStrNone
                ret

                ALIGN 4

func_entry0A:   Deb8s RegAH,'Purge input buffer'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit0A:    DebStrNone
                ret

                ALIGN 4

func_entry0B:   Deb8s RegAH,'Transmit no wait'
                DebSep
                Deb8s RegAL,'Character'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit0B:    Deb16s RegAX,'OK (0001) or no room in buffer (0000)'
                DebSep
                ret

                ALIGN 4

func_entry0C:   Deb8s RegAH,'Non-destructive read-ahead'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit0C:    Deb16s RegAX,'Character or FFFF'
                DebSep
                ret

                ALIGN 4

func_entry0D:   Deb8s RegAH,'Keyboard read without wait'
                DebSep
                ret

                ALIGN 4

func_exit0D:    Deb16s RegAX,'Scan code or FFFF'
                DebSep
                ret

                ALIGN 4

func_entry0E:   Deb8s RegAH,'Keyboard read with wait'
                DebSep
                ret

                ALIGN 4

func_exit0E:    Deb16s RegAX,'Scan code'
                DebSep
                ret

                ALIGN 4

func_entry0F:   Deb8s RegAH,'Flow control for serial I/O'
                DebSep
                Deb8s RegAL,'Control bits'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit0F:    DebStrNone
                ret

                ALIGN 4

func_entry10:   Deb8s RegAH,'Control-C / Control-K checking'
                DebSep
                Deb8s RegAL,'Control bits'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit10:    Deb16s RegAX,'Control-C/K received (0001) or not received (0000)'
                DebSep
                ret

                ALIGN 4

func_entry11:   Deb8s RegAH,'Set current cursor location'
                DebSep
                Deb8s RegDH,'Row'
                DebSep
                Deb8s RegDL,'Line'
                DebSep
                ret

                ALIGN 4

func_exit11:    DebStrNone
                ret

                ALIGN 4

func_entry12:   Deb8s RegAH,'Read current cursor location'
                DebSep
                ret

                ALIGN 4

func_exit12:    Deb8s RegDH,'Row'
                DebSep
                Deb8s RegDL,'Line'
                DebSep
                ret

                ALIGN 4

func_entry13:   Deb8s RegAH,'Single character ANSI write to screen'
                DebSep
                Deb8s RegAL,'Character'
                DebSep
                ret

                ALIGN 4

func_exit13:    DebStrNone
                ret

                ALIGN 4

func_entry14:   Deb8s RegAH,'Enable or disable the DCD watchdog'
                DebSep
                Deb8s RegAL,'Enable (01) or disable (00)'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit14:    DebStrNone
                ret

                ALIGN 4

func_entry15:   Deb8s RegAH,'Write character to screen using BIOS'
                DebSep
                Deb8s RegAL,'Character'
                DebSep
                ret

                ALIGN 4

func_exit15:    DebStrNone
                ret

                ALIGN 4

func_entry16:   Deb8s RegAH,'Add or delete a routine from the timer tick'
                DebSep
                Deb8s RegAL,'Add (01) or delete (00)'
                DebSep
                Deb32s RegES,RegDX,'Address of function'
                DebSep
                ret

                ALIGN 4

func_exit16:    Deb16s RegAX,'OK (0000 or ticks/sec) or fail (FFFF)'
                DebSep
                ret

                ALIGN 4

func_entry17:   Deb8s RegAH,'Reboot system'
                DebSep
                Deb8s RegAL,'Cold (00) or warm (01)'
                DebSep
                ret

                ALIGN 4

func_exit17:    DebStrNone
                ret

                ALIGN 4

func_entry18:   Deb8s RegAH,'Block Read'
                DebSep
                Deb32s RegES,RegDI,'Address of buffer'
                DebSep
                Deb16s RegCX,'Number of bytes'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit18:    Deb16s RegAX,'Bytes transferred'
                DebSep
                ret

                ALIGN 4

func_entry19:   Deb8s RegAH,'Block Write'
                DebSep
                Deb32s RegES,RegDI,'Address of buffer'
                DebSep
                Deb16s RegCX,'Number of bytes'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit19:    Deb16s RegAX,'Bytes transferred'
                DebSep
                ret

                ALIGN 4

func_entry1A:   Deb8s RegAH,'Break begin or end'
                DebSep
                Deb8s RegAL,'Begin (01) or end (00)'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit1A:    DebStrNone
                ret

                ALIGN 4

func_entry1B:   Deb8s RegAH,'Return information about FOSSIL'
                DebSep
                Deb32s RegES,RegDI,'Address of buffer'
                DebSep
                Deb16s RegCX,'Number of bytes'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit1B:    Deb16s RegAX,'Bytes transferred'
                DebSep
                ret

                ALIGN 4

func_entry1C:   Deb8s RegAH,'Activate port'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit1C:    Deb16s RegAX,'Reply 1954'
                DebSep
                Deb8s RegBH,'Rev of FOSSIL'
                DebSep
                Deb8s RegBL,'Max function number'
                DebSep
                ret

                ALIGN 4

func_entry1D:   Deb8s RegAH,'Deactivate port'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit1D:    DebStrNone
                ret

                ALIGN 4

func_entry1E:   Deb8s RegAH,'Extended line control initialization'
                DebSep
                Deb8s RegAL,'Break begin (01) or break end (00)'
                DebSep
                Deb16s RegBX,'Parameters'
                DebSep
                Deb16s RegCX,'Parameters'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit1E:    Deb16s RegAX,'Status'
                DebSep
                ret

                ALIGN 4

func_entry1F:   Deb8s RegAH,'Extended serial port status/control'
                DebSep
                Deb8s RegAL,'Read (00) or write (01)'
                DebSep
                Deb8s RegBL,'Modem control register'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit1F:    Deb16s RegAX,'Status'
                DebSep
                Deb8s RegBL,'Modem control register'
                DebSep
                ret

                ALIGN 4

func_entry20:   Deb8s RegAH,'Read with no wait (destructive)'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret

                ALIGN 4

func_exit20:    Deb16s RegAX,'Character or FFFF'
                DebSep
                ret

                ALIGN 4

func_entry21:   Deb8s RegAH,'Stuff/Poke the receive buffer'
                DebSep
                Deb8s RegAL,'Character'
                DebSep
                Deb16s RegDX,'Port'
                DebSep
                ret
func_exit21:    DebStrNone
                ret

                ALIGN 4

func_entry_x:   Deb8s RegAH,'Unknown'
                DebSep
func_exit_x:    DebStr 'Unknown'
                DebSep
                ret

                ALIGN 4

func_entry      DW OFFSET func_entry00
                DW OFFSET func_entry01
                DW OFFSET func_entry02
                DW OFFSET func_entry03
                DW OFFSET func_entry04
                DW OFFSET func_entry05
                DW OFFSET func_entry06
                DW OFFSET func_entry07
                DW OFFSET func_entry08
                DW OFFSET func_entry09
                DW OFFSET func_entry0A
                DW OFFSET func_entry0B
                DW OFFSET func_entry0C
                DW OFFSET func_entry0D
                DW OFFSET func_entry0E
                DW OFFSET func_entry0F
                DW OFFSET func_entry10
                DW OFFSET func_entry11
                DW OFFSET func_entry12
                DW OFFSET func_entry13
                DW OFFSET func_entry14
                DW OFFSET func_entry15
                DW OFFSET func_entry16
                DW OFFSET func_entry17
                DW OFFSET func_entry18
                DW OFFSET func_entry19
                DW OFFSET func_entry1A
                DW OFFSET func_entry1B
                DW OFFSET func_entry1C
                DW OFFSET func_entry1D
                DW OFFSET func_entry1E
                DW OFFSET func_entry1F
                DW OFFSET func_entry20
                DW OFFSET func_entry21
                DW OFFSET func_entry_x

func_exit       DW OFFSET func_exit00
                DW OFFSET func_exit01
                DW OFFSET func_exit02
                DW OFFSET func_exit03
                DW OFFSET func_exit04
                DW OFFSET func_exit05
                DW OFFSET func_exit06
                DW OFFSET func_exit07
                DW OFFSET func_exit08
                DW OFFSET func_exit09
                DW OFFSET func_exit0A
                DW OFFSET func_exit0B
                DW OFFSET func_exit0C
                DW OFFSET func_exit0D
                DW OFFSET func_exit0E
                DW OFFSET func_exit0F
                DW OFFSET func_exit10
                DW OFFSET func_exit11
                DW OFFSET func_exit12
                DW OFFSET func_exit13
                DW OFFSET func_exit14
                DW OFFSET func_exit15
                DW OFFSET func_exit16
                DW OFFSET func_exit17
                DW OFFSET func_exit18
                DW OFFSET func_exit19
                DW OFFSET func_exit1A
                DW OFFSET func_exit1B
                DW OFFSET func_exit1C
                DW OFFSET func_exit1D
                DW OFFSET func_exit1E
                DW OFFSET func_exit1F
                DW OFFSET func_exit20
                DW OFFSET func_exit21
                DW OFFSET func_exit_x

                ALIGN 4

jump_to_old:    pop es
                pop ds
                pop di
                pop si
                pop bp
                pop dx
                pop cx
                pop bx
                pop ax
                popf
                pop ax
                pop ax
                pop ax
                jmp cs:[oldint14]

                ALIGN 4

oldint14        DD 0
                DB 14H,'INT'

fossil:         jmp SHORT fossil1

                DB 'ADF',0
                DW 1954H
                DB INT14_MAXFUNC
                DB 0


;               SP          ;BP+32
;               Flags       ;BP+30
;               CS          ;BP+28
;               IP          ;BP+26
fossil1:        push ax     ;BP+24      (timer MSB)
                push ax     ;BP+22      (timer LSB)
                push ax     ;BP+20      (exit func)
                pushf       ;BP+18
                push ax     ;BP+16
                push bx     ;BP+14
                push cx     ;BP+12
                push dx     ;BP+10
                push bp     ;BP+8
                push si     ;BP+6
                push di     ;BP+4
                push ds     ;BP+2
                push es     ;BP+0
                cld
                sti
                mov bp,sp
                mov bx,cs   ;Keep AH
                mov ds,bx
                mov es,bx
                cmp [debug_mode],0
                jz jump_to_old
                mov bx,[bp+30]
                mov [bp+18],bx
                cmp ah,INT14_MAXFUNC
                jbe fossil1a
                mov ah,INT14_MAXFUNC+1
fossil1a:       mov al,ah
                xor ah,ah
                shl ax,1
                mov bx,ax
                mov [bp+20],bx
                xor ax,ax
                mov cx,DebRegLen/2
                mov di,OFFSET DebRegStart
                rep stosw
                mov di,OFFSET DebBuf
                DebStr <'INT 14'>
                DebSep
                mov bx,[bp+20]
                call [func_entry+bx]
                DebCSIP 'CS:IP='
                DebSSSP ' SS:SP='
                DebSep
                call DebOthers
                mov si,OFFSET DebBuf
                sub di,si
                call DebOutput
                cmp [debug_timer],0
                jz fossil2
                call read_838ns
                mov [bp+22],ax
                mov [bp+24],dx
fossil2:        pop es
                pop ds
                pop di
                pop si
                pop bp
                pop dx
                pop cx
                pop bx
                pop ax
                popf
                pushf
                cli
                call cs:[oldint14]
                pushf       ;BP+18
                cli
                push ax     ;BP+16
                push bx     ;BP+14
                push cx     ;BP+12
                push dx     ;BP+10
                push bp     ;BP+8
                push si     ;BP+6
                push di     ;BP+4
                push ds     ;BP+2
                push es     ;BP+0
                mov bp,sp
                mov ax,cs
                mov ds,ax
                mov es,ax
                cmp [debug_timer],0
                jz fossil3
                call read_838ns
                sub ax,[bp+22]
                sbb dx,[bp+24]
                mov [bp+22],ax
                mov [bp+24],dx
fossil3:        sti
                cld
                xor ax,ax
                mov cx,DebRegLen/2
                mov di,OFFSET DebRegStart
                rep stosw
                mov di,OFFSET DebBuf
                DebStr 'Return'
                cmp [debug_timer],0
                jz fossil4
                DebStr ', time: '
                mov ax,[bp+22]
                mov dx,[bp+24]
                call ltoa
fossil4:        DebSep
                mov bx,[bp+20]
                call [func_exit+bx]
                call DebOthers
                mov al,13
                stosb
                mov al,10
                stosb
                mov si,OFFSET DebBuf
                sub di,si
                call DebOutput
                mov ax,[bp+18]
                mov [bp+30],ax
                pop es
                pop ds
                pop di
                pop si
                pop bp
                pop dx
                pop cx
                pop bx
                pop ax
                add sp,8
                iret

TSRCODE         ENDS

PROG            SEGMENT WORD PUBLIC 'CODE'

tsr_end         EQU $   ;Must be on even address

txt_doc_init    DB 13,10
                DB 'AnDan Software FOSSIL Debug Version ',VERSION,13,10
                DB 'Copyright (c) 1995-2000 Scandinavian Digital Systems AB',13,10
                DB 13,10
                DB 'Internet: http://www.digsys.se     e-mail: andan@digsys.se',13,10
                DB 13,10
                DB 'Freeware: May be used, copied and distributed if no fee is',13,10
                DB '          charged and if no changes are done.',13,10
                DB 0

txt_doc_usage   DB 13,10
                DB 'adfdebug command',13,10
                DB 13,10
                DB 39,'command',39,' is one of the following commands:',13,10
                DB 13,10
                DB 'L [opt] Load TSR, should be done after the FOSSIL load. Options:',13,10
                DB '        /t    Use time measurement.',13,10
                DB '        /sNN  Use ASCII NN as separator, default is 13 and 10 (CR and LF).',13,10
                DB 'U       Unload TSR, should be done before the FOSSIL unload.',13,10
                DB 'N       No output (default at load time).',13,10
                DB 'S       Screen output.',13,10
                DB 'F file  File output to the specified file.',13,10
                DB 0

err_begin       DB 13,10,7,"Error when executing ADFDebug:",13,10,13,10,0
err_end1        DB 13,10,13,10,7,"Press any key to continue, or wait a moment.",0
err_end2        DB 13,10,13,10,0

err_arg         DB 'Argument error (command line error).',0
err_dosver      DB 'DOS v3.1 or newer required.',0
err_tsr         DB 'Unable to handle TSRs in this environment.',0
err_free        DB 'Error when releasing memory.',0
err_intrel      DB 'Error when restoring interrupts.',0
err_reload      DB 'ADFDebug already loaded.',0
err_notload     DB 'ADFDebug not loaded.',0

txt_loaded      DB 13,10,'ADFDebug loaded.',13,10,0
txt_timeload    DB 13,10,'ADFDebug loaded with time measurement.',13,10,0
txt_unload      DB 13,10,'ADFDebug unloaded.',13,10,0
txt_deb_none    DB 13,10,'Debug output: None',13,10,0
txt_deb_screen  DB 13,10,'Debug output: Screen',13,10,0
txt_deb_file    DB 13,10,'Debug output: File',13,10,0

                ALIGN 2

pspseg          DW 0


;
; print
;

                ALIGN 2

print:          xor     al,al
                mov     di,si
                mov     cx,0FFFFh
                repne   scasb
                not     cx
                dec     cx
                mov     bx,1
                mov     dx,si
                mov     ah,40H
                int     21H
                ret

                ALIGN 2

;
; print_err
;
print_err:      push ax
                mov ax,cs
                mov ds,ax
                mov es,ax
                push si
                mov si,OFFSET err_begin
                call print
                pop si
                call print
                mov si,OFFSET err_end1
                call print
                mov si,30
                mov ah,2CH
                int 21H
print_err1:     mov bl,dh
print_err2:     mov ah,01H
                int 16H
                jnz print_err4
                mov ah,2CH
                int 21H
                cmp bl,dh
                jz print_err2
                dec si
                jnz print_err1
print_err3:     mov si,OFFSET err_end2
                call print
                pop ax
                ret

print_err4:     xor ah,ah
                int 16H
                jmp print_err3

                ALIGN 2

jmp_white:      lodsb
                cmp     al,13
                je      jmp_white1
                cmp     al,32
                jbe     jmp_white
                dec     si
                clc
                ret
jmp_white1:     dec     si
                stc
                ret

                ALIGN 2

ascstr:         lodsb
                cmp al,32
                jbe ascstr1
                stosb
                loop ascstr
                stc
                ret

ascstr1:        dec si
                xor al,al
                stosb
                ret

                ALIGN 2

asc8dec:        xor al,al
                mov bl,10
asc8dec1:       mov cl,[si]
                sub cl,'0'
                jc asc8dec3
                cmp cl,bl
                jae asc8dec3
                inc si
                mul bl
                and ah,ah
                jnz asc8dec2
                add al,cl
                jnc asc8dec1
asc8dec2:       stc
                ret
asc8dec3:       cmp BYTE PTR [si],33
                cmc
                ret

                ALIGN 2

;
; int_init
;
; Initialize an interrupt.
;
; In:  DS:BX = Address to the interrupt routine and data. The routine and
;              data must must have the structure:
;
;              oldintXX        DD 0                     ;Nonzero if vector
;                                                       ;already is saved
;                                                       ;Zero if vector
;                                                       ;is not saved
;
;                              DB XXH,'INT'             ;XXH is the interrupt
;                                                       ;number in hex
;
;              intXX           PROC FAR                 ;DS:BX points here
;
;                              .
;                              .
;                              .
;
;              intXX           ENDP
;
;
; Register AX, BX, CX, DX are destroyed
;
; Note, may be called during unload with DS set to TSR.
;
USE_INT21       EQU 1           ;Use INT 21H to modify interrupt pointers

int_init:       mov ax,[bx-8]
                or ax,[bx-6]
                jnz int_init1
                push es

                IFE USE_INT21

                mov cx,di
                mov al,[bx-4]
                xor ah,ah
                shl ax,1
                shl ax,1
                mov di,ax
                xor ax,ax
                mov es,ax
                cli
                mov ax,es:[di]
                mov dx,es:[di+2]
                mov [bx-8],ax
                mov [bx-6],dx
                mov es:[di],bx
                mov es:[di+2],ds
                sti
                mov di,cx

                ELSE

                mov dx,bx
                mov al,[bx-4]
                mov ah,35H
                cli
                int 21H
                cli
                xchg dx,bx
                mov [bx-8],dx
                mov [bx-6],es
                mov dx,bx
                mov ah,25H
                int 21H
                sti

                ENDIF

                pop es

int_init1:      ret


                ALIGN 2

;
; int_term
;
; Restores an interrupt.
;
; In:  DS:BX = Address to the interrupt routine and data, see 'int_init'.
; Out: C = 1 if no restore was possible.
;
; Register AX, BX, CX, DX are destroyed
;
; Note, may be called during unload with DS set to TSR.
;
int_term:       mov ax,[bx-8]
                or ax,[bx-6]
                jz int_term2

                push di
                push es
                mov cx,ds

                IFE USE_INT21

                mov al,[bx-4]
                xor ah,ah
                shl ax,1
                shl ax,1
                mov di,ax
                mov dx,ax
                xor ax,ax
                mov es,ax
                cli
                les di,es:[di]
                mov ax,es
                cmp ax,cx
                jnz int_term4
                cmp di,bx
                jnz int_term4
                xor ax,ax
                mov es,ax
                mov di,dx
                mov ax,[bx-8]
                mov dx,[bx-6]
                mov es:[di],ax
                mov es:[di+2],dx
                xor ax,ax
                mov [bx-8],ax
                mov [bx-6],ax
                sti

                ELSE

                mov dx,bx
                mov al,[bx-4]
                mov ah,35H
                cli
                int 21H
                cli
                mov di,bx
                mov bx,dx
                mov dx,es
                cmp dx,cx
                jnz int_term4
                cmp di,bx
                jnz int_term4
                mov cx,ds
                lds dx,[bx-8]
                mov ah,25H
                int 21H
                cli
                xor ax,ax
                mov es:[bx-8],ax
                mov es:[bx-6],ax
                sti
                mov ds,cx

                ENDIF

int_term1:      pop es
                pop di
int_term2:      clc
                ret

int_term3:      les di,es:[di-8]

;
; BX = Offset to interrupt header to release
; DS = Segment to interrupt header to release
; CX = DS
; DI = Offset to current interrupt header to release
; ES = Segment to current interrupt header to release

int_term4:      cmp di,8
                jb int_term5
                cmp WORD PTR es:[di-2],'TN'
                jnz int_term5
                mov ax,[bx-4]
                cmp ax,es:[di-4]
                jnz int_term5
                cmp bx,es:[di-8]
                jnz int_term3
                cmp cx,es:[di-6]
                jnz int_term3
                mov ax,[bx-8]
                mov cx,[bx-6]
                mov es:[di-8],ax
                mov es:[di-6],cx
                xor ax,ax
                mov [bx-8],ax
                mov [bx-6],ax
                sti
                jmp int_term1

int_term5:      sti
                pop es
                pop di
                stc
                ret

                ALIGN 2

;
; find_tsr
;
; In:   ES = DS = CS
; Out:  ZF = 1 --> TSR not found
;                  DX = 0
;       ZF = 0 --> TSR found
;                  DX = Segment
; Chg:  AX, BX, CX, DX, SI, DI
;
; block_init must have been called once on program startup
;

first_block_seg DW 0

find_tsr:       mov dx,[first_block_seg]

find_tsr1:      call dos_next_block
                and dx,dx
                jz find_tsr2
; DS = DX-1
                cmp dx,ds:[1]
                jnz find_tsr1
                mov si,90H
                mov di,OFFSET tsr_id
                mov cx,tsr_id_len
                repe cmpsb
                jnz find_tsr1

find_tsr2:      mov ax,cs
                mov ds,ax
                and dx,dx
                ret

                ALIGN 2

dos_next_block: and dx,dx
                jz next_block4
                dec dx
                jz next_block4
                mov ds,dx
                inc dx
                mov al,ds:[0]
                cmp al,4DH
                jnz next_block3
                add dx,ds:[3]
                jc next_block3
next_block2:    mov ds,dx
                inc dx
                jz next_block4
                mov al,ds:[0]
                cmp al,4DH
                jz next_block4
                cmp al,5AH
                jz next_block4
next_block3:    xor dx,dx
next_block4:    ret

                ALIGN 2

old_umb         DW 0
exit_flags      DB 0
                DB 0

block_init:     mov ax,5802H
                int 21H
                jnc get_umb1
                xor al,al
get_umb1:       xor ah,ah
                mov [old_umb],ax
                or [exit_flags],00000001B
                mov bx,1        ;UMBs are part of DOS allocated memory block chain
                mov ax,5803H
                int 21H

                mov ah,52H
                int 21H
                mov dx,es:[bx-2]
                inc dx
                push dx
                call block_init_s
                pop ax
                jnz block_init1
                xor ax,ax
                mov es,ax
                mov dx,es:[2EH*4+2]
                push dx
                call block_init_s
                pop ax
                jz block_init2
block_init1:    mov [first_block_seg],ax
                clc
                ret
block_init2:    stc
                ret

block_init_s:   mov cx,1024
block_init_s1:  call dos_next_block
                and dx,dx
                jz block_init_s2
                cmp dx,cs:[pspseg]
                loopnz block_init_s1
block_init_s2:  mov ax,cs
                mov ds,ax
                and dx,dx
                ret

                ALIGN 2

sysint24:       sti
                push ds
                push bx
                push ax
sysint24a:      mov ds,cs:[pspseg]
                pushf
                call DWORD PTR ds:[12H]
                pop bx
                mov ah,bh
                pop bx
                pop ds
                and al,al
                jnz sysint24c
                test ah,00100000B
                jnz sysint24e
                mov al,3
sysint24c:      cmp al,1
                jnz sysint24d
                test ah,00010000B
                jnz sysint24e
                mov al,3
sysint24d:      cmp al,3
                jnz sysint24f
                test ah,00001000B
                jz sysint24f
sysint24e:      iret
sysint24f:      jmp prg_quit

;
; Start of program
;
main:           cld
                mov cs:[pspseg],ds      ;Save PSP segment
                mov dx,cs               ;DX=EXE segment
                mov ax,ss               ;AX=STACK segment
                sub ax,dx               ;AX=distance between STACK and EXE
                mov cl,4
                shl ax,cl               ;Distance in bytes
                add ax,sp               ;SP should be added with the distance
                and ax,0FFF0H
                cli
                mov ss,dx
                mov sp,ax
                xor ax,ax
                mov es,ax
                mov di,22H*4
                mov ax,OFFSET sysint22
                stosw
                mov ax,dx
                stosw
                mov ax,OFFSET sysint23
                stosw
                mov ax,dx
                stosw
                mov ax,OFFSET sysint24
                stosw
                mov ax,dx
                stosw
                sti

                mov es,dx
                mov si,80H
                mov di,OFFSET arg_buf
                mov cl,[si]
                add cl,3
                shr cl,1
                xor ch,ch
                rep movsw
                mov ds,dx

                mov si,OFFSET txt_doc_init
                call print

main2:          mov     ah,30H
                int     21H
                cmp     al,3
                jb      main3
                ja      main4
                cmp     ah,1
                jae     main4
main3:          mov     si,OFFSET err_dosver
                jmp     short print_quit_err

main4:          call    block_init
                jnc     main5

main4a:         mov     si,OFFSET err_tsr
                jmp     short print_quit_err

main5:          mov ax,cs
                mov es,ax
                mov bx,[pspseg]
                sub ax,bx
                cmp ax,10H
                jnz main4a
                mov si,OFFSET arg_buf+1
                call jmp_white
                jnc parse1

                mov si,OFFSET txt_doc_usage
                call print
                jmp prg_quit

arg_err:        mov si,OFFSET err_arg

print_quit_err: mov al,0FFH

                call print_err

prg_exit:       push ax
                mov ax,cs
                mov ds,ax
                test [exit_flags],00000001B
                jz prg_exit1
                mov bx,[old_umb]
                mov ax,5803H
                int 21H
prg_exit1:      pop ax
                mov ah,4CH
                int 21H

sysint22:
sysint23:
prg_quit:       mov al,0FFH
                jmp prg_exit

print_exit_ok:  mov ax,cs
                mov ds,ax
                mov es,ax
                call print
                xor al,al
                jmp prg_exit

parse1:         lodsb
                cmp BYTE PTR [si],33
                jnc arg_err
                and al,11011111B        ;Lower to upper case for 'a' to 'z'
                cmp al,'L'
                jz cmd_load
                cmp al,'U'
                jz to_cmd_unload
                cmp al,'N'
                jz cmd_none
                cmp al,'S'
                jz cmd_screen
                cmp al,'F'
                jz cmd_file
                jmp arg_err

to_cmd_unload:  jmp cmd_unload

cmd_load:       call jmp_white
                lodsb
                jc cmd_load_end
                cmp al,'/'
                jz cmd_load1
                cmp al,'-'
                jnz arg_err
cmd_load1:      lodsb
                and al,11011111B        ;Lower to upper case for 'a' to 'z'
                cmp al,'T'
                jnz cmd_load2
                mov [debug_timer],1
                jmp cmd_load
cmd_load2:      cmp al,'S'
                jnz arg_err
                call asc8dec
                jc arg_err
                mov [debug_sep],al
                jmp cmd_load

cmd_load_end:   jmp tsrload

cmd_none:       call jmp_white
                jnc to_arg_err
                call find_tsr
                jz not_loaded
                add dx,8
                mov ds,dx
                mov [debug_mode],0
                mov si,OFFSET txt_deb_none
                jmp print_exit_ok

cmd_screen:     call jmp_white
                jnc to_arg_err
                call find_tsr
                jz not_loaded
                add dx,8
                mov ds,dx
                mov [debug_mode],1
                mov si,OFFSET txt_deb_screen
                jmp print_exit_ok

to_arg_err:     jmp arg_err

cmd_file:       call jmp_white
                jc to_arg_err
                mov di,OFFSET DebFileName
                mov cx,32
                call ascstr
                jc to_arg_err
                call jmp_white
                jnc to_arg_err
                call find_tsr
                jz not_loaded
                mov di,OFFSET DebFileName
                mov si,di
                mov cx,16       ;32/2
                add dx,8
                mov es,dx
                cli
                mov es:[debug_mode],2
                rep movsw
                sti
                mov si,OFFSET txt_deb_file
                jmp print_exit_ok

not_loaded:     mov si,OFFSET err_notload
                jmp print_quit_err

cmd_unload:     call jmp_white
                jnc to_arg_err
                call find_tsr
                jz not_loaded
                push dx
                add dx,8
                mov ds,dx
                mov es,dx
                xor al,al
                xchg al,[debug_timer]
                and al,al
                jz cmd_unload1
                mov bx,OFFSET sysint08us
                call int_term
                jc intrel_err
cmd_unload1:    mov bx,OFFSET fossil
                call int_term
                jc intrel_err
                pop dx
                mov es,dx
                mov ah,49H
                int 21H
                jc free_err
                mov si,OFFSET txt_unload
                jmp print_exit_ok

intrel_err:     mov si,OFFSET err_intrel
                jmp print_quit_err

reload_err:     mov si,OFFSET err_reload
                jmp print_quit_err

free_err:       mov si,OFFSET err_free
                jmp print_quit_err

tsrload:        call find_tsr
                jnz reload_err

                mov es,[pspseg]
                mov es,es:[2CH]
                mov ah,49H
                int 21H
                jc free_err

                xor di,di
                xor si,si
                mov ax,[pspseg]
                add ax,8
                mov es,ax
                mov cx,OFFSET tsr_end
                shr cx,1
                rep movsw
;
; TSR portion moved, do not call functions or access data in TSR portion
; of EXE segment.
;
                mov ds,ax
;
; DS = ES = TSR memory
;

                mov si,OFFSET txt_loaded
                cmp [debug_timer],0
                jz tsrload2

                mov bx,OFFSET sysint08us
                call int_init
tsrload1:       sti
                cmp [ustimer],0
                jz tsrload1
                mov si,OFFSET txt_timeload

tsrload2:       mov bx,OFFSET fossil
                call int_init

                mov ax,cs
                mov ds,ax
                mov es,ax
                call print

                test [exit_flags],00000001B
                jz tsrload3
                and [exit_flags],11111110B
                mov bx,[old_umb]
                mov ax,5803H
                int 21H
tsrload3:       mov ax,OFFSET tsr_end + 15+128  ;Include PSP
                mov cl,4
                shr ax,cl
                cmp ax,10H
                jnc tsrload4
                mov ax,10H
tsrload4:       mov dx,ax
                mov ax,3100H
                int 21H
                jmp prg_quit

PROG            ENDS

DATA            SEGMENT PARA PUBLIC 'DATA'

arg_buf         DB 128 DUP(?)

DATA            ENDS

STACK           SEGMENT PARA STACK 'STACK'

                DB 2048 DUP(?)

STACK           ENDS

                END main