home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / sampler0 / hiload.asm < prev    next >
Assembly Source File  |  1990-06-18  |  22KB  |  895 lines

  1. ; This is version 1.01 of HILOAD
  2. ;
  3. ;        See accompanying .DOC file for theory of
  4. ;        operation and instructions
  5. ;
  6. ;        No guarantees, but the author would appreciate
  7. ;        information on bugs.
  8. ;
  9. ;        Larry Shannon 18 Jun 89
  10. ;
  11. ; Equates
  12. ;
  13.         CR    EQU    0D
  14.         LF    EQU    0A
  15.         SPACE    EQU    020
  16.         MON    EQU    MOV    ; Common typo
  17.         ONE    EQU    1
  18.         TWO    EQU    2
  19.         DOLLAR    EQU    024
  20.         ZERO    EQU    0
  21.         BELL    EQU    07
  22. ;.....
  23. ;
  24. ; Macros
  25. ;
  26. PRINT         MACRO            ; Usage: print MSG1
  27.         PUSH    AX        ; All registers preserved
  28.         PUSH    DX
  29.         MOV    AH,9
  30.         LEA    DX, #1
  31.         INT    021
  32.         POP    DX
  33.         POP    AX
  34.         #EM
  35. ;
  36. PRINT$         MACRO            ; Usage: print$,"MESSAGE"
  37.         PUSH    AX        ; Prints at current cursor position
  38.         PUSH    DX
  39.         JMP    >M1
  40. M0:
  41.         DB    #1
  42.         DB    "$"
  43. M1:
  44.         MOV    AH,9        ; All registers preserved
  45.         LEA    DX,M0
  46.         INT    021
  47.         POP    DX
  48.         POP    AX
  49.         #EM
  50. ;
  51. QUIT         MACRO            ; Usage: quit 0
  52.         MOV    AH,04C        ; Must give some value
  53.         MOV    AL,#1
  54.         INT    021
  55.         #EM
  56. ;
  57. NEWLINE         MACRO            ; Equivalent to CR,LF
  58.         PUSH    AX        ; Scrolls if off screen
  59.         PUSH    DX
  60.         JMP    > M1
  61. M0:
  62.         DB    0D,0A,'$'
  63. M1:
  64.         LEA    DX,M0
  65.         MOV    AH,9
  66.         INT    021
  67.         POP    DX
  68.         POP    AX
  69.         #EM
  70. ;
  71. SPLIT         MACRO    AAM 16    #EM    ; Be careful with these with
  72. ;                    ; Nec v-20/v-30 chips!
  73. UNSPLIT         MACRO            ; This macro will effectively
  74.         PUSH    CX        ; Do the same thing, and should be
  75.         MOV    CX,4        ; Compatible with all pc's
  76.         ROL    AH,CL
  77.         AND    AH,0F0
  78.         OR    AL,AH
  79.         POP    CX
  80.         #EM
  81. ;
  82. HEX_TO_PRNT     MACRO            ; Changes an 8-bit register quantity
  83.         OR    #1,030        ; From 0-f to the ascii equivalent
  84.         CMP    #1,039        ; Register must be in form 00 to 0f
  85. ;
  86.          IF    A ADD #1,7
  87.         #EM
  88. ;
  89. PRINT_REG     MACRO            ; Used to print a register (or any 16-bit
  90.         JMP    > M1        ; Quantity) at the current cursor position
  91. M0:
  92.         DB    5 DUP ('$')
  93. M1:
  94.         PUSH    AX        ; Usage - print_reg AX
  95.         MOV    AX,#1        ; Prints the 16-bit quantity in hex
  96.         XCHG    AH,AL
  97.         PUSH    AX
  98.         MAKE_HEX_ASCII
  99.         XCHG    AH,AL
  100.         MOV    W[M0],AX
  101.         POP    AX
  102.         XCHG    AH,AL
  103.         MAKE_HEX_ASCII
  104.         XCHG    AH,AL
  105.         MOV    W[M0+2],AX
  106.         PRINT    M0
  107.         POP    AX
  108.         #EM
  109. ;
  110. PRINT_32_DEC     MACRO            ; Macro to print a 32-bit hex number
  111.         PUSH    AX        ; As a decimal string
  112.         PUSH    DX        ; Enter with si pointing to two-word
  113.         PUSH    DI        ; (four byte) quantity to be converted
  114.         MOV    DX,W[SI]    ; Most significant word first
  115.         MOV    AX,W[SI+2]    ; Prints at current cursor position
  116.         JMP    > M1        ; All registers restored
  117. M0:
  118.         DB    11 DUP ('$')
  119. M1:
  120.         LEA    DI,M0
  121.         ADD    DI,9
  122.         CALL    LARGE_HEX_TO_ASCII
  123.         MOV    DX,DI
  124.         MOV    AH,9
  125.         INT    021
  126.         POP    DI
  127.         POP    DX
  128.         POP    AX
  129.         #EM
  130. ;
  131. REG_TO_PRINT     MACRO            ; Converts a 16-bit quantity to ascii
  132.         PUSH    AX        ; And puts the resultant string in a
  133.         PUSH    BX        ; Place pointed to by ds:si
  134.         MOV    BX,#1        ; All registers restored
  135.         MOV    AL,BH
  136.         CALL    HEX2PRNT
  137.         MOV    [SI],AX
  138.         MOV    AL,BL
  139.         CALL    HEX2PRNT
  140.         MOV    [SI+2],AX
  141.         POP    BX
  142.         POP    AX
  143.         #EM
  144. ;
  145. MAKE_CAP     MACRO            ; Makes letters capitals
  146.         CMP    #1,061        ; Useage  make_cap AH
  147.         JB    > M1        ; Ah contains a candidate ascii letter
  148.         CMP    #1,07A        ; From A-Z or a-z
  149.         JA    > M1        ; Returns A-Z
  150.         AND    #1,0DF
  151. M1:
  152.         NOP
  153.         #EM
  154. ;
  155. MAKE_HEX_ASCII     MACRO            ; Makes al in hex into two ascii
  156.         SPLIT            ; Characters in ah:al
  157.         HEX_TO_PRNT AH
  158.         HEX_TO_PRNT AL
  159.         #EM
  160. ;.....
  161. ;
  162. ; Data and strings
  163. ;
  164. ;
  165.         ORG    0100
  166. ;
  167. ;
  168. HILOAD:        JMP    LONG > L0
  169.  
  170. LOAD_BLOCK    DW    0,0
  171. FILE_STRING    DB    65 DUP('$')
  172. TAIL_PTR    DW    0
  173. FILE_PTR    DW    0
  174. OLD_INT_27    DW    0,0
  175. OLD_INT_21    DW    0,0
  176. START_ADDR    DW    0100,0
  177. TAIL_BFR    DB    127 DUP    ('020')
  178. SW2127        DB    0
  179. TEMPWRDS    DW    0,0
  180. BAR        DB    40 DUP ('*'),'$'
  181. RESET_MSG    DB    CR,LF,'Resetting ICA area',CR,LF,'$'
  182. DEFAULT_ENV    DB    'HILOAD',0
  183. INT_MSG        DB    'Interupt '
  184. INT_NUM        DB    0,0,'H is now located at '
  185. INT_SEG        DB    0,0,0,0,':'
  186. INT_OFF        DB    0,0,0,0,CR,LF,'$'
  187. TEMP        DW    0
  188. LOAD_POINT    DW    0,0
  189. LP_PLUS_BYTES    DW    0,0
  190. INT_ADDR_1    DW    0
  191. INT_ADDR_2    DW    0
  192. ;
  193. NEW_INT21:
  194.             CMP    AH,031        ; New address for int 21h
  195.         JE    > Z21        ; Is it TSR termination?
  196.         CMP    AX,02521    ; Setting vector for int 21h?
  197.         JE    > Z25        ; If so, save it
  198.         CMP    AX,03521    ; Request for int 21h address?
  199.         JE    > Z35        ; If so, give him original address
  200.         CS    JMP D[OLD_INT_21] ; Otherwise, do real int 21h
  201. Z25:
  202.         CS    MOV OLD_INT_21,DX ; Here we save int 21h address info
  203.         CS    MOV OLD_INT_21+2,DS
  204.         IRET            ; And return to caller
  205. Z35:
  206.         CS    MOV BX,[OLD_INT_21] ; Here we give him original address
  207.         CS    MOV ES,[OLD_INT_21+2]
  208.         IRET            ; And return to caller
  209. Z21:
  210.         CS    MOV SW2127,0    ; Exiting via int 21 - set switch for
  211.         JMP    > Z22        ; Storage return handling
  212. ;.....
  213. ;
  214. NEW_INT27:
  215.         CS    MOV SW2127,1    ; Trap for int 27h - set switch
  216. Z22:
  217.         MOV    AX,CS        ; Get our code segment
  218.         MOV    BX,DX        ; Save return size info
  219.         MOV    DS,AX        ; Set up local addressability
  220.         MOV    ES,AX        ; Make sure other registers are
  221.         MOV    SS,AX        ; What they should be
  222.         MOV    DX,[OLD_INT_27]    ; Find original address of int 27h
  223.         MOV    AX,[OLD_INT_27+2] ; Segment portion
  224.         MOV    ES,0        ; Addressing bottom page
  225.         ES    MOV W[09C],DX    ; Store vector addresses directly
  226.         ES    MOV W[09E],AX    ; Since int 21h cannot be used to do
  227.         MOV    DX,[OLD_INT_21]    ; The job - we've trapped it above!
  228.         MOV    AX,[OLD_INT_21 + 2] ; Do the same with int 21h
  229.         MOV    ES,0
  230.         ES    MOV W[084],DX    ; And store its address in the
  231.         ES    MOV W[086],AX    ; Proper place in the table
  232.         NEWLINE            ; Space a line
  233.         PRINT$    'Saved bytes = ' ; Start of message
  234.         CMP    SW2127,1    ; See how we terminated; 1=int 27h so
  235.         JE    > Q2        ; Returns bytes - int 21h returns para-
  236.         MOV    AX,BX        ; Graphs - here we're converting
  237.         XOR    DX,DX        ; Paragraphs to bytes by multiplying
  238.         MOV    CX,4        ; By 4 (shift left 4 places)
  239. Q1:
  240.         RCL    AX,1        ; Have to allow for greater than 64k
  241.         PUSHF            ; Save flags with state of carry bit
  242.         ROL    DX,1
  243.         POPF            ; Get flags back
  244.         ADC    DX,0        ; Add in and include carry
  245.         LOOP    Q1        ; Carry on
  246.         JMP    > Q3
  247. Q2:
  248.         MOV    AX,BX        ; Size info in bx - do setup for
  249.         XOR    DX,DX        ; Conversion
  250. Q3:
  251.         MOV    TEMPWRDS,DX    ; Temporarily store upper and lower
  252.         MOV    TEMPWRDS + 2,AX    ; Halves of return size info (32 bits)
  253.         PUSH    DX        ; Save dx
  254.         MOV    DX,[LOAD_POINT]    ; Get where we started
  255.         MOV    LP_PLUS_BYTES,DX ; Put it here
  256.         POP    DX        ; Retrieve dx
  257.         ADD    LP_PLUS_BYTES,DX ; Add size info
  258.         MOV    LP_PLUS_BYTES+2,AX ; Store upper half here
  259.         LEA    SI,TEMPWRDS    ; Point to temporary storage
  260.         PRINT_32_DEC        ; Print out size in bytes
  261.         NEWLINE            ; Do new line
  262.         MOV    DX,[TEMPWRDS]    ; Get back size info
  263.         MOV    AX,[TEMPWRDS+2]
  264.         CLC            ; Clear the carry
  265.         MOV    CX,4        ; We're going to convert to a 32-bit
  266. Q7:
  267.         SHR    DX,1        ; Number here and store it in
  268.         PUSHF            ; The ica area
  269.         RCR    AX,1
  270.         POPF
  271.         LOOP    Q7
  272.         MOV    ES,040        ; Point to segment of ica
  273.         ES    MOV BX,[0F0]    ; Get what was there
  274.         ADD    DX,BX        ; Add new size
  275.         ES    MOV [0F0],DX    ; And put it back
  276.         ES    MOV BX,[0F2]    ; Get old lower half
  277.         ADD    AX,BX        ; Add new bytes saved data
  278.         INC    AX        ; Allow for truncation
  279.         ES    MOV [0F2],AX    ; And put it back
  280.  
  281.         NEWLINE            ; Start of trap info
  282.         PRINT$    'This TSR traps the following interrupts:'
  283.         NEWLINE            ; Some spaces
  284.         NEWLINE
  285. ;
  286. ; Here is where we look to see what interrupts are trapped
  287. ;
  288.         MOV    CX,0FF        ; Look at 256 interrupts
  289.         MOV    AX,03500    ; Set up call
  290. H1:
  291.         PUSH    CX        ; Save registers
  292.         PUSH    AX
  293.         INT    021        ; Get interrupt addresses
  294.         MOV    AX,BX        ; Ax is offset
  295.         MOV    DX,ES        ; Dx:ax is addr of interrupt
  296.         MOV    INT_ADDR_1,AX    ; Store offset away
  297.         MOV    INT_ADDR_2,DX    ; Store segment
  298.         CALL    ADD_SEG_OFF    ; Convert to 32-bit number
  299.         XCHG    BX,DX        ; Now bx:cx is int addr
  300.         XCHG    CX,AX        ; In 32-bit form
  301.         MOV    DX,[LOAD_POINT]    ; Where do we start
  302.         XOR    AX,AX        ; No offset from start
  303.         CALL    ADD_SEG_OFF    ; Make 32-bitter
  304.         CALL    CMP_32        ; Is int address beyond start point?
  305.         JNC    > H2        ; If below, can't be us - get out
  306.         MOV    DX,[LP_PLUS_BYTES]
  307.         MOV    AX,[LP_PLUS_BYTES + 2] ; Dx:ax now address of end of pgm
  308.         CALL    ADD_SEG_OFF    ; Make 32-bits
  309.         CALL    CMP_32        ; Compare them
  310.         JC    > H2        ; If greater - beyond me
  311.         POP    AX        ; We got one - retrieve interrupt
  312.         PUSH    AX        ; And save function and int number
  313.         CALL    HEX2PRNT    ; Get interrupt number in ascii
  314.         LEA    SI,INT_NUM    ; Point to proper place
  315.         MOV    W[SI],AX    ; Store it
  316.         LEA    SI,INT_SEG    ; Point to place
  317.         REG_TO_PRINT [INT_ADDR_2] ; Get segment in ascii
  318.         LEA    SI,INT_OFF    ; Point to place
  319.         REG_TO_PRINT [INT_ADDR_1] ; Print offset in ascii
  320.         PRINT    INT_MSG        ; Print whole message
  321. H2:
  322.         POP    AX        ; Get registers back
  323.         INC    AX
  324.         POP    CX
  325.         DEC    CX
  326.         JCXZ    > H3        ; Are we done?
  327.         JMP    LONG H1        ; No - go back for more
  328. H3:
  329.         QUIT    0        ; We're done - exit
  330. ;.....
  331. ;
  332. ;=======================================================================
  333. ; Main program starts here
  334. ;=======================================================================
  335. ;
  336. L0:
  337.         NEWLINE            ; Give us some space
  338.         PRINT    BAR        ; Print banner bar
  339.         NEWLINE            ; Another space
  340.         MOV    AH,[080]    ; See if any comand tail
  341.         CMP    AH,1
  342.         JA    > L1
  343. L00:
  344.         MOV    ES,040        ; If no tail, reset ica
  345.         ES    MOV W[0F0],0
  346.         ES    MOV W[0F2],0
  347.         PRINT    RESET_MSG    ; Write message
  348.         QUIT    0        ; And get out - normal exit
  349. L1:
  350.         MOV    DI,080        ; Point to command tail
  351. L22:
  352.         INC    DI
  353.         MOV    AH,[DI]
  354.         CMP    AH,020        ; Bumping past the spaces here
  355.         JE    L22
  356.         MOV    FILE_PTR,DI    ; Point to file name
  357. L222:
  358.         MOV    AH,[DI]
  359.         CMP    AH,SPACE
  360.         JE    > L555
  361.         CMP    AH,CR
  362.         JE    > L555
  363.         INC    DI
  364.         JMP    L222
  365.         MOV    AL,CR        ; Look for carriage return
  366.         MOV    CX,0100        ; Look for a long time!
  367.         CLD
  368.         REPNE    SCASB
  369.         JCXZ    L00        ; Get out if no find one
  370.         DEC    DI
  371. L555:
  372.         MOV    TAIL_PTR,DI    ; Save pointer to command tail
  373.         PUSH    DI
  374.         LEA    BX,TAIL_BFR    ; Point to command tail (saved)
  375. L16:
  376.         MOV    AH,[DI]        ; Get element
  377.         CMP    AH,CR        ; End of tail?
  378.         JE    > L17
  379.         MOV    [BX],AH        ; Stuff it away
  380.         INC    DI        ; Bump pointers
  381.         INC    BX
  382.         JMP    L16        ; Do again
  383. L17:
  384.         MOV    B[BX],CR    ; Terminate tail
  385.         POP    DI
  386.         LEA    BX,FILE_STRING    ; Point to buffer to store file name
  387.         MOV    DI,[FILE_PTR]    ; Get pointer to program in command tail
  388. L33:
  389.         MOV    AH,[DI]        ; Build the name, char by char
  390.         MAKE_CAP AH        ; Make sure all caps
  391.         MOV    [BX],AH        ; Stuff it away
  392.         INC    BX        ; Bump pointers
  393.         INC    DI
  394.         CMP    DI,[TAIL_PTR]    ; Are we done?
  395.         JB    L33        ; If not, carry on
  396.         MOV    W[BX],'C.'    ; Stick in ".COM" extension
  397.         MOV    W[BX+2],'MO'    ; Reversed - that's the way intel works
  398.         MOV    B[BX+4],0    ; End with 0 to make asciiz string
  399.         LEA    DX,FILE_STRING    ; Point dx to the file
  400.         MOV    AH,04E        ; Find file
  401.         MOV    CX,027        ; File attribute byte - this works
  402.         INT    021        ; Do it
  403.         JC    > L77        ; Did we find it?
  404.         JMP    LONG L78    ; Got it! go process it
  405. L77:
  406.         NEWLINE            ; Couldn't find file
  407.         NEWLINE
  408.         PRINT$    'Cant find file ' ; So say so
  409.         MOV    B[DI-1],'$'    ; Put in string delimiter and print
  410.         PRINT    FILE_STRING    ; What we were looking for
  411.         PRINT$    ' ...ABORTING'    ; Sorry charlie
  412.         NEWLINE
  413.         NEWLINE
  414.         QUIT    3        ; Quit with error level = 3
  415. L78:
  416.         MOV    AL,' '        ; Looking for a space
  417.         MOV    CX,100        ; Up to 256 bytes back
  418.         STD            ; Scan backwards
  419.         REPNE    SCASB        ; And search
  420.         LEA    DX,FILE_STRING    ; Ok, now at start of file string
  421.         PUSH    DI        ; Save pointer
  422.         MOV    B[DI-1],0    ; Make asciiz string
  423.         PUSH    BX
  424.         PUSH    CX
  425.         MOV    AH,030        ; Check dos version level
  426.         INT    021
  427.         POP    CX
  428.         POP    BX
  429.         CMP    AL,2        ; At least version 2?
  430.         JAE    > V1
  431.         NEWLINE            ; If not, dump out
  432.         PRINT$    'Requires DOS 2.0 or above ... ABORTING'
  433.         NEWLINE
  434.         QUIT    2        ; Bad dos version - error level = 2
  435. V1:
  436.         CMP    AL,3        ; Version 3.0 or above?
  437.         JAE    > V2        ; If it is, we're ok
  438.         LEA    SI,DEFAULT_ENV    ; Set up default envir var name
  439.         JMP    > V3
  440. V2:
  441.         CALL    WHOAMI        ; Find out this programs'name
  442. V3:
  443.         CALL    GET_ENV_VAR    ; Get the environment value
  444.         JC    > L88        ; Did we get a match?
  445.         JMP    LONG L888    ; Yes, we did
  446. L88:
  447.         NEWLINE            ; No we didn't
  448.         PRINT$    'No address given ... ABORTING'
  449.         QUIT    1        ; Bad environment variable - error
  450. L888:
  451.         PUSH    DS
  452.         PUSH    ES
  453.         POP    DS
  454.         CALL    ASC_2_NUMS    ; Convert the ascii to hex values
  455.         POP    DS
  456.         MOV    START_ADDR+2,AX    ; That's our starting address
  457.         MOV    ES,040
  458.         ES    ADD AX,[0F0]    ; Add the last loads' space
  459.         ES    ADD AX,[0F2]
  460.         ADD    AX,010        ; Allow for psp
  461.         MOV    LOAD_BLOCK,AX    ; This is out new loading address
  462.         SUB    AX,010        ; Remove psp allowance
  463.         NEWLINE            ; Starting load message
  464.         PRINT$    'Loading '
  465.         POP    DI
  466.         MOV    B[DI-1],'$'    ; Make printable
  467.         PRINT    FILE_STRING    ; And print it
  468.         PRINT$    'at segment '
  469.         PRINT_REG AX        ; Print segment address
  470.         LEA    BX,LOAD_BLOCK    ; Where we load
  471.         PUSH    ES
  472.         PUSH    DS
  473.         POP    ES
  474.         MOV    AH,04B        ; Dos exec function
  475.         MOV    AL,3        ; Load but don't execute
  476.         INT    021        ; Do it
  477.         POP    ES
  478.         MOV    AX,[LOAD_BLOCK]    ; Loading address again
  479.         SUB    AX,010        ; Allow for psp
  480.         MOV    START_ADDR + 2,AX ; Stuff it away
  481.         MOV    LOAD_POINT,AX    ; And here
  482.         MOV    LP_PLUS_BYTES,AX ; And here, too
  483.         MOV    ES,AX        ; Segment of where tsr is loaded
  484.         MOV    CX,0100        ; Going to transfer 256 bytes
  485.         XOR    SI,SI        ; Of the psp (we're using the one
  486.         XOR    DI,DI        ; We got from dos)
  487.         CLD            ; Set direction flag
  488.         REP    MOVSB        ; Transfer it
  489.         MOV    DI,081        ; Point to com tail in new psp
  490.         LEA    SI,TAIL_BFR
  491.         XOR    AL,AL        ; Count of command tail length
  492. L98:
  493.         MOV    AH,[SI]
  494.         CMP    AH,CR        ; Any command tail at all?
  495.         JE    > L99
  496.         ES    MOV [DI],AH    ; If so, start transferring the
  497.         INC    AL        ; Tsr's command tail - he might
  498.         INC    DI        ; Need it
  499.         INC    SI
  500.         JMP    L98
  501. L99:
  502.         MOV    B[SI],'$'    ; Again, for dos int 21h printing
  503.         NEWLINE
  504.         PRINT$    'Command tail = ' ; Printing out the supplied
  505.         PRINT    TAIL_BFR    ; Command tail
  506.         MOV    B[SI],CR    ; Terminate
  507.         ES    MOV B[DI],CR    ; Terminate new tail
  508.         ES    MOV [080],AL    ; Put in count
  509.         ES    MOV B[081],SPACE ; And normal space
  510. ;
  511. ; Here we start revectoring the appropriate interrupts
  512. ;
  513.         MOV    AH,035        ; The 'gimme address' function
  514.         MOV    AL,027        ; For interrupt 27h
  515.         INT    021        ; Go get it
  516.         MOV    AX,ES        ; Its segment
  517.         MOV    OLD_INT_27,BX    ; Store offset value
  518.         MOV    (OLD_INT_27 + 2),AX ; Store segment value
  519.         LEA    DX,NEW_INT27    ; Where we're going to point to
  520.         MOV    AH,025        ; Tell dos about it
  521.         MOV    AL,027        ; For int 27h
  522.         INT    021        ; Do it
  523.         MOV    AH,035        ; Get address function again
  524.         MOV    AL,021        ; This time for int 21h
  525.         INT    021        ; Do it
  526.         MOV    AX,ES
  527.         MOV    OLD_INT_21,BX    ; Save offset
  528.         MOV    (OLD_INT_21 + 2),AX ; And segment
  529.         LEA    DX,NEW_INT21    ; Point to my routine
  530.         MOV    AH,025        ; And tell dos
  531.         MOV    AL,021
  532.         INT    021
  533.         MOV    AX,[START_ADDR+2] ; Get address of routine
  534.         MOV    ES,AX        ; Set up registers
  535.         MOV    DS,AX        ; But don't change stack reg (ss)!!
  536.         CS    JMP D[START_ADDR] ; And execute the program
  537. ;...
  538. ;
  539. ; This is the end of the regular program.  We exit when the TSR executes
  540. ; and INT 27H or an INT 21H with function 31H.
  541. ;
  542. ; The following are the various subroutines used
  543. ;
  544. ;    routine to compare two 32-bit quantities
  545. ;    if BX:CX > DX:AX, carry bit is set
  546. ;    if BX:CX < DX:AX, carry bit is cleared
  547. ;    if BX:CX = DX:AX, zero flag is set
  548. ;
  549. ;    all registers unchanged
  550. ;
  551. CMP_32:
  552.         CMP    BX,DX
  553.         JAE    > L0
  554.         JMP    > L1
  555. L0:
  556.         JA    > L2
  557.         CMP    CX,AX
  558.         JB    > L1
  559. L2:
  560.         STC
  561.         RET
  562. L1:
  563.         CLC
  564.         RET
  565. ;.....
  566. ;
  567. ; Routine to form 32-bit sum of (typically) a segment and offset pair
  568. ;
  569. ;    enter with "segment" value in DX, "offset" in AX
  570. ;    returns with sum in DX:AX
  571. ;
  572. ;    all other registers restored
  573. ;
  574. ADD_SEG_OFF:
  575.             PUSH    BX,CX
  576.         XOR    BX,BX
  577.         MOV    CX,4
  578. L0:
  579.         SHL    BX,1
  580.         SHL    DX,1
  581.         ADC    BX,0
  582.         LOOP    L0
  583.         ADD    AX,DX
  584.         ADC    BX,0
  585.         MOV    DX,BX
  586.         POP    CX,BX
  587.         RET
  588. ;.....
  589. ;
  590. ; Routine to convert a HEX digit to a two byte word containing the
  591. ; equivalent ASCII characters
  592. ;
  593. ;    Enter with the byte to be converted in AL
  594. ;    Return with the ASCII string in AX in 'backwords' format
  595. ;    i.e., an AL value of 47 would return AX = 3734
  596. ;    so a MOV W[SI],AX for example would store the values
  597. ;    in memory in the proper order
  598. ;
  599. ;    All other registers restored
  600. ;
  601. ;    This is essentially identical to the macro MAKE_HEX_ASCII
  602. ;    except the macro does not interchange AH and AL
  603. ;
  604. HEX2PRNT:
  605.         XOR    AH,AH        ; Zero out upper half
  606.         AAM    16        ; Split into two
  607.         ADD    AX,03030    ; Make ASCII
  608.         CMP    AH,039        ; Check for a - f
  609.          IF    A ADD AH,7
  610.         CMP    AL,039
  611.          IF    A ADD AL,7
  612.         XCHG    AH,AL        ; Put in proper order
  613.         RET            ; For a MOV innstruction
  614. ;.....
  615. ;
  616. ; Routine to find out the program name.
  617. ;    no parameters on entry.
  618. ;    return with SI pointing to a string containing the file name
  619. ;    with no extent or period.
  620. ;    the string is terminated with a 0.
  621. ;    all registers (except SI) are restored
  622. ;
  623. WHOAMI:
  624.         JMP    > L0
  625. MY_NAME:
  626.         DB    9 DUP (0)
  627. L0:
  628.         PUSH    AX
  629.         PUSH    BX
  630.         PUSH    CX
  631.         PUSH    ES
  632.         PUSH    DI
  633.         MOV    BX,[02C]    ; Get seg addr of env
  634.         MOV    ES,BX        ; Put in es
  635.         XOR    DI,DI        ; Zero out di
  636.         XOR    AX,AX        ; Looking for double zeros
  637.         MOV    CX,08000    ; Max environment length = 32k
  638.         CLD            ; Set direction flag
  639. L3:
  640.         REPNE    SCASB        ; Look for zero
  641.         ES    MOV BX,W[DI-1]
  642.         CMP    BX,0        ; Got two bytes of zero?
  643.         JNE    L3
  644.         MOV    AL,'.'
  645.         REPNE    SCASB        ; Looking for extent
  646.         MOV    BX,DI        ; Save end of string pointer
  647. L6:
  648.         ES    MOV AL,[DI]
  649.         CMP    AL,'\'
  650.         JE    > L7
  651.         CMP    AL,0
  652.         JE    > L7
  653.         DEC    DI
  654.         JMP    L6
  655. L7:
  656.         MOV    SI,DI
  657.         INC    SI        ; Point to first byte of asciiz
  658.         LEA    DI,MY_NAME    ; Will store it in this segment
  659. L2:
  660.         ES    MOV AH,[SI]
  661.         CMP    AH,'.'
  662.         JE    > L1
  663.         MAKE_CAP AH        ; Make sure all names are capitals
  664.         MOV    [DI],AH
  665.         INC    DI
  666.         INC    SI
  667.         JMP    L2
  668. L1:
  669.         LEA    SI,MY_NAME
  670.         POP    DI
  671.         POP    ES
  672.         POP    CX
  673.         POP    BX
  674.         POP    AX
  675.         RET
  676. ;.....
  677. ;
  678. ; Routine to find a match between a given string and an environment
  679. ; variable.
  680. ;
  681. ;    Enter with DS:SI pointing to a string, terminated by a 0,
  682. ;    which contains the string to be matched.
  683. ;
  684. ;    Returns with SI pointing to the end of the matching
  685. ;    string in in the environment.
  686. ;
  687. ;    The environment variables are of the form NAME=string
  688. ;    This routine returns SI pointing to the string, just
  689. ;    after the equal sign.
  690. ;
  691. ;    ES points to the environment segment on return
  692. ;
  693. ;    If a matching string is found, the carry bit will be
  694. ;    clear. If no match is found, the carry will be set.
  695. ;
  696. ;    All other registers are restored; SI not guaranteed.
  697. ;
  698. GET_ENV_VAR:
  699.         JMP    > L0
  700. STRING_COUNT:
  701.         DW    0
  702. L0:
  703.         PUSH    AX
  704.         PUSH    CX
  705.         PUSH    DI
  706.         XOR    CX,CX        ; Zero out counter
  707.         PUSH    SI        ; Save pointer
  708. L1:
  709.         MOV    AL,[SI]
  710.         CMP    AL,0        ; At end of string?
  711.         JE    > L2
  712.         INC    SI        ; Bump pointer
  713.         INC    CX        ; Bump counter
  714.         JMP    L1
  715. L2:
  716.         CS    MOV STRING_COUNT,CX ; Save counter
  717.         POP    SI        ; Restore pointer
  718.         CALL    GET_ENV_LENGTH    ; Get length of environment
  719.         MOV    CX,AX        ; Set up count
  720.         XOR    DI,DI        ; Start at beginning
  721.         MOV    AX,[02C]    ; Environment segment
  722.         MOV    ES,AX
  723.         CLD            ; Scan forward
  724.         MOV    AL,[SI]        ; Look for first letter
  725. L3:
  726.         REPNE    SCASB        ; Scan for it
  727.         DEC    DI        ; Back off to point to match
  728.         JCXZ    > L99        ; Get out if not there
  729.         PUSH    CX        ; Save counter
  730.         CS    MOV CX,[STRING_COUNT]
  731.         PUSH    SI        ; Save my old place
  732.         REPE    CMPSB        ; See if they're all equal
  733.         POP    SI        ; Restore my place
  734.         JZ    > L4
  735.         POP    CX        ; No match, so carry on
  736.         JMP    L3
  737. L99:
  738.         STC            ; Set the carry
  739.         JMP    > L5
  740. L4:
  741.         POP    CX        ; Clear stack
  742.         MOV    SI,DI        ; Put pointer in si
  743.         INC    SI        ; Skip past equal sign
  744.         CLC            ; Clear carry
  745. L5:
  746.         POP    DI
  747.         POP    CX
  748.         POP    AX
  749.         RET
  750. ;.....
  751. ;
  752. ; Routine to find length of environment
  753. ;
  754. ;    IF CARRY IS CLEAR, RESULT RETURNED IN AX
  755. ;    IF CARRY IS SET, ERROR CONDITION
  756. ;
  757. ;    IN EITHER EVENT, ALL REGISTERS OTHER THAN AX ARE RESTORED
  758. ;
  759. GET_ENV_LENGTH:
  760.         PUSH    CX
  761.         PUSH    ES
  762.         PUSH    DI
  763.         MOV    AX,[02C]    ; Get segment of environment
  764.         MOV    ES,AX
  765.         XOR    DI,DI        ; Start at beginning of env
  766.         MOV    CX,08000    ; Maximum env string = 32k
  767. L9:
  768.         ES    MOV AX,W[DI]
  769.         CMP    AX,0
  770.         JE    > L0
  771.         INC    DI
  772.         LOOP    L9
  773.         JCXZ    >L1        ; If cx=0, we're in big trouble
  774. L0:
  775.         MOV    AX,DI        ; Si is length of env - put it in ax
  776.         CLC            ; Clear carry bit - result ok
  777.         JMP    > L2
  778. L1:
  779.         STC            ; Set the carry - error
  780. L2:
  781.         POP    DI
  782.         POP    ES
  783.         POP    CX
  784.         RET
  785. ;.....
  786. ;
  787. ; Routine to convert a 2-digit ASCII pair into a hex number e.g.,
  788. ; convert 3741 into 7A.
  789. ;
  790. ;    Enter with the ASCII pair in AX, return with the hex digit
  791. ;    in AL
  792. ;
  793. ;    If all is well, the carry bit is clear
  794. ;    If the carry bit is set, at least one of the proposed digits
  795. ;    was not in the range (0-9) snd (A-F) (Routine accepts small
  796. ;    letters and makes them caps)
  797. ;
  798. ;    All other registers unaffected.
  799. ;
  800. ASC_2_HEX:
  801.         XCHG    AH,AL
  802.         CMP    AH,039
  803.         JBE    > L0
  804.         AND    AH,0DF        ; Make caps
  805.         CMP    AH,'F'
  806.         JA    > L3
  807.         SUB    AH,7
  808. L0:
  809.         CMP    AH,030
  810.         JB    > L3
  811.         CMP    AL,039
  812.         JBE    > L1
  813.         AND    AL,0DF
  814.         CMP    AL,'F'
  815.         JA    > L3
  816.         SUB    AL,7
  817. L1:
  818.         CMP    AL,030
  819.         JB    > L3
  820.         SUB    AX,03030
  821.         UNSPLIT
  822.         CLC
  823.         RET
  824. L3:
  825.         STC
  826.         RET
  827. ;.....
  828. ;
  829. ; Routine to convert a 4-digit ASCII number representation into a
  830. ; 4-digit hex number e.g., 31374230 -> 17B0
  831. ;
  832. ;    Enter with DS:SI pointing to the string.
  833. ;    Return with the number in AX, in the proper order
  834. ;    i.e., 31374230 -> AH = 17, AL = B0
  835. ;
  836. ;    Carry bit set indicates bad ASCII number (out of range) see above
  837. ;
  838. ASC_2_NUMS:
  839.         PUSH    BX
  840.         MOV    AX,W[SI]
  841.         CALL    ASC_2_HEX
  842.         JC    > L1
  843.         MOV    BX,AX
  844.         MOV    AX,W[SI+2]
  845.         CALL    ASC_2_HEX
  846.         JC    > L1
  847.         MOV    AH,BL
  848.         POP    BX
  849.         CLC
  850. L1:
  851.         RET
  852. ;.....
  853. ;
  854. ; Routine to convert a 32-bit number to a decimal ASCII string enter
  855. ; with the number to be converted in DX:AX and DI pointing to the last
  856. ; byte of the result string area.  Return with DI pointing to first
  857. ; non-zero character of resultant conversion.
  858. ;
  859. ;    BX, CX, and SI unchanged
  860. ;
  861. ;    This routine was cribbed from FREE by Art Merrill - I don't really
  862. ;    understand it all, but it works!
  863. ;
  864. LARGE_HEX_TO_ASCII:
  865.         PUSH BX
  866.         PUSH    CX
  867.         XCHG    CX,DX
  868.         MOV    BX,10
  869. L1:
  870.         CMP    CX,0
  871.         JE    > L2
  872.         XCHG    AX,CX
  873.         XOR    DX,DX
  874.         DIV    BX
  875.         XCHG    AX,CX
  876.         DIV    BX
  877.         OR    DL,030
  878.         MOV    [DI],DL
  879.         DEC    DI
  880.         JMP    L1
  881. L2:
  882.         XOR    DX,DX
  883.         DIV    BX
  884.         OR    DL,030
  885.         MOV    [DI],DL
  886.         DEC    DI
  887.         CMP    AX,0
  888.         JNE    L2
  889.         INC    DI        ; Back up pointer to first char
  890.         POP    CX
  891.         POP    BX
  892.         RET
  893. ;
  894.                 end
  895.