home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msr313src.zip / msnut1.asm < prev    next >
Assembly Source File  |  1993-07-12  |  16KB  |  746 lines

  1.        NAME    MSNUT1
  2. ; File MSNUT1.ASM
  3. ; Provides various Intel 8088 level operations, including
  4. ; display facilities (via msg buffer or DOS) for char, strings, etc.
  5. ;
  6. ; Copyright 1991, University of Waterloo.
  7. ;  Copyright (C) 1985, 1993, Trustees of Columbia University in the 
  8. ;  City of New York.  Permission is granted to any individual or institution
  9. ;  to use this software as long as it is not sold for profit.  This copyright
  10. ;  notice must be retained.  This software may not be included in commercial
  11. ;  products without written permission of Columbia University.
  12. ; Written by Erick Engelke of the University of Waterloo, Waterloo, 
  13. ;  Ontario, Canada,
  14. ;  and by Joe R. Doupnik, Utah State University, 
  15. ;  jrd@cc.usu.edu, jrd@usu.Bitnet.
  16. ;
  17. ; Edit history
  18. ; 27 August 1992 version 3.13
  19. ; 6 Sept 1991 v3.11
  20. ; Last Edit
  21. ; 13 May 1993
  22.  
  23. cr    equ    0dh
  24. lf    equ    0ah
  25. conout    equ    2
  26. dos    equ    21h
  27. allocmem equ    48h
  28. freemem    equ    49h
  29.  
  30. MSGBUFLEN equ    512            ; coordinate with msntnd.c
  31. BIOSCLK    equ    046ch
  32. HI_MAX    equ    018h
  33. LO_MAX    equ     0b0h
  34.  
  35. _TEXT    SEGMENT  WORD PUBLIC 'CODE'
  36. _TEXT    ENDS
  37. _DATA    SEGMENT  WORD PUBLIC 'DATA'
  38. _DATA    ENDS
  39. CONST    SEGMENT  WORD PUBLIC 'CONST'
  40. CONST    ENDS
  41. _BSS    SEGMENT  WORD PUBLIC 'BSS'
  42. _BSS    ENDS
  43. DGROUP    GROUP    CONST, _BSS, _DATA
  44.     ASSUME  CS: _TEXT, DS: DGROUP, SS: DGROUP
  45.  
  46. _DATA    SEGMENT
  47.     extrn    _doslevel:word, _msgcnt:word, _msgbuf:byte,_display_mode:byte
  48. _DATA    ENDS
  49.  
  50. _TEXT    segment
  51.  
  52.         ; Compute 1's-complement sum of data buffer
  53.         ; unsigned checksum( unsigned word *buf, unsigned cnt)
  54.  
  55.     public    _checksum
  56. _checksum proc    near
  57.     push    bp
  58.     mov    bp,sp
  59.     push    si
  60.     push    bx
  61.     push    cx
  62.     push    dx
  63.         mov     si,[bp+4+0]        ; offset of data to be checked
  64.     mov     cx,[bp+4+2]        ; cx = cnt
  65.     mov    bl,cl
  66.     shr     cx,1            ; group into words
  67.     xor    dx,dx            ; set checksum to 0
  68.         cld
  69.     jcxz    chk3
  70.         clc
  71. chk1:    lodsw
  72.     adc    dx,ax
  73.     loop    chk1
  74.                     ; resolve remainder
  75. chk2:    adc     dx,0
  76.         jc    chk2
  77. chk3:    and    bl,1
  78.     jz    chk5
  79.         xor     ah,ah
  80.     lodsb
  81.         clc
  82.         add     dx,ax
  83. chk4:    adc     dx,0
  84.     jc    chk4
  85. chk5:    mov    ax,dx            ; result into ax
  86.         or      ax,ax
  87.     jnz    chk6
  88.         mov     ax,0ffffh
  89. chk6:    pop    dx
  90.     pop    cx
  91.     pop    bx
  92.     pop    si
  93.     pop    bp
  94.     ret
  95. _checksum endp
  96.  
  97. ;  ntohl(longword x)    32 bit network (big endian) to host (little endian)
  98. ;  htonl(longword x)    32 bit host (little endian) to network (big endian)
  99. ;  intel(longword x)
  100. ;  Reverse order of 4 byte groups between big and little endian forms
  101. ;
  102.     public    _intel, _ntohl, _htonl
  103.  
  104. _intel    proc    near
  105. _ntohl    equ    this byte
  106. _htonl    equ    this byte
  107.     push    bp
  108.     mov    bp,sp
  109.     mov    ax,[bp+4+2]
  110.     mov    dx,[bp+4+0]
  111.     xchg    al,ah
  112.     xchg    dl,dh
  113.     pop    bp
  114.     ret
  115. _intel    endp
  116.  
  117. ;  ntohs(word x)    16 bit network (big endian) to host (little endian)
  118. ;  htons(word x)    16 bit host (little endian) to network (big endian)
  119. ;  intel16(word x)
  120. ;  Reverse order of 2 byte groups between big and little endian forms
  121.     public    _intel16, _ntohs, _htons
  122. _intel16 proc    near
  123. _ntohs    equ    this byte
  124. _htons    equ    this byte
  125.     push    bp
  126.     mov    bp,sp
  127.     mov    ax,[bp+4+0]
  128.     xchg    al,ah
  129.     pop    bp
  130.     ret
  131. _intel16 endp
  132.  
  133.  
  134. ; int ourmod(int top, int bottom)
  135. ; Perform modulo function on 16 bit quantities
  136.     public    _ourmod
  137. _ourmod    proc    near
  138.     push    bp
  139.     mov    bp,sp
  140.     push    bx
  141.     mov    ax,[bp+4+0]        ; top number
  142.     mov    bx,[bp+4+2]        ; bottom number (radix)
  143.     xor    dx,dx
  144.     or    bx,bx            ; bottom is zero?
  145.     jz    ourmod1            ; z = yes, return zero
  146.     div    bx
  147. ourmod1:mov    ax,dx            ; return remainder
  148.     pop    bx
  149.     pop    bp
  150.     ret
  151. _ourmod    endp
  152.  
  153. ; int ourdiv(int top, int bottom)
  154. ; Perform 16 bit integer division
  155.     public    _ourdiv
  156. _ourdiv    proc    near
  157.     push    bp
  158.     mov    bp,sp
  159.     push    bx
  160.     mov    ax,[bp+4+0]        ; top
  161.     mov    bx,[bp+4+2]        ; bottom
  162.     xor    dx,dx
  163.     or    bx,bx            ; divide by zero?
  164.     jz    outdiv1            ; z = yes, divide by one
  165.     div    bx
  166. outdiv1:pop    bx
  167.     pop    bp            ; quotient is returned in ax
  168.     ret
  169. _ourdiv    endp
  170.  
  171. ; int ourlmod(long top, int bottom)
  172. ; Perform 32 bit integer modulo function
  173.     public    _ourlmod
  174. _ourlmod proc    near
  175.     push    bp
  176.     mov    bp,sp
  177.     push    bx
  178.     mov    ax,[bp+4+0]        ; top lower 16 bits
  179.     mov    dx,[bp+4+2]        ; top upper 16 bits
  180.     mov    bx,[bp+4+4]        ; bottom
  181.     or    bx,bx            ; zero?
  182.     jz    outlmo1            ; z = yes divide by 2^16 and quit
  183.     div    bx
  184. outlmo1:mov    ax,dx            ; return remainder in ax
  185.     pop    bx
  186.     pop    bp
  187.     ret
  188. _ourlmod endp
  189.  
  190. ; int ourldiv(long top, int bottom)
  191. ; Perform 32 bit integer division of 32 bit quotient by 16 bit divisor
  192.     public    _ourldiv
  193. _ourldiv proc    near
  194.     push    bp
  195.     mov    bp,sp
  196.     push    bx
  197.     mov    ax,[bp+4+0]        ; top lower 16 bits
  198.     mov    dx,[bp+4+2]        ; top upper 16 bits
  199.     mov    bx,[bp+4+4]        ; bottom
  200.     cmp    dx,bx            ; about to overflow?
  201.     jae    ourldiv1        ; ae = yes, return 0xffffh
  202.     div    bx
  203.     xor    dx,dx            ; clear remainder (high order ret)
  204.     pop    bx
  205.     pop    bp            ; quotient is returned in dx:ax
  206.     ret
  207. ourldiv1:mov    ax,0ffffh        ; overflow indication
  208.     xor    dx,dx            ; clear high order
  209.     pop    bx
  210.     pop    bp
  211.     ret
  212. _ourldiv endp
  213.  
  214. ; long ourlmul(long top, int bottom)
  215. ; Perform 32 bit integer multiplication of 32 bit multiplicand by 16 bit mult
  216.     public    _ourlmul
  217. _ourlmul proc    near
  218.     push    bp
  219.     mov    bp,sp
  220.     push    bx
  221.     push    cx
  222.     mov    ax,[bp+4+2]        ; top upper 16 bits
  223.     mov    bx,[bp+4+4]        ; bottom
  224.     mul    bx
  225.     mov    cx,ax            ; save product (no overflow noted)
  226.     mov    ax,[bp+4+0]        ; top lower 16 bits
  227.     mul    bx
  228.     adc    dx,cx            ; new upper 16 bits
  229.     pop    cx
  230.     pop    bx
  231.     mov    sp,bp
  232.     pop    bp            ; long product is returned in dx:ax
  233.     ret
  234. _ourlmul endp
  235.  
  236. ; void * bcopy(src, dest, count)
  237. ; void *dest, *src;
  238. ; size_t count;
  239. ; copy count bytes from src to dest
  240.     public    _bcopy
  241. _bcopy proc    near
  242.     push    bp
  243.     mov    bp,sp
  244.     push    es
  245.     push    si
  246.     push    di
  247.     push    cx
  248.     mov    ax,ds            ; set to same data segment
  249.     mov    es,ax
  250.     mov    si,[bp+4+0]        ; offset of source
  251.     mov    di,[bp+4+2]        ; offset of destination
  252.     mov    cx,[bp+4+4]        ; count
  253.     cld
  254.     push    di            ; push dest address for return
  255.     jcxz    bcopy2            ; z = nothing to copy
  256.     or    di,di            ; is destination NULL?
  257.     jz    bcopy2            ; z = yes, don't do a thing
  258.     cmp    si,di            ; is source after destination?
  259.     ja    bcopy1            ; a = yes, no overlap problem
  260.     je    bcopy2            ; e = same place, do nothing
  261.     add    di,cx            ; start at the ends
  262.     dec    di
  263.     add    si,cx
  264.     dec    si
  265.     std                ; work backward
  266. bcopy1:    rep    movsb
  267. bcopy2:    pop    ax            ; recover return destination
  268.     cld
  269.     pop    cx
  270.     pop    di
  271.     pop    si
  272.     pop    es
  273.     mov    sp,bp
  274.     pop    bp
  275.     ret
  276. _bcopy endp
  277.  
  278. ; void * bcopy(src, dest, count)
  279. ; void * FAR dest, * FAR src;
  280. ; size_t count;
  281. ; copy count bytes from src to dest
  282.     public    _bcopyff
  283. _bcopyff proc    near
  284.     push    bp
  285.     mov    bp,sp
  286.     push    es
  287.     push    ds
  288.     push    si
  289.     push    di
  290.     push    cx
  291.     push    dx
  292.     lds    si,dword ptr [bp+4+0]    ; source
  293.     les    di,dword ptr [bp+4+4]    ; destination
  294.     mov    cx,[bp+4+8]        ; count
  295.     cld
  296.     jcxz    bcopyff2        ; z = nothing to copy
  297.     mov    ax,ds
  298.     mov    dx,es
  299.     or    ax,ax            ; is destination NULL?
  300.     jz    bcopyff2        ; z = yes, don't do a thing
  301.     cmp    ax,dx            ; is source seg after destination?
  302.     ja    bcopyff1        ; a = yes, no overlap problem
  303.     jb    bcopyff3        ; b = no, no overlap the other way
  304.     cmp    si,di            ; is source offset after destination?
  305.     ja    bcopyff1        ; a = yes, no overlap problem
  306.     je    bcopyff2        ; e = same place, do nothing
  307. bcopyff3:add    di,cx            ; start at the ends
  308.     dec    di
  309.     add    si,cx
  310.     dec    si
  311.     std                ; work backward
  312. bcopyff1:rep    movsb
  313. bcopyff2:xor    ax,ax            ; say null destination
  314.     cld
  315.     pop    dx
  316.     pop    cx
  317.     pop    di
  318.     pop    si
  319.     pop    ds
  320.     pop    es
  321.     mov    sp,bp
  322.     pop    bp
  323.     ret
  324. _bcopyff endp
  325.  
  326.  
  327. ; void * memset(dest, c, count)
  328. ; void *dest;
  329. ; char c;
  330. ; size_t count;
  331. ; Store count copies of byte c in destination area dest
  332.     public    _memset
  333. _memset    proc    near
  334.     push    bp
  335.     mov    bp,sp
  336.     push    es
  337.     push    di
  338.     push    cx
  339.     mov    ax,ds            ; setup data segment
  340.     mov    es,ax
  341.     mov    di,[bp+4+0]        ; offset of destination
  342.     or    di,di            ; is it NULL?
  343.     jz    memset1            ; z = yes, don't do a thing
  344.     push    di            ; save dest for return
  345.     mov    al,[bp+4+2]        ; byte of character c
  346.     mov    ah,al
  347.     mov    cx,[bp+4+4]        ; count
  348.     jcxz    memset1            ; z = do nothing
  349.     cld
  350.     shr    cx,1
  351.     jnc    memset2
  352.     stosb
  353. memset2:rep    stosw
  354.     pop    ax            ; return pointer to destination
  355. memset1:pop    cx
  356.     pop    di
  357.     pop    es
  358.     mov    sp,bp
  359.     pop    bp
  360.     ret
  361. _memset    endp
  362.  
  363. ; Allocate size bytes from DOS free memory.
  364. ; void FAR * malloc(size_t size)
  365. ; Returns FAR pointer in dx:ax, or 0L if failure. Size is an unsigned int.
  366.     public    _malloc
  367. _malloc    proc    near
  368.     push    bp
  369.     mov    bp,sp
  370.     push    bx
  371.     push    cx
  372.     mov    bx,[bp+4+0]        ; bytes wanted
  373.     add    bx,15            ; round up
  374.     mov    cl,4
  375.     shr    bx,cl            ; convert to # of paragraphs
  376.     mov    cx,bx            ; remember quantity wanted
  377.     mov    ah,allocmem        ; DOS memory allocator
  378.     int    dos            ; returns segment in ax
  379.     jc    malloc1            ; c = fatal error
  380.     cmp    cx,bx            ; paragraphs wanted vs delivered
  381.     je    malloc2            ; e = got the block
  382.     push    es            ; insufficient, return it
  383.     mov    es,ax            ; identify the block
  384.     mov    ah,freemem        ; free the unwanted block
  385.     int    dos
  386.     pop    es
  387. malloc1:xor    ax,ax            ; return 0L on failure
  388. malloc2:mov    dx,ax            ; segment
  389.     xor    ax,ax            ; offset
  390.     pop    cx
  391.     pop    bx
  392.     pop    bp
  393.     ret
  394. _malloc    endp
  395.  
  396. ; Free a block of memory allocated from the DOS memory pool.
  397. ; void free(FAR * memblock);
  398.     public    _free
  399. _free    proc    near
  400.     push    bp
  401.     mov    bp,sp
  402.     push    ax
  403.     push    es
  404.     mov    ax,[bp+4+2]        ; get high order (segment) arg
  405.     or    ax,ax            ; NULL?
  406.     jz    free1            ; z = yes, leave it alone
  407.     mov    es,ax            ; identify the block
  408.     mov    ah,freemem        ; free the unwanted block
  409.     int    dos
  410. free1:    pop    es
  411.     pop    ax
  412.     pop    bp
  413.     ret
  414. _free    endp
  415.  
  416. ; int fstchr(const char FAR * p, word len, byte c)
  417. ; finds first occurence of unsigned byte in low part of c and returns
  418. ; the number of bytes preceeding it in the buffer, or len if not found.
  419.     public    _fstchr
  420. _fstchr proc    near
  421.     push    bp
  422.     mov    bp,sp
  423.     push    es
  424.     push    bx
  425.     push    cx
  426.     push    di
  427.     les    di,dword ptr [bp+4+0]    ; Far string address
  428.     mov    bx,es            ; check for NULL
  429.     mov    ax,-1            ; error return value
  430.     or    bx,bx            ; NULL?
  431.     jz    fstchr1            ; z = yes, return -1
  432.     mov    bx,di            ; remember starting offset
  433.     mov    cx,[bp+4+4]        ; number of bytes to examine
  434.     jcxz    fstchr1            ; z = empty string, return -1
  435.     mov    ax,[bp+4+6]        ; pattern is in al
  436.     cld
  437.     repne    scasb
  438.     mov    ax,di            ; ending place
  439.     dec    ax            ; minus auto inc of rep
  440.     sub    ax,bx            ; minus starting offset
  441. fstchr1:pop    di
  442.     pop    cx
  443.     pop    bx
  444.     pop    es
  445.     pop    bp
  446.     ret
  447. _fstchr endp
  448.  
  449. ;  Timer routines - use set_*timeout to receive a clock value which
  450. ;                   can later be tested by calling chk_timeout with
  451. ;                   that clock value to determine if a timeout has
  452. ;                   occurred.  chk_timeout returns 0 if NOT timed out.
  453. ;  Usage:   long set_timeout( int seconds );
  454. ;           long set_ttimeout( int bios_ticks );
  455. ;           int chk_timeout( long value );
  456. ;
  457. ;  (c) 1990 University of Waterloo,
  458. ;           Faculty of Engineering,
  459. ;           Engineering Microcomputer Network Development Office
  460. ;  version
  461. ;    0.1    7-Nov -1990   E. P. Engelke
  462.  
  463.     public    _set_ttimeout
  464. _set_ttimeout proc    near
  465.     push    bp
  466.     mov    bp,sp
  467.     push    es
  468.         xor     ax,ax
  469.         cwd
  470.         mov     es,ax
  471.         mov     ax,[bp+4+0]        ; initial Bios clock ticks
  472.     pushf                ; critical section
  473.     cli
  474.         add     ax,es:[BIOSCLK+0];
  475.         adc     dx,es:[BIOSCLK+2];
  476.     popf                ; end critical section
  477.     pop    es
  478.     pop    bp
  479.     ret
  480. _set_ttimeout endp
  481.  
  482.     public    _set_timeout
  483. _set_timeout proc near
  484.     push    bp
  485.     mov    bp,sp
  486.     push    es
  487.     push    cx
  488.     xor    ax,ax            ; reference low memory
  489.     mov    es,ax
  490.     mov    ax,[bp+4+0]        ; seconds
  491.     xor    dx,dx
  492.     mov    cx,1165
  493.     mul    cx            ; 1165/64 = 18.203...
  494.     mov    cx,6
  495. tmp:    shr    dx,1
  496.     rcr    ax,1
  497.     loop    tmp
  498.     pushf                ; critical section
  499.     cli
  500.     add    ax,es:[BIOSCLK+0]
  501.     adc    dx,es:[BIOSCLK+2]
  502.     popf                ; end critical section
  503.     pop    cx
  504.     pop    es
  505.     pop    bp
  506.     ret
  507. _set_timeout    endp
  508.  
  509.     public    _chk_timeout
  510. _chk_timeout    proc near
  511.     push    bp
  512.     mov    bp,sp
  513.     push    cx
  514.     push    es
  515.     xor    ax,ax
  516.     mov    es,ax
  517.     pushf                ; critical section
  518.     cli
  519.     mov    cx,es:[BIOSCLK+0]
  520.     mov    bx,es:[BIOSCLK+2]
  521.     popf                ; end critical section
  522.     pop    es
  523.     mov    ax,[bp+4+0]        ; timeout value
  524.     mov    dx,[bp+4+2]
  525.     cmp    dx,bx            ; if timeout < clock, has expired
  526.         jb      ret_tru
  527.     cmp    ax,cx
  528.         jbe    ret_tru
  529.                     ; may have gone over by one day
  530.     sub    ax,LO_MAX
  531.     sbb    dx,HI_MAX
  532.     jc    ret_fal            ; c = nope, timeout is today
  533.                     ; test timeout new values
  534.     cmp    dx,bx
  535.     jb    ret_tru
  536.     cmp    ax,cx
  537.     ja    ret_fal
  538. ret_tru:mov    ax,1            ; say have timed out
  539.     pop    cx
  540.     pop    bp
  541.     ret
  542.  
  543. ret_fal:xor    ax,ax            ; say have not timed out
  544.     pop    cx
  545.     pop    bp
  546.     ret
  547. _chk_timeout    endp
  548.  
  549. ; unsigned long realclock(void)
  550.     public    _realclock
  551. _realclock    proc near        ; get Bios time of day dword
  552.     push    es
  553.     xor    ax,ax            ; reference low memory
  554.     mov    es,ax
  555.     pushf                ; critical section
  556.     cli
  557.     mov    ax,es:[BIOSCLK+0]    ; return Bios time of day tick count
  558.     mov    dx,es:[BIOSCLK+2]
  559.     popf                ; end critical section
  560.     pop    es
  561.     ret
  562. _realclock endp
  563.  
  564. ; void _chkstk()
  565. ; Stack checker
  566. ; {
  567. ;  ;
  568. ; }
  569.     public    __chkstk, __aNchkstk
  570. __chkstk proc    near            ; MSC v5.1
  571. __aNchkstk equ    this byte        ; MSC v6.00
  572.     pop    bx            ; pop return address
  573.     sub    sp,ax            ; down adjust stack pointer
  574.     jmp    bx            ; return the no-stack way
  575. __chkstk endp
  576.  
  577. ; Microsoft C v7.0 direct support. Shift left dx:ax by cx. No C calling conv.
  578. ; Long shift left
  579.     public    __aNlshl
  580. __aNlshl proc    near
  581.     jcxz    lshift2            ; z = no shift
  582. lshift1:shl    ax,1
  583.     rcl    dx,1
  584.     loop    lshift1
  585. lshift2:ret
  586. __aNlshl endp
  587.  
  588. ; Microsoft C v7.0 direct support. Shift rgt dx:ax by cx. No C calling conv.
  589. ; Unsigned long shift right
  590.     public    __aNulshr
  591. __aNulshr proc    near
  592.     jcxz    rshift2            ; z = no shift
  593. rshift1:shr    dx,1
  594.     rcr    ax,1
  595.     loop    rshift1
  596. rshift2:ret
  597. __aNulshr endp
  598.  
  599. ; void 
  600. ; outch(char ch)
  601. ; Sends character to the screen via the msgbuf buffer if operating at
  602. ; interrupt level, or via DOS if operating at task level.
  603.     public    _outch
  604. _outch    proc    near
  605.     push    bp
  606.     mov    bp,sp
  607.     push    ax
  608.     push    bx
  609.     cmp    _display_mode,0        ; quiet screen?
  610.     je    outch3            ; e = yes
  611.     mov    al,[bp+4]        ; get the character
  612.     cmp    _doslevel,0        ; at DOS task level?
  613.     je    outch1            ; e = no
  614.     mov    ah,conout        ; use DOS
  615.     push    dx
  616.     mov    dl,al
  617.     int    dos
  618.     pop    dx
  619.     jmp    short outch3
  620. outch1:    cmp    _msgcnt,MSGBUFLEN    ; is buffer filled?
  621.     ja    outch3            ; a = yes, discard this byte
  622.     mov    bx,_msgcnt
  623.     mov    _msgbuf[bx],al
  624.     inc    _msgcnt
  625. outch3:    pop    bx
  626.     pop    ax
  627.     mov    sp,bp
  628.     pop    bp
  629.     ret
  630. _outch    endp
  631.  
  632.  
  633. ; void 
  634. ; outsn(char * string, int count)
  635. ; display counted string
  636.     public    _outsn
  637. _outsn    proc    near
  638.     push    bp
  639.     mov    bp,sp
  640.     push    ax
  641.     push    si
  642.     mov    si,[bp+4]        ; string address
  643.     mov    cx,[bp+4+2]        ; string length
  644.     cld
  645. outsn1:    lodsb
  646.     or    al,al
  647.         jz      outsn2
  648.     push    ax            ; push arg
  649.         call    _outch
  650.     pop    ax            ; clean stack
  651.     loop    outsn1
  652. outsn2:    pop    si
  653.     pop    ax
  654.     mov    sp,bp
  655.     pop    bp
  656.     ret
  657. _outsn    endp
  658.  
  659. ; void 
  660. ; outs(char * string)
  661. ; display asciiz string
  662.     public    _outs
  663. _outs    proc    near
  664.     push    bp
  665.     mov    bp,sp
  666.     push    ax
  667.     push    si
  668.     mov    si,[bp+4]        ; asciiz string address
  669.     cld
  670. outs1:    lodsb
  671.         or      al,al            ; terminator ?
  672.     jz     outs2            ; z = yes
  673.     push    ax            ; push arg
  674.     call    _outch
  675.     pop    ax            ; clean stack
  676.     jmp    short outs1
  677. outs2:    pop    si
  678.     pop    ax
  679.     mov    sp,bp
  680.     pop    bp
  681.     ret
  682. _outs    endp
  683.  
  684. ; void
  685. ; outhex(char c)
  686. ; display char in hex
  687.     public _outhex
  688. _outhex    proc    near
  689.     push    bp
  690.     mov    bp,sp
  691.     push    ax
  692.         mov     ax,[bp+4]        ; incoming character
  693.         mov     cl,4
  694.         shr     al,cl
  695.         call    outh
  696.         mov     ax,[bp+4]
  697.         call    outh
  698.     pop    ax
  699.     mov    sp,bp
  700.     pop    bp
  701.     ret
  702.  
  703. ; worker for outhex
  704. outh    proc    near
  705.     and     al,0fh
  706.         cmp     al,9
  707.         jbe     outh1
  708.         add     al,'A' - '9' - 1
  709. outh1:    add     al,'0'
  710.         push    ax
  711.         call    _outch
  712.         pop     ax
  713.         ret
  714. outh    endp
  715. _outhex    endp
  716.  
  717. ; output a string of hex chars
  718. ; void
  719. ; outhexes(char * string, int count )
  720.     public    _outhexes
  721. _outhexes proc    near
  722.     push    bp
  723.     mov    bp,sp
  724.     push    ax
  725.     push    si            ; preserve such things
  726.     mov    si,[bp+4]        ; get string pointer
  727.     mov    cx,[bp+4+2]        ; get char count
  728.     jcxz    outhexs2        ; z = nothing
  729.     cld
  730. outhexs1:lodsb                ; read a byte
  731.     push    cx            ; save loop counter
  732.     push    ax
  733.     call    _outhex            ; display as hex pair
  734.     add    sp,2            ; clean stack
  735.     pop    cx
  736.     loop    outhexs1        ; do count's worth
  737. outhexs2:pop    si
  738.     pop    ax
  739.     mov    sp,bp
  740.     pop    bp
  741.     ret
  742. _outhexes endp
  743. _TEXT    ends
  744.         end
  745.