home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
sampler0
/
hiload.asm
< prev
next >
Wrap
Assembly Source File
|
1990-06-18
|
22KB
|
895 lines
; This is version 1.01 of HILOAD
;
; See accompanying .DOC file for theory of
; operation and instructions
;
; No guarantees, but the author would appreciate
; information on bugs.
;
; Larry Shannon 18 Jun 89
;
; Equates
;
CR EQU 0D
LF EQU 0A
SPACE EQU 020
MON EQU MOV ; Common typo
ONE EQU 1
TWO EQU 2
DOLLAR EQU 024
ZERO EQU 0
BELL EQU 07
;.....
;
; Macros
;
PRINT MACRO ; Usage: print MSG1
PUSH AX ; All registers preserved
PUSH DX
MOV AH,9
LEA DX, #1
INT 021
POP DX
POP AX
#EM
;
PRINT$ MACRO ; Usage: print$,"MESSAGE"
PUSH AX ; Prints at current cursor position
PUSH DX
JMP >M1
M0:
DB #1
DB "$"
M1:
MOV AH,9 ; All registers preserved
LEA DX,M0
INT 021
POP DX
POP AX
#EM
;
QUIT MACRO ; Usage: quit 0
MOV AH,04C ; Must give some value
MOV AL,#1
INT 021
#EM
;
NEWLINE MACRO ; Equivalent to CR,LF
PUSH AX ; Scrolls if off screen
PUSH DX
JMP > M1
M0:
DB 0D,0A,'$'
M1:
LEA DX,M0
MOV AH,9
INT 021
POP DX
POP AX
#EM
;
SPLIT MACRO AAM 16 #EM ; Be careful with these with
; ; Nec v-20/v-30 chips!
UNSPLIT MACRO ; This macro will effectively
PUSH CX ; Do the same thing, and should be
MOV CX,4 ; Compatible with all pc's
ROL AH,CL
AND AH,0F0
OR AL,AH
POP CX
#EM
;
HEX_TO_PRNT MACRO ; Changes an 8-bit register quantity
OR #1,030 ; From 0-f to the ascii equivalent
CMP #1,039 ; Register must be in form 00 to 0f
;
IF A ADD #1,7
#EM
;
PRINT_REG MACRO ; Used to print a register (or any 16-bit
JMP > M1 ; Quantity) at the current cursor position
M0:
DB 5 DUP ('$')
M1:
PUSH AX ; Usage - print_reg AX
MOV AX,#1 ; Prints the 16-bit quantity in hex
XCHG AH,AL
PUSH AX
MAKE_HEX_ASCII
XCHG AH,AL
MOV W[M0],AX
POP AX
XCHG AH,AL
MAKE_HEX_ASCII
XCHG AH,AL
MOV W[M0+2],AX
PRINT M0
POP AX
#EM
;
PRINT_32_DEC MACRO ; Macro to print a 32-bit hex number
PUSH AX ; As a decimal string
PUSH DX ; Enter with si pointing to two-word
PUSH DI ; (four byte) quantity to be converted
MOV DX,W[SI] ; Most significant word first
MOV AX,W[SI+2] ; Prints at current cursor position
JMP > M1 ; All registers restored
M0:
DB 11 DUP ('$')
M1:
LEA DI,M0
ADD DI,9
CALL LARGE_HEX_TO_ASCII
MOV DX,DI
MOV AH,9
INT 021
POP DI
POP DX
POP AX
#EM
;
REG_TO_PRINT MACRO ; Converts a 16-bit quantity to ascii
PUSH AX ; And puts the resultant string in a
PUSH BX ; Place pointed to by ds:si
MOV BX,#1 ; All registers restored
MOV AL,BH
CALL HEX2PRNT
MOV [SI],AX
MOV AL,BL
CALL HEX2PRNT
MOV [SI+2],AX
POP BX
POP AX
#EM
;
MAKE_CAP MACRO ; Makes letters capitals
CMP #1,061 ; Useage make_cap AH
JB > M1 ; Ah contains a candidate ascii letter
CMP #1,07A ; From A-Z or a-z
JA > M1 ; Returns A-Z
AND #1,0DF
M1:
NOP
#EM
;
MAKE_HEX_ASCII MACRO ; Makes al in hex into two ascii
SPLIT ; Characters in ah:al
HEX_TO_PRNT AH
HEX_TO_PRNT AL
#EM
;.....
;
; Data and strings
;
;
ORG 0100
;
;
HILOAD: JMP LONG > L0
LOAD_BLOCK DW 0,0
FILE_STRING DB 65 DUP('$')
TAIL_PTR DW 0
FILE_PTR DW 0
OLD_INT_27 DW 0,0
OLD_INT_21 DW 0,0
START_ADDR DW 0100,0
TAIL_BFR DB 127 DUP ('020')
SW2127 DB 0
TEMPWRDS DW 0,0
BAR DB 40 DUP ('*'),'$'
RESET_MSG DB CR,LF,'Resetting ICA area',CR,LF,'$'
DEFAULT_ENV DB 'HILOAD',0
INT_MSG DB 'Interupt '
INT_NUM DB 0,0,'H is now located at '
INT_SEG DB 0,0,0,0,':'
INT_OFF DB 0,0,0,0,CR,LF,'$'
TEMP DW 0
LOAD_POINT DW 0,0
LP_PLUS_BYTES DW 0,0
INT_ADDR_1 DW 0
INT_ADDR_2 DW 0
;
NEW_INT21:
CMP AH,031 ; New address for int 21h
JE > Z21 ; Is it TSR termination?
CMP AX,02521 ; Setting vector for int 21h?
JE > Z25 ; If so, save it
CMP AX,03521 ; Request for int 21h address?
JE > Z35 ; If so, give him original address
CS JMP D[OLD_INT_21] ; Otherwise, do real int 21h
Z25:
CS MOV OLD_INT_21,DX ; Here we save int 21h address info
CS MOV OLD_INT_21+2,DS
IRET ; And return to caller
Z35:
CS MOV BX,[OLD_INT_21] ; Here we give him original address
CS MOV ES,[OLD_INT_21+2]
IRET ; And return to caller
Z21:
CS MOV SW2127,0 ; Exiting via int 21 - set switch for
JMP > Z22 ; Storage return handling
;.....
;
NEW_INT27:
CS MOV SW2127,1 ; Trap for int 27h - set switch
Z22:
MOV AX,CS ; Get our code segment
MOV BX,DX ; Save return size info
MOV DS,AX ; Set up local addressability
MOV ES,AX ; Make sure other registers are
MOV SS,AX ; What they should be
MOV DX,[OLD_INT_27] ; Find original address of int 27h
MOV AX,[OLD_INT_27+2] ; Segment portion
MOV ES,0 ; Addressing bottom page
ES MOV W[09C],DX ; Store vector addresses directly
ES MOV W[09E],AX ; Since int 21h cannot be used to do
MOV DX,[OLD_INT_21] ; The job - we've trapped it above!
MOV AX,[OLD_INT_21 + 2] ; Do the same with int 21h
MOV ES,0
ES MOV W[084],DX ; And store its address in the
ES MOV W[086],AX ; Proper place in the table
NEWLINE ; Space a line
PRINT$ 'Saved bytes = ' ; Start of message
CMP SW2127,1 ; See how we terminated; 1=int 27h so
JE > Q2 ; Returns bytes - int 21h returns para-
MOV AX,BX ; Graphs - here we're converting
XOR DX,DX ; Paragraphs to bytes by multiplying
MOV CX,4 ; By 4 (shift left 4 places)
Q1:
RCL AX,1 ; Have to allow for greater than 64k
PUSHF ; Save flags with state of carry bit
ROL DX,1
POPF ; Get flags back
ADC DX,0 ; Add in and include carry
LOOP Q1 ; Carry on
JMP > Q3
Q2:
MOV AX,BX ; Size info in bx - do setup for
XOR DX,DX ; Conversion
Q3:
MOV TEMPWRDS,DX ; Temporarily store upper and lower
MOV TEMPWRDS + 2,AX ; Halves of return size info (32 bits)
PUSH DX ; Save dx
MOV DX,[LOAD_POINT] ; Get where we started
MOV LP_PLUS_BYTES,DX ; Put it here
POP DX ; Retrieve dx
ADD LP_PLUS_BYTES,DX ; Add size info
MOV LP_PLUS_BYTES+2,AX ; Store upper half here
LEA SI,TEMPWRDS ; Point to temporary storage
PRINT_32_DEC ; Print out size in bytes
NEWLINE ; Do new line
MOV DX,[TEMPWRDS] ; Get back size info
MOV AX,[TEMPWRDS+2]
CLC ; Clear the carry
MOV CX,4 ; We're going to convert to a 32-bit
Q7:
SHR DX,1 ; Number here and store it in
PUSHF ; The ica area
RCR AX,1
POPF
LOOP Q7
MOV ES,040 ; Point to segment of ica
ES MOV BX,[0F0] ; Get what was there
ADD DX,BX ; Add new size
ES MOV [0F0],DX ; And put it back
ES MOV BX,[0F2] ; Get old lower half
ADD AX,BX ; Add new bytes saved data
INC AX ; Allow for truncation
ES MOV [0F2],AX ; And put it back
NEWLINE ; Start of trap info
PRINT$ 'This TSR traps the following interrupts:'
NEWLINE ; Some spaces
NEWLINE
;
; Here is where we look to see what interrupts are trapped
;
MOV CX,0FF ; Look at 256 interrupts
MOV AX,03500 ; Set up call
H1:
PUSH CX ; Save registers
PUSH AX
INT 021 ; Get interrupt addresses
MOV AX,BX ; Ax is offset
MOV DX,ES ; Dx:ax is addr of interrupt
MOV INT_ADDR_1,AX ; Store offset away
MOV INT_ADDR_2,DX ; Store segment
CALL ADD_SEG_OFF ; Convert to 32-bit number
XCHG BX,DX ; Now bx:cx is int addr
XCHG CX,AX ; In 32-bit form
MOV DX,[LOAD_POINT] ; Where do we start
XOR AX,AX ; No offset from start
CALL ADD_SEG_OFF ; Make 32-bitter
CALL CMP_32 ; Is int address beyond start point?
JNC > H2 ; If below, can't be us - get out
MOV DX,[LP_PLUS_BYTES]
MOV AX,[LP_PLUS_BYTES + 2] ; Dx:ax now address of end of pgm
CALL ADD_SEG_OFF ; Make 32-bits
CALL CMP_32 ; Compare them
JC > H2 ; If greater - beyond me
POP AX ; We got one - retrieve interrupt
PUSH AX ; And save function and int number
CALL HEX2PRNT ; Get interrupt number in ascii
LEA SI,INT_NUM ; Point to proper place
MOV W[SI],AX ; Store it
LEA SI,INT_SEG ; Point to place
REG_TO_PRINT [INT_ADDR_2] ; Get segment in ascii
LEA SI,INT_OFF ; Point to place
REG_TO_PRINT [INT_ADDR_1] ; Print offset in ascii
PRINT INT_MSG ; Print whole message
H2:
POP AX ; Get registers back
INC AX
POP CX
DEC CX
JCXZ > H3 ; Are we done?
JMP LONG H1 ; No - go back for more
H3:
QUIT 0 ; We're done - exit
;.....
;
;=======================================================================
; Main program starts here
;=======================================================================
;
L0:
NEWLINE ; Give us some space
PRINT BAR ; Print banner bar
NEWLINE ; Another space
MOV AH,[080] ; See if any comand tail
CMP AH,1
JA > L1
L00:
MOV ES,040 ; If no tail, reset ica
ES MOV W[0F0],0
ES MOV W[0F2],0
PRINT RESET_MSG ; Write message
QUIT 0 ; And get out - normal exit
L1:
MOV DI,080 ; Point to command tail
L22:
INC DI
MOV AH,[DI]
CMP AH,020 ; Bumping past the spaces here
JE L22
MOV FILE_PTR,DI ; Point to file name
L222:
MOV AH,[DI]
CMP AH,SPACE
JE > L555
CMP AH,CR
JE > L555
INC DI
JMP L222
MOV AL,CR ; Look for carriage return
MOV CX,0100 ; Look for a long time!
CLD
REPNE SCASB
JCXZ L00 ; Get out if no find one
DEC DI
L555:
MOV TAIL_PTR,DI ; Save pointer to command tail
PUSH DI
LEA BX,TAIL_BFR ; Point to command tail (saved)
L16:
MOV AH,[DI] ; Get element
CMP AH,CR ; End of tail?
JE > L17
MOV [BX],AH ; Stuff it away
INC DI ; Bump pointers
INC BX
JMP L16 ; Do again
L17:
MOV B[BX],CR ; Terminate tail
POP DI
LEA BX,FILE_STRING ; Point to buffer to store file name
MOV DI,[FILE_PTR] ; Get pointer to program in command tail
L33:
MOV AH,[DI] ; Build the name, char by char
MAKE_CAP AH ; Make sure all caps
MOV [BX],AH ; Stuff it away
INC BX ; Bump pointers
INC DI
CMP DI,[TAIL_PTR] ; Are we done?
JB L33 ; If not, carry on
MOV W[BX],'C.' ; Stick in ".COM" extension
MOV W[BX+2],'MO' ; Reversed - that's the way intel works
MOV B[BX+4],0 ; End with 0 to make asciiz string
LEA DX,FILE_STRING ; Point dx to the file
MOV AH,04E ; Find file
MOV CX,027 ; File attribute byte - this works
INT 021 ; Do it
JC > L77 ; Did we find it?
JMP LONG L78 ; Got it! go process it
L77:
NEWLINE ; Couldn't find file
NEWLINE
PRINT$ 'Cant find file ' ; So say so
MOV B[DI-1],'$' ; Put in string delimiter and print
PRINT FILE_STRING ; What we were looking for
PRINT$ ' ...ABORTING' ; Sorry charlie
NEWLINE
NEWLINE
QUIT 3 ; Quit with error level = 3
L78:
MOV AL,' ' ; Looking for a space
MOV CX,100 ; Up to 256 bytes back
STD ; Scan backwards
REPNE SCASB ; And search
LEA DX,FILE_STRING ; Ok, now at start of file string
PUSH DI ; Save pointer
MOV B[DI-1],0 ; Make asciiz string
PUSH BX
PUSH CX
MOV AH,030 ; Check dos version level
INT 021
POP CX
POP BX
CMP AL,2 ; At least version 2?
JAE > V1
NEWLINE ; If not, dump out
PRINT$ 'Requires DOS 2.0 or above ... ABORTING'
NEWLINE
QUIT 2 ; Bad dos version - error level = 2
V1:
CMP AL,3 ; Version 3.0 or above?
JAE > V2 ; If it is, we're ok
LEA SI,DEFAULT_ENV ; Set up default envir var name
JMP > V3
V2:
CALL WHOAMI ; Find out this programs'name
V3:
CALL GET_ENV_VAR ; Get the environment value
JC > L88 ; Did we get a match?
JMP LONG L888 ; Yes, we did
L88:
NEWLINE ; No we didn't
PRINT$ 'No address given ... ABORTING'
QUIT 1 ; Bad environment variable - error
L888:
PUSH DS
PUSH ES
POP DS
CALL ASC_2_NUMS ; Convert the ascii to hex values
POP DS
MOV START_ADDR+2,AX ; That's our starting address
MOV ES,040
ES ADD AX,[0F0] ; Add the last loads' space
ES ADD AX,[0F2]
ADD AX,010 ; Allow for psp
MOV LOAD_BLOCK,AX ; This is out new loading address
SUB AX,010 ; Remove psp allowance
NEWLINE ; Starting load message
PRINT$ 'Loading '
POP DI
MOV B[DI-1],'$' ; Make printable
PRINT FILE_STRING ; And print it
PRINT$ 'at segment '
PRINT_REG AX ; Print segment address
LEA BX,LOAD_BLOCK ; Where we load
PUSH ES
PUSH DS
POP ES
MOV AH,04B ; Dos exec function
MOV AL,3 ; Load but don't execute
INT 021 ; Do it
POP ES
MOV AX,[LOAD_BLOCK] ; Loading address again
SUB AX,010 ; Allow for psp
MOV START_ADDR + 2,AX ; Stuff it away
MOV LOAD_POINT,AX ; And here
MOV LP_PLUS_BYTES,AX ; And here, too
MOV ES,AX ; Segment of where tsr is loaded
MOV CX,0100 ; Going to transfer 256 bytes
XOR SI,SI ; Of the psp (we're using the one
XOR DI,DI ; We got from dos)
CLD ; Set direction flag
REP MOVSB ; Transfer it
MOV DI,081 ; Point to com tail in new psp
LEA SI,TAIL_BFR
XOR AL,AL ; Count of command tail length
L98:
MOV AH,[SI]
CMP AH,CR ; Any command tail at all?
JE > L99
ES MOV [DI],AH ; If so, start transferring the
INC AL ; Tsr's command tail - he might
INC DI ; Need it
INC SI
JMP L98
L99:
MOV B[SI],'$' ; Again, for dos int 21h printing
NEWLINE
PRINT$ 'Command tail = ' ; Printing out the supplied
PRINT TAIL_BFR ; Command tail
MOV B[SI],CR ; Terminate
ES MOV B[DI],CR ; Terminate new tail
ES MOV [080],AL ; Put in count
ES MOV B[081],SPACE ; And normal space
;
; Here we start revectoring the appropriate interrupts
;
MOV AH,035 ; The 'gimme address' function
MOV AL,027 ; For interrupt 27h
INT 021 ; Go get it
MOV AX,ES ; Its segment
MOV OLD_INT_27,BX ; Store offset value
MOV (OLD_INT_27 + 2),AX ; Store segment value
LEA DX,NEW_INT27 ; Where we're going to point to
MOV AH,025 ; Tell dos about it
MOV AL,027 ; For int 27h
INT 021 ; Do it
MOV AH,035 ; Get address function again
MOV AL,021 ; This time for int 21h
INT 021 ; Do it
MOV AX,ES
MOV OLD_INT_21,BX ; Save offset
MOV (OLD_INT_21 + 2),AX ; And segment
LEA DX,NEW_INT21 ; Point to my routine
MOV AH,025 ; And tell dos
MOV AL,021
INT 021
MOV AX,[START_ADDR+2] ; Get address of routine
MOV ES,AX ; Set up registers
MOV DS,AX ; But don't change stack reg (ss)!!
CS JMP D[START_ADDR] ; And execute the program
;...
;
; This is the end of the regular program. We exit when the TSR executes
; and INT 27H or an INT 21H with function 31H.
;
; The following are the various subroutines used
;
; routine to compare two 32-bit quantities
; if BX:CX > DX:AX, carry bit is set
; if BX:CX < DX:AX, carry bit is cleared
; if BX:CX = DX:AX, zero flag is set
;
; all registers unchanged
;
CMP_32:
CMP BX,DX
JAE > L0
JMP > L1
L0:
JA > L2
CMP CX,AX
JB > L1
L2:
STC
RET
L1:
CLC
RET
;.....
;
; Routine to form 32-bit sum of (typically) a segment and offset pair
;
; enter with "segment" value in DX, "offset" in AX
; returns with sum in DX:AX
;
; all other registers restored
;
ADD_SEG_OFF:
PUSH BX,CX
XOR BX,BX
MOV CX,4
L0:
SHL BX,1
SHL DX,1
ADC BX,0
LOOP L0
ADD AX,DX
ADC BX,0
MOV DX,BX
POP CX,BX
RET
;.....
;
; Routine to convert a HEX digit to a two byte word containing the
; equivalent ASCII characters
;
; Enter with the byte to be converted in AL
; Return with the ASCII string in AX in 'backwords' format
; i.e., an AL value of 47 would return AX = 3734
; so a MOV W[SI],AX for example would store the values
; in memory in the proper order
;
; All other registers restored
;
; This is essentially identical to the macro MAKE_HEX_ASCII
; except the macro does not interchange AH and AL
;
HEX2PRNT:
XOR AH,AH ; Zero out upper half
AAM 16 ; Split into two
ADD AX,03030 ; Make ASCII
CMP AH,039 ; Check for a - f
IF A ADD AH,7
CMP AL,039
IF A ADD AL,7
XCHG AH,AL ; Put in proper order
RET ; For a MOV innstruction
;.....
;
; Routine to find out the program name.
; no parameters on entry.
; return with SI pointing to a string containing the file name
; with no extent or period.
; the string is terminated with a 0.
; all registers (except SI) are restored
;
WHOAMI:
JMP > L0
MY_NAME:
DB 9 DUP (0)
L0:
PUSH AX
PUSH BX
PUSH CX
PUSH ES
PUSH DI
MOV BX,[02C] ; Get seg addr of env
MOV ES,BX ; Put in es
XOR DI,DI ; Zero out di
XOR AX,AX ; Looking for double zeros
MOV CX,08000 ; Max environment length = 32k
CLD ; Set direction flag
L3:
REPNE SCASB ; Look for zero
ES MOV BX,W[DI-1]
CMP BX,0 ; Got two bytes of zero?
JNE L3
MOV AL,'.'
REPNE SCASB ; Looking for extent
MOV BX,DI ; Save end of string pointer
L6:
ES MOV AL,[DI]
CMP AL,'\'
JE > L7
CMP AL,0
JE > L7
DEC DI
JMP L6
L7:
MOV SI,DI
INC SI ; Point to first byte of asciiz
LEA DI,MY_NAME ; Will store it in this segment
L2:
ES MOV AH,[SI]
CMP AH,'.'
JE > L1
MAKE_CAP AH ; Make sure all names are capitals
MOV [DI],AH
INC DI
INC SI
JMP L2
L1:
LEA SI,MY_NAME
POP DI
POP ES
POP CX
POP BX
POP AX
RET
;.....
;
; Routine to find a match between a given string and an environment
; variable.
;
; Enter with DS:SI pointing to a string, terminated by a 0,
; which contains the string to be matched.
;
; Returns with SI pointing to the end of the matching
; string in in the environment.
;
; The environment variables are of the form NAME=string
; This routine returns SI pointing to the string, just
; after the equal sign.
;
; ES points to the environment segment on return
;
; If a matching string is found, the carry bit will be
; clear. If no match is found, the carry will be set.
;
; All other registers are restored; SI not guaranteed.
;
GET_ENV_VAR:
JMP > L0
STRING_COUNT:
DW 0
L0:
PUSH AX
PUSH CX
PUSH DI
XOR CX,CX ; Zero out counter
PUSH SI ; Save pointer
L1:
MOV AL,[SI]
CMP AL,0 ; At end of string?
JE > L2
INC SI ; Bump pointer
INC CX ; Bump counter
JMP L1
L2:
CS MOV STRING_COUNT,CX ; Save counter
POP SI ; Restore pointer
CALL GET_ENV_LENGTH ; Get length of environment
MOV CX,AX ; Set up count
XOR DI,DI ; Start at beginning
MOV AX,[02C] ; Environment segment
MOV ES,AX
CLD ; Scan forward
MOV AL,[SI] ; Look for first letter
L3:
REPNE SCASB ; Scan for it
DEC DI ; Back off to point to match
JCXZ > L99 ; Get out if not there
PUSH CX ; Save counter
CS MOV CX,[STRING_COUNT]
PUSH SI ; Save my old place
REPE CMPSB ; See if they're all equal
POP SI ; Restore my place
JZ > L4
POP CX ; No match, so carry on
JMP L3
L99:
STC ; Set the carry
JMP > L5
L4:
POP CX ; Clear stack
MOV SI,DI ; Put pointer in si
INC SI ; Skip past equal sign
CLC ; Clear carry
L5:
POP DI
POP CX
POP AX
RET
;.....
;
; Routine to find length of environment
;
; IF CARRY IS CLEAR, RESULT RETURNED IN AX
; IF CARRY IS SET, ERROR CONDITION
;
; IN EITHER EVENT, ALL REGISTERS OTHER THAN AX ARE RESTORED
;
GET_ENV_LENGTH:
PUSH CX
PUSH ES
PUSH DI
MOV AX,[02C] ; Get segment of environment
MOV ES,AX
XOR DI,DI ; Start at beginning of env
MOV CX,08000 ; Maximum env string = 32k
L9:
ES MOV AX,W[DI]
CMP AX,0
JE > L0
INC DI
LOOP L9
JCXZ >L1 ; If cx=0, we're in big trouble
L0:
MOV AX,DI ; Si is length of env - put it in ax
CLC ; Clear carry bit - result ok
JMP > L2
L1:
STC ; Set the carry - error
L2:
POP DI
POP ES
POP CX
RET
;.....
;
; Routine to convert a 2-digit ASCII pair into a hex number e.g.,
; convert 3741 into 7A.
;
; Enter with the ASCII pair in AX, return with the hex digit
; in AL
;
; If all is well, the carry bit is clear
; If the carry bit is set, at least one of the proposed digits
; was not in the range (0-9) snd (A-F) (Routine accepts small
; letters and makes them caps)
;
; All other registers unaffected.
;
ASC_2_HEX:
XCHG AH,AL
CMP AH,039
JBE > L0
AND AH,0DF ; Make caps
CMP AH,'F'
JA > L3
SUB AH,7
L0:
CMP AH,030
JB > L3
CMP AL,039
JBE > L1
AND AL,0DF
CMP AL,'F'
JA > L3
SUB AL,7
L1:
CMP AL,030
JB > L3
SUB AX,03030
UNSPLIT
CLC
RET
L3:
STC
RET
;.....
;
; Routine to convert a 4-digit ASCII number representation into a
; 4-digit hex number e.g., 31374230 -> 17B0
;
; Enter with DS:SI pointing to the string.
; Return with the number in AX, in the proper order
; i.e., 31374230 -> AH = 17, AL = B0
;
; Carry bit set indicates bad ASCII number (out of range) see above
;
ASC_2_NUMS:
PUSH BX
MOV AX,W[SI]
CALL ASC_2_HEX
JC > L1
MOV BX,AX
MOV AX,W[SI+2]
CALL ASC_2_HEX
JC > L1
MOV AH,BL
POP BX
CLC
L1:
RET
;.....
;
; Routine to convert a 32-bit number to a decimal ASCII string enter
; with the number to be converted in DX:AX and DI pointing to the last
; byte of the result string area. Return with DI pointing to first
; non-zero character of resultant conversion.
;
; BX, CX, and SI unchanged
;
; This routine was cribbed from FREE by Art Merrill - I don't really
; understand it all, but it works!
;
LARGE_HEX_TO_ASCII:
PUSH BX
PUSH CX
XCHG CX,DX
MOV BX,10
L1:
CMP CX,0
JE > L2
XCHG AX,CX
XOR DX,DX
DIV BX
XCHG AX,CX
DIV BX
OR DL,030
MOV [DI],DL
DEC DI
JMP L1
L2:
XOR DX,DX
DIV BX
OR DL,030
MOV [DI],DL
DEC DI
CMP AX,0
JNE L2
INC DI ; Back up pointer to first char
POP CX
POP BX
RET
;
end