mirror of
https://github.com/Microsoft/MS-DOS.git
synced 2025-08-14 10:47:14 -07:00
MS-DOS v2.0 Release
This commit is contained in:
parent
fce0f75959
commit
80ab2fddfd
156 changed files with 56403 additions and 0 deletions
705
v2.0/source/PROFIL.ASM
Normal file
705
v2.0/source/PROFIL.ASM
Normal file
|
@ -0,0 +1,705 @@
|
|||
TITLE PROFIL - MS-DOS Profile program
|
||||
|
||||
;Profiler for MS-DOS 1.25 2.00
|
||||
;
|
||||
; Lots of stuff stolen from debug.
|
||||
; User provides # of paragraphs per bucket, program is cut up accordingly.
|
||||
; User also specifies clock interval
|
||||
|
||||
|
||||
;System calls
|
||||
PRINTBUF EQU 9
|
||||
SETDMA EQU 26
|
||||
CREATE EQU 22
|
||||
OPEN EQU 15
|
||||
CLOSE EQU 16
|
||||
GETBUF EQU 10
|
||||
BLKWRT EQU 40
|
||||
BLKRD EQU 39
|
||||
OUTCH EQU 2
|
||||
SETBASE EQU 38
|
||||
|
||||
FCB EQU 5CH
|
||||
BUFLEN EQU 80
|
||||
|
||||
; FCB offsets
|
||||
RR EQU 33
|
||||
RECLEN EQU 14
|
||||
FILELEN EQU 16
|
||||
|
||||
|
||||
;Segments in load order
|
||||
|
||||
CODE SEGMENT PUBLIC
|
||||
CODE ENDS
|
||||
|
||||
DATA SEGMENT BYTE
|
||||
DATA ENDS
|
||||
|
||||
INIT SEGMENT BYTE
|
||||
INIT ENDS
|
||||
|
||||
DG GROUP CODE,DATA,INIT
|
||||
|
||||
;The data segment
|
||||
|
||||
DATA SEGMENT BYTE
|
||||
ORG 0
|
||||
ENDMES DB 13,10,"Program terminated normally",13,10,"$"
|
||||
ABORTMES DB 13,10,"Program aborted",13,10,"$"
|
||||
TOOBIG DB "Program too big",13,10,"$"
|
||||
EXEBAD DB "EXE file bad",13,10,"$"
|
||||
|
||||
OUT_FCB LABEL WORD
|
||||
DB 0
|
||||
OUTNAME DB " PRF"
|
||||
DB 30 DUP(0)
|
||||
|
||||
DB 80H DUP(?)
|
||||
STACK LABEL WORD
|
||||
|
||||
BYTEBUF DB BUFLEN DUP(?) ;Processed input queue
|
||||
AXSAVE DW ? ;See interrupt routine
|
||||
BXSAVE DW ? ; " " "
|
||||
PROG_AREA DW ? ;Segment of program start
|
||||
|
||||
;EXE file header
|
||||
RUNVAR LABEL WORD
|
||||
RELPT DW ?
|
||||
LASTP LABEL WORD
|
||||
RELSEG DW ?
|
||||
PSIZE LABEL WORD
|
||||
PAGES DW ?
|
||||
RELCNT DW ?
|
||||
HEADSIZ DW ?
|
||||
DW ?
|
||||
LOADLOW DW ?
|
||||
PROG_SS LABEL WORD ;Program stack seg
|
||||
INITSS DW ?
|
||||
PROG_SP LABEL WORD ;Program SP
|
||||
INITSP DW ?
|
||||
DW ?
|
||||
PROG_ENTRY EQU THIS DWORD
|
||||
PROG_RA LABEL WORD ;Program start offset
|
||||
INITIP DW ?
|
||||
PROG_SA LABEL WORD ;Program start segment (may be different from PROG_AREA)
|
||||
INITCS DW ?
|
||||
RELTAB DW ?
|
||||
RUNVARSIZ EQU $-RUNVAR
|
||||
|
||||
EXEFILE DB 0 ;Flag to indicate EXE file
|
||||
DRV_VALID DW ? ;Init for AX register
|
||||
OUTPUT_DATA LABEL WORD ;Start of the profile data
|
||||
CLOCK_GRAIN DW ? ;Clock interval micro-seconds
|
||||
BUCKET_NUM DW ? ;Number of buckets
|
||||
BUCKET_SIZE DW ? ;Paragraphs per bucket
|
||||
PROG_LOW_PA DW ? ;Start of program (PARA #)
|
||||
PROG_HIGH_PA DW ? ;End of program (PARA #)
|
||||
DOS_PA DW ? ;IO-DOS PARA boundry
|
||||
HIT_IO DW 0 ;IO bucket
|
||||
HIT_DOS DW 0 ;DOS bucket
|
||||
HIT_HIGH DW 0 ;Above Program bucket
|
||||
NUM_DATA_WORDS EQU ($-OUTPUT_DATA)/2 ;Number of word items
|
||||
BUCKET LABEL WORD ;Bucket count area
|
||||
|
||||
;The following data will be overwritten when the buckets are initialized
|
||||
LINEBUF DB BUFLEN,1,0DH ;Raw input buffer
|
||||
DB BUFLEN DUP(?)
|
||||
|
||||
NOFILE DB "File not found",13,10,"$"
|
||||
OUTERR DB "Cannot open output file",13,10,"$"
|
||||
GRAIN_PROMPT DB "Sample time (micro-sec) >= 60 ? ","$"
|
||||
SIZE_PROMPT DB "Number of paragraphs (16 bytes) per bucket? ","$"
|
||||
PARAM_PROMPT DB "Parameters to program? ","$"
|
||||
DATA ENDS
|
||||
|
||||
;The resident code portion
|
||||
CODE SEGMENT PUBLIC
|
||||
ASSUME CS:DG,DS:DG,ES:DG,SS:DG
|
||||
|
||||
;The clock interrupt routine
|
||||
PUBLIC CLK_INTER
|
||||
|
||||
;Stuff provided by external clock handler routine
|
||||
EXTRN CLOCKON:NEAR,CLOCKOFF:NEAR,LEAVE_INT:NEAR
|
||||
|
||||
ORG 100H
|
||||
START:
|
||||
CLD
|
||||
MOV SP,OFFSET DG:STACK ;Use internal stack
|
||||
CALL SETUP
|
||||
;The following setup stuff cannot be done in SETUP because we're probably
|
||||
; overwritting the INIT area
|
||||
MOV DX,[PROG_AREA]
|
||||
MOV AH,SETBASE
|
||||
INT 21H ;Set base for program
|
||||
MOV ES,[PROG_AREA]
|
||||
PUSH SI ;Points to BYTEBUF
|
||||
MOV DI,81H ;Set unformatted params
|
||||
COMTAIL:
|
||||
LODSB
|
||||
STOSB
|
||||
CMP AL,13
|
||||
JNZ COMTAIL
|
||||
SUB DI,82H ;Figure length
|
||||
XCHG AX,DI
|
||||
MOV BYTE PTR ES:[80H],AL
|
||||
POP SI
|
||||
MOV DI,FCB ;First param
|
||||
MOV AX,2901H
|
||||
INT 21H
|
||||
MOV BYTE PTR [DRV_VALID],AL
|
||||
MOV AX,2901H
|
||||
MOV DI,6CH ;Second param
|
||||
INT 21H
|
||||
MOV BYTE PTR [DRV_VALID+1],AL
|
||||
|
||||
MOV AX,ES ;Prog segment to AX
|
||||
MOV DX,[PROG_RA] ;Offset
|
||||
CMP [EXEFILE],1
|
||||
JZ EXELOAD ;EXE file
|
||||
JMP BINFIL ;Regular file (.COM)
|
||||
|
||||
EXELOAD:
|
||||
MOV AX,[HEADSIZ] ;Size of header in paragraphs
|
||||
ADD AX,31
|
||||
MOV CL,4
|
||||
ROL AX,CL ;Size in bytes
|
||||
MOV BX,AX
|
||||
AND AX,0FE00H
|
||||
AND BX,0FH
|
||||
MOV WORD PTR DS:[FCB+RR],AX ;Position in file of program
|
||||
MOV WORD PTR DS:[FCB+RR+2],BX ;Record size
|
||||
MOV DX,[PAGES] ;Size in 512 byte blocks
|
||||
DEC DX
|
||||
XCHG DH,DL
|
||||
ROL DX,1
|
||||
MOV DI,DX
|
||||
MOV SI,DX
|
||||
AND DI,0FE00H
|
||||
AND SI,1FFH
|
||||
SUB DI,AX
|
||||
SBB SI,BX
|
||||
MOV AX,[LASTP]
|
||||
OR AX,AX
|
||||
JNZ PARTP
|
||||
MOV AX,200H
|
||||
PARTP:
|
||||
ADD DI,AX
|
||||
ADC SI,0
|
||||
MOV AX,DI
|
||||
ADD AX,15
|
||||
AND AL,0F0H
|
||||
OR AX,SI
|
||||
MOV CL,4
|
||||
ROR AX,CL
|
||||
XCHG AX,CX
|
||||
MOV BX,[PROG_AREA]
|
||||
ADD BX,10H
|
||||
MOV AX,WORD PTR DS:[2]
|
||||
SUB AX,CX
|
||||
MOV DX,OFFSET DG:TOOBIG
|
||||
JB ERROR
|
||||
CMP BX,AX
|
||||
JA ERROR
|
||||
CMP [LOADLOW],-1
|
||||
JNZ LOADEXE
|
||||
XCHG AX,BX
|
||||
LOADEXE:
|
||||
MOV BP,AX
|
||||
XOR DX,DX
|
||||
CALL READ
|
||||
JC HAVEXE
|
||||
BADEXE:
|
||||
MOV DX,OFFSET DG:EXEBAD
|
||||
|
||||
ERROR:
|
||||
MOV AH,PRINTBUF ;Print the message in DX
|
||||
INT 21H
|
||||
INT 20H ;Exit
|
||||
|
||||
HAVEXE:
|
||||
MOV AX,[RELTAB] ;Get position of relocation table
|
||||
MOV WORD PTR DS:[FCB+RR],AX
|
||||
MOV WORD PTR DS:[FCB+RR+2],0
|
||||
MOV DX,OFFSET DG:RELPT ;Four byte buffer
|
||||
MOV AH,SETDMA
|
||||
INT 21H
|
||||
CMP [RELCNT],0
|
||||
JZ NOREL
|
||||
RELOC:
|
||||
MOV AH,BLKRD
|
||||
MOV DX,FCB
|
||||
MOV CX,4
|
||||
INT 21H ;Read in one relocation pointer
|
||||
OR AL,AL
|
||||
JNZ BADEXE
|
||||
MOV DI,[RELPT] ;Pointer offset
|
||||
MOV AX,[RELSEG] ;pointer segment
|
||||
ADD AX,BP ;Bias with actual load segment
|
||||
MOV ES,AX
|
||||
ADD ES:[DI],BP ;Relocate
|
||||
DEC [RELCNT]
|
||||
JNZ RELOC
|
||||
|
||||
NOREL:
|
||||
ADD [INITSS],BP
|
||||
ADD [INITCS],BP
|
||||
JMP SHORT PROGGO
|
||||
|
||||
BINFIL:
|
||||
MOV WORD PTR DS:[FCB+RECLEN],1
|
||||
MOV SI,-1
|
||||
MOV DI,SI
|
||||
CALL READ
|
||||
MOV ES,[PROG_SA] ;Prog segment to ES
|
||||
MOV AX,WORD PTR ES:[6]
|
||||
MOV [PROG_SP],AX ;Default SP for non EXE files
|
||||
DEC AH
|
||||
MOV WORD PTR ES:[6],AX ;Fix size
|
||||
|
||||
PROGGO:
|
||||
PUSH DS
|
||||
MOV AX,[PROG_AREA]
|
||||
MOV DS,AX
|
||||
MOV DX,80H
|
||||
MOV AH,SETDMA
|
||||
INT 21H ;Set default disk transfer address
|
||||
POP DS
|
||||
MOV BX,[BUCKET_NUM]
|
||||
SHL BX,1 ;Mult by 2 to get #bytes in bucket area
|
||||
CLEAR:
|
||||
MOV BUCKET[BX],0 ;Zero counts
|
||||
SUB BX,2
|
||||
JGE CLEAR
|
||||
MOV DX,[CLOCK_GRAIN]
|
||||
PUSH DS
|
||||
POP ES
|
||||
CLI ;Don't collect data yet
|
||||
CALL CLOCKON ;Set the interrupt
|
||||
MOV SI,[PROG_RA]
|
||||
MOV DI,[PROG_AREA]
|
||||
MOV BX,[PROG_SS]
|
||||
MOV CX,[PROG_SP]
|
||||
MOV AX,[DRV_VALID]
|
||||
MOV DX,[PROG_SA]
|
||||
MOV SS,BX
|
||||
MOV SP,CX
|
||||
XOR CX,CX
|
||||
PUSH CX ;0 on prog stack
|
||||
PUSH DX
|
||||
PUSH SI
|
||||
MOV DS,DI ;Set up segments
|
||||
MOV ES,DI
|
||||
STI ;Start collecting data
|
||||
XXX PROC FAR
|
||||
RET ;Hop to program
|
||||
XXX ENDP
|
||||
|
||||
READ:
|
||||
; AX:DX is disk transfer address (segment:offset)
|
||||
; SI:DI is 32 bit length
|
||||
|
||||
RDLOOP:
|
||||
MOV BX,DX
|
||||
AND DX,000FH
|
||||
MOV CL,4
|
||||
SHR BX,CL
|
||||
ADD AX,BX
|
||||
PUSH AX
|
||||
PUSH DX
|
||||
PUSH DS
|
||||
MOV DS,AX
|
||||
MOV AH,SETDMA
|
||||
INT 21H
|
||||
POP DS
|
||||
MOV DX,FCB
|
||||
MOV CX,0FFF0H ;Keep request in segment
|
||||
OR SI,SI ;Need > 64K?
|
||||
JNZ BIGRD
|
||||
MOV CX,DI ;Limit to amount requested
|
||||
BIGRD:
|
||||
MOV AH,BLKRD
|
||||
INT 21H
|
||||
SUB DI,CX ;Subtract off amount done
|
||||
SBB SI,0 ;Ripple carry
|
||||
CMP AL,1 ;EOF?
|
||||
POP DX
|
||||
POP AX ;Restore transfer address
|
||||
JZ RET10
|
||||
ADD DX,CX ;Bump transfer address by last read
|
||||
MOV BX,SI
|
||||
OR BX,DI ;Finished with request
|
||||
JNZ RDLOOP
|
||||
RET10: STC
|
||||
RET
|
||||
|
||||
|
||||
;Return here on termination or abort
|
||||
|
||||
TERMINATE:
|
||||
CLI ;Stop collecting data
|
||||
MOV DX,OFFSET DG:ENDMES
|
||||
JMP SHORT WRITEOUT
|
||||
ABORT:
|
||||
CLI ;Stop collecting data
|
||||
MOV DX,OFFSET DG:ABORTMES
|
||||
WRITEOUT:
|
||||
MOV AX,CS
|
||||
MOV DS,AX
|
||||
MOV SS,AX
|
||||
MOV SP,OFFSET DG:STACK ;Use internal stack
|
||||
PUSH DX
|
||||
CALL CLOCKOFF ;Restore original clock routine
|
||||
STI ;Back to normal clock
|
||||
POP DX
|
||||
MOV AH,PRINTBUF
|
||||
INT 21H ;Apropriate termination message
|
||||
MOV [OUT_FCB+14],2 ;Word size records
|
||||
MOV DX,OFFSET DG:OUTPUT_DATA
|
||||
MOV AH,SETDMA
|
||||
INT 21H ;Set the transfer address
|
||||
MOV CX,NUM_DATA_WORDS
|
||||
ADD CX,[BUCKET_NUM]
|
||||
MOV DX,OFFSET DG:OUT_FCB
|
||||
MOV AH,BLKWRT
|
||||
INT 21H ;Write out data
|
||||
MOV DX,OFFSET DG:OUT_FCB
|
||||
MOV AH,CLOSE
|
||||
INT 21H
|
||||
INT 20H ;Exit
|
||||
|
||||
|
||||
;The clock interrupt routine
|
||||
CLK_INTER PROC NEAR
|
||||
CLI
|
||||
PUSH DS
|
||||
PUSH CS
|
||||
POP DS ;Get profile segment
|
||||
MOV [AXSAVE],AX
|
||||
MOV [BXSAVE],BX
|
||||
POP AX ;old DS
|
||||
MOV BX,OFFSET DG:LEAVE_INT
|
||||
PUSH BX
|
||||
PUSH AX
|
||||
PUSH ES
|
||||
PUSH [AXSAVE]
|
||||
PUSH [BXSAVE]
|
||||
PUSH CX
|
||||
PUSH DX
|
||||
|
||||
|
||||
;Stack looks like this
|
||||
;
|
||||
; +18 OLDFLAGS
|
||||
; +16 OLDCS
|
||||
; +14 OLDIP
|
||||
; +12 RETURN TO LEAVE_INT
|
||||
; +10 OLDDS
|
||||
; +8 OLDES
|
||||
; +6 OLDAX
|
||||
; +4 OLDBX
|
||||
; +2 OLDCX
|
||||
;SP-> OLDDX
|
||||
|
||||
MOV BX,SP
|
||||
LES BX,DWORD PTR SS:[BX+14] ;Get CS:IP
|
||||
MOV AX,BX
|
||||
MOV CL,4
|
||||
SHR AX,CL
|
||||
MOV CX,ES
|
||||
ADD AX,CX ;Paragraph of CS:IP
|
||||
CMP AX,[DOS_PA] ;Below DOS?
|
||||
JB IOHIT
|
||||
CMP AX,[PROG_LOW_PA] ;Below program?
|
||||
JB DOSHIT
|
||||
CMP AX,[PROG_HIGH_PA] ;Above program?
|
||||
JAE MISSH
|
||||
|
||||
SUB AX,[PROG_LOW_PA] ;Paragraph offset
|
||||
XOR DX,DX
|
||||
|
||||
DIV [BUCKET_SIZE]
|
||||
MOV BX,AX
|
||||
SHL BX,1 ;Mult by 2 to get byte offset
|
||||
INC BUCKET[BX]
|
||||
JMP SHORT DONE
|
||||
|
||||
IOHIT:
|
||||
INC [HIT_IO]
|
||||
JMP SHORT DONE
|
||||
|
||||
DOSHIT:
|
||||
INC [HIT_DOS]
|
||||
JMP SHORT DONE
|
||||
|
||||
MISSH:
|
||||
INC [HIT_HIGH]
|
||||
|
||||
DONE:
|
||||
POP DX
|
||||
POP CX
|
||||
POP BX
|
||||
POP AX
|
||||
POP ES
|
||||
POP DS
|
||||
STI
|
||||
RET ;To LEAVE_INT
|
||||
|
||||
CLK_INTER ENDP
|
||||
|
||||
CODE ENDS
|
||||
|
||||
;The init segment contains code to process input parameters
|
||||
; It will be blasted as soon as the program to be run is read in
|
||||
; And/or the bucket area is initialized
|
||||
|
||||
INIT SEGMENT BYTE
|
||||
ORG 0
|
||||
|
||||
SETUP:
|
||||
MOV DX,FCB
|
||||
MOV AH,OPEN
|
||||
INT 21H ;Open program file
|
||||
AND AL,AL
|
||||
JZ OPENOK
|
||||
MOV DX,OFFSET DG:NOFILE
|
||||
JMP ERROR
|
||||
|
||||
OPENOK:
|
||||
XOR BX,BX
|
||||
MOV WORD PTR DS:[FCB+RR],BX
|
||||
MOV WORD PTR DS:[FCB+RR+2],BX ;RR to 0
|
||||
MOV SI,FCB
|
||||
MOV DI,OFFSET DG:OUT_FCB
|
||||
MOV CX,4
|
||||
REP MOVSW
|
||||
MOVSB ;Transfer drive spec and file to output
|
||||
MOV DX,OFFSET DG:OUT_FCB
|
||||
MOV AH,CREATE
|
||||
INT 21H ;Try to create the output file
|
||||
AND AL,AL
|
||||
JZ GETSIZE
|
||||
MOV DX,OFFSET DG:OUTERR
|
||||
JMP ERROR
|
||||
|
||||
GETSIZE: ;Get bucket size
|
||||
MOV DX,OFFSET DG:SIZE_PROMPT
|
||||
MOV AH,PRINTBUF
|
||||
INT 21H
|
||||
CALL INBUF
|
||||
CALL SCANB
|
||||
JZ GETSIZE ;SCANB went to CR
|
||||
XOR BX,BX
|
||||
INC BX ;Size >=1
|
||||
CALL GETNUM
|
||||
JC GETSIZE ;Bad number
|
||||
MOV [BUCKET_SIZE],DX
|
||||
|
||||
CMP WORD PTR DS:[FCB+9],5800H+"E" ;"EX"
|
||||
JNZ NOTEXE
|
||||
CMP BYTE PTR DS:[FCB+11],"E"
|
||||
JNZ NOTEXE
|
||||
|
||||
LOADEXEHEAD: ;Load the EXE header
|
||||
MOV [EXEFILE],1
|
||||
MOV DX,OFFSET DG:RUNVAR ;Read header in here
|
||||
MOV AH,SETDMA
|
||||
INT 21H
|
||||
MOV CX,RUNVARSIZ
|
||||
MOV DX,FCB
|
||||
MOV WORD PTR DS:[FCB+RECLEN],1
|
||||
OR AL,AL
|
||||
MOV AH,BLKRD
|
||||
INT 21H
|
||||
CMP [RELPT],5A4DH ;Magic number
|
||||
JZ EXEOK
|
||||
JMP BADEXE
|
||||
EXEOK:
|
||||
MOV AX,[PAGES] ;Size of file in 512 byte blocks
|
||||
MOV CL,5
|
||||
SHL AX,CL ;Size in paragraphs
|
||||
JMP SHORT SETBUCKET
|
||||
|
||||
NOTEXE:
|
||||
MOV AX,WORD PTR DS:[FCB+FILELEN]
|
||||
MOV DX,WORD PTR DS:[FCB+FILELEN+2] ;Size of file in bytes DX:AX
|
||||
ADD AX,15
|
||||
ADC DX,0 ;Round to PARA
|
||||
MOV CL,4
|
||||
SHR AX,CL
|
||||
AND AX,0FFFH
|
||||
MOV CL,12
|
||||
SHL DX,CL
|
||||
AND DX,0F000H
|
||||
OR AX,DX ;Size in paragraphs to AX
|
||||
MOV [PROG_RA],100H ;Default offset
|
||||
|
||||
SETBUCKET:
|
||||
PUSH AX ;Save size
|
||||
XOR DX,DX
|
||||
DIV [BUCKET_SIZE]
|
||||
INC AX ;Round up
|
||||
MOV [BUCKET_NUM],AX
|
||||
MOV BX,OFFSET DG:BUCKET
|
||||
SHL AX,1 ;Number of bytes in bucket area
|
||||
ADD AX,BX ;Size of profil in bytes
|
||||
ADD AX,15 ;Round up to PARA boundry
|
||||
MOV CL,4
|
||||
SHR AX,CL ;Number of paragraphs in profil
|
||||
INC AX ;Insurance
|
||||
MOV BX,CS
|
||||
ADD AX,BX
|
||||
MOV [PROG_AREA],AX
|
||||
|
||||
CMP [EXEFILE],1
|
||||
JZ SETBOUNDS
|
||||
MOV AX,[PROG_AREA] ;Set up .COM segments
|
||||
MOV [PROG_SS],AX
|
||||
MOV [PROG_SA],AX
|
||||
|
||||
SETBOUNDS: ;Set the sample window
|
||||
MOV BX,10H ;Get start offset
|
||||
ADD BX,[PROG_AREA] ;PARA # of start
|
||||
MOV [PROG_LOW_PA],BX
|
||||
POP AX ;Recall size of PROG in paragraphs
|
||||
ADD BX,AX
|
||||
MOV [PROG_HIGH_PA],BX
|
||||
|
||||
SETDOS:
|
||||
XOR DX,DX
|
||||
MOV ES,DX ;look in interrupt area
|
||||
MOV DX,WORD PTR ES:[82H] ;From int #20
|
||||
MOV [DOS_PA],DX
|
||||
PUSH DS
|
||||
POP ES
|
||||
|
||||
GETGRAIN: ;Get sample interval
|
||||
MOV DX,OFFSET DG:GRAIN_PROMPT
|
||||
MOV AH,PRINTBUF
|
||||
INT 21H
|
||||
CALL INBUF
|
||||
CALL SCANB
|
||||
JZ GETGRAIN ;SCANB went to CR
|
||||
MOV BX,60 ;Grain >=60
|
||||
CALL GETNUM
|
||||
JC GETGRAIN ;Bad number
|
||||
MOV [CLOCK_GRAIN],DX
|
||||
|
||||
MOV DX,OFFSET DG:PARAM_PROMPT
|
||||
MOV AH,PRINTBUF
|
||||
INT 21H
|
||||
CALL INBUF ;Get program parameters
|
||||
|
||||
MOV AX,2522H ;Set vector 22H
|
||||
MOV DX,OFFSET DG:TERMINATE
|
||||
INT 21H
|
||||
MOV AL,23H ;Set vector 23H
|
||||
MOV DX,OFFSET DG:ABORT
|
||||
INT 21H
|
||||
RET ;Back to resident code
|
||||
|
||||
GETNUM: ;Get a number, DS:SI points to buffer, carry set if bad
|
||||
XOR DX,DX
|
||||
MOV CL,0
|
||||
LODSB
|
||||
NUMLP:
|
||||
SUB AL,"0"
|
||||
JB NUMCHK
|
||||
CMP AL,9
|
||||
JA NUMCHK
|
||||
CMP DX,6553
|
||||
JAE BADNUM
|
||||
MOV CL,1
|
||||
PUSH BX
|
||||
MOV BX,DX
|
||||
SHL DX,1
|
||||
SHL DX,1
|
||||
ADD DX,BX
|
||||
SHL DX,1
|
||||
CBW
|
||||
POP BX
|
||||
ADD DX,AX
|
||||
LODSB
|
||||
JMP NUMLP
|
||||
NUMCHK:
|
||||
CMP CL,0
|
||||
JZ BADNUM
|
||||
CMP BX,DX
|
||||
JA BADNUM
|
||||
CLC
|
||||
RET
|
||||
BADNUM:
|
||||
STC
|
||||
RET
|
||||
|
||||
INBUF: ;Read in from console, SI points to start on exit
|
||||
MOV AH,GETBUF
|
||||
MOV DX,OFFSET DG:LINEBUF
|
||||
INT 21H
|
||||
MOV SI,2 + OFFSET DG:LINEBUF
|
||||
MOV DI,OFFSET DG:BYTEBUF
|
||||
CASECHK:
|
||||
LODSB
|
||||
CMP AL,'a'
|
||||
JB NOCONV
|
||||
CMP AL,'z'
|
||||
JA NOCONV
|
||||
ADD AL,"A"-"a" ;Convert to upper case
|
||||
NOCONV:
|
||||
STOSB
|
||||
CMP AL,13
|
||||
JZ INDONE
|
||||
CMP AL,'"'
|
||||
JNZ QUOTSCAN
|
||||
CMP AL,"'"
|
||||
JNZ CASECHK
|
||||
QUOTSCAN:
|
||||
MOV AH,AL
|
||||
KILLSTR:
|
||||
LODSB
|
||||
STOSB
|
||||
CMP AL,13
|
||||
JZ INDONE
|
||||
CMP AL,AH
|
||||
JNZ KILLSTR
|
||||
JMP SHORT CASECHK
|
||||
|
||||
INDONE:
|
||||
MOV SI,OFFSET DG:BYTEBUF
|
||||
|
||||
;Output CR/LF
|
||||
|
||||
CRLF:
|
||||
MOV AL,13
|
||||
CALL OUT
|
||||
MOV AL,10
|
||||
|
||||
OUT:
|
||||
PUSH AX
|
||||
PUSH DX
|
||||
AND AL,7FH
|
||||
XCHG AX,DX
|
||||
MOV AH,OUTCH
|
||||
INT 21H
|
||||
POP DX
|
||||
POP AX
|
||||
RET
|
||||
|
||||
SCANB: ;Scan to first non-blank
|
||||
PUSH AX
|
||||
SCANNEXT:
|
||||
LODSB
|
||||
CMP AL," "
|
||||
JZ SCANNEXT
|
||||
CMP AL,9
|
||||
JZ SCANNEXT
|
||||
DEC SI
|
||||
POP AX
|
||||
EOLCHK:
|
||||
CMP BYTE PTR[SI],13
|
||||
RET
|
||||
|
||||
INIT ENDS
|
||||
END START
|
||||
|