home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Multimedia Jumpstart 1.1a / CD_ROM.BIN / develpmt / source / mergedib / mem.asm < prev    next >
Encoding:
Assembly Source File  |  1992-09-12  |  10.3 KB  |  562 lines

  1. ; mem.asm:
  2. ;
  3. ;     (C) Copyright Microsoft Corp. 1991.  All rights reserved.
  4. ;
  5. ;     You have a royalty-free right to use, modify, reproduce and 
  6. ;     distribute the Sample Files (and/or any modified version) in 
  7. ;     any way you find useful, provided that you agree that 
  8. ;     Microsoft has no warranty obligations or liability for any 
  9. ;     Sample Application Files which are modified. 
  10. ;
  11. ; masm -Mx -Zi -DSEGNAME=????? asm.asm
  12. ;
  13.     TITLE MEM.ASM
  14.  
  15. ;****************************************************************
  16. ;* MEM.ASM - Assembly mem-fill and mem-copy routines        *
  17. ;*        for 80286 and 80386                *
  18. ;****************************************************************
  19. ;
  20.  
  21. ?PLM=1        ; PASCAL Calling convention is DEFAULT
  22. ?WIN=1        ; Windows calling convention
  23. ?386=0        ; Use 386 code?
  24.  
  25. .xlist
  26. include cmacros.inc
  27. include windows.inc
  28. .list
  29.  
  30.     externA        __WinFlags        ; in KERNEL
  31.     externA        __AHINCR        ; in KERNEL
  32.     externA        __AHSHIFT        ; in KERNEL
  33.  
  34. ; The following structure should be used to access high and low
  35. ; words of a DWORD.  This means that "word ptr foo[2]" -> "foo.hi".
  36.  
  37. LONG    struc
  38. lo    dw    ?
  39. hi    dw    ?
  40. LONG    ends
  41.  
  42. FARPOINTER    struc
  43. off    dw    ?
  44. sel    dw    ?
  45. FARPOINTER    ends
  46.  
  47. ; -------------------------------------------------------
  48. ;        DATA SEGMENT DECLARATIONS
  49. ; -------------------------------------------------------
  50.  
  51. ifndef SEGNAME
  52.     SEGNAME equ <_TEXT>
  53. endif
  54.  
  55. createSeg %SEGNAME, CodeSeg, word, public, CODE
  56.  
  57. sBegin Data
  58. sEnd Data
  59.  
  60. sBegin CodeSeg
  61. assumes cs,CodeSeg
  62. assumes ds,DATA
  63.  
  64. ;---------------------------Public-Routine------------------------------;
  65. ; fmemfill
  66. ;
  67. ;   fills memory with a bunch of bytes
  68. ;
  69. ; Entry:
  70. ;    lpMem    LPSTR to memory to fill
  71. ;    cbMem    DWORD count of bytes to fill
  72. ;    bFill    BYTE  byte to fill
  73. ;
  74. ; Returns:
  75. ;    nothing
  76. ; Error Returns:
  77. ;    None
  78. ; Registers Preserved:
  79. ;    BP,DS,SI,DI
  80. ; Registers Destroyed:
  81. ;    AX,BX,CX,DX,FLAGS
  82. ; Calls:
  83. ;    fmemfill286 or fmemfill386
  84. ;-----------------------------------------------------------------------;
  85.  
  86. cProc fmemfill,<FAR,PUBLIC,NODATA>,<>
  87. ;     ParmD     lpMem
  88. ;     ParmD     cbMem
  89. ;     ParmB     bFill
  90. cBegin    <nogen>
  91.     mov    ax,__WinFlags
  92.     test    ax,WF_CPU286
  93.     jnz    fmemfill286
  94.     errn$    fmemfill386
  95. cEnd <nogen>
  96.  
  97. cProc fmemfill386,<FAR,PUBLIC,NODATA>,<>
  98.     ParmD    lpMem
  99.     ParmD    cbMem
  100.     ParmB    bFill
  101. cBegin
  102.     .386
  103.     push    edi
  104.  
  105.     cld
  106.     mov    bl, byte ptr bFill        ; repeat the byte through EAX
  107.     mov    bh, bl
  108.     mov    ax,bx
  109.     shl    eax,16
  110.     mov    ax,bx
  111.  
  112.     les    di, lpMem
  113.     movzx    edi,di
  114.     mov    ebx,cbMem
  115.  
  116.     mov    ecx,edi
  117.     neg    ecx
  118.     and    ecx,0011b
  119.     sub    ebx,ecx
  120.     rep    stos byte ptr es:[edi]        ; note can optimize WORD/DWORD writes
  121.     db    67H        ; Fix strange 386 bug
  122.     mov    ecx,ebx
  123.     shr    ecx,2
  124.     rep    stos dword ptr es:[edi]
  125.     db    67H        ; Fix strange 386 bug
  126.     mov    ecx,ebx
  127.     and    ecx,0011b
  128.     rep    stos byte ptr es:[edi]
  129.     db    67H        ; Fix strange 386 bug
  130.  
  131. mf386_exit:
  132.     pop    edi
  133.     .286
  134. cEnd
  135.  
  136. cProc fmemfill286,<FAR,PUBLIC,NODATA>,<di>
  137.     ParmD    lpMem
  138.     ParmD    cbMem
  139.     ParmB    bFill
  140. cBegin
  141.     cld
  142.     les    di, lpMem
  143.     mov    al, byte ptr bFill
  144.     mov    ah, al
  145.  
  146.     mov    bx,cbMem.lo        ; dx:bx = cbMem
  147.     mov    dx,cbMem.hi
  148.  
  149.     mov    cx,bx            ; cbMem == 0?
  150.     or    cx,dx            ;  Yes == get out
  151.     jz    mf_exit
  152.  
  153.     mov    cx,di            ; should we move the first byte
  154.     and    cx,1
  155.     sub    bx,cx
  156.     sbb    dx,0
  157.  
  158.     shr    dx,1            ; divide by two for WORD count
  159.     rcr    bx,1
  160.     pushf                ; save error bit
  161.  
  162.     test    di,1
  163.     jz    mf_loop
  164.  
  165.     stosb                ; move first byte
  166.  
  167.     or    di,di
  168.     jz    mf_next_seg
  169. mf_loop:
  170.     mov    cx,di            ; calc remaining words in seg
  171.     shr    cx,1
  172.     neg    cx
  173.     add    cx,8000h
  174. @@:    sub    bx,cx
  175.     sbb    dx,0
  176.     jl    mf_last_seg
  177.  
  178.     rep    stosw
  179.  
  180. mf_next_seg:
  181.     mov    cx,bx            ; is dx:bx == 0?
  182.     or    cx,dx            ; yes go check last byte
  183.     jz    mf_last_byte
  184.  
  185.     mov    cx,es
  186.     add    cx,__AHINCR
  187.     mov    es,cx
  188.  
  189.     jmp    mf_loop
  190. mf_last_seg:
  191.     add    cx,bx
  192.     rep    stosw
  193. mf_last_byte:
  194.     popf
  195.     jnc    mf_exit
  196.     or    di,di
  197.     jnz    mf_ack
  198.     mov    cx,es
  199.     add    cx,__AHINCR
  200.     mov    es,cx
  201. mf_ack:
  202.     stosb
  203. mf_exit:
  204. cEnd
  205.  
  206. ;---------------------------Public-Routine------------------------------;
  207. ; hmemcpy
  208. ;
  209. ;   copy memory
  210. ;
  211. ; Entry:
  212. ;    lpSrc    HPSTR to copy from
  213. ;    lpDst    HPSTR to copy to
  214. ;    cbMem    DWORD count of bytes to move
  215. ;
  216. ;    NOTE: overlapped copies will work iff lpSrc.sel == lpDst.sel
  217. ;        [This is a lie.     They will always work.]
  218. ;
  219. ; Returns:
  220. ;    destination pointer
  221. ; Error Returns:
  222. ;    None
  223. ; Registers Preserved:
  224. ;    BP,DS,SI,DI
  225. ; Registers Destroyed:
  226. ;    AX,BX,CX,DX,FLAGS
  227. ; Calls:
  228. ;    fmemcpy286 or fmemcpy386
  229. ;-----------------------------------------------------------------------;
  230.  
  231. cProc hmemcpy,<FAR,PASCAL,PUBLIC,NODATA>,<>
  232. ;     ParmD     lpDst
  233. ;     ParmD     lpSrc
  234. ;     ParmD     cbMem
  235. cBegin    <nogen>
  236.     mov    ax,__WinFlags
  237.     test    ax,WF_CPU286
  238.     jz    fmemcpy386
  239.     jmp    FAR PTR    fmemcpy286
  240. cEnd <nogen>
  241.  
  242. cProc fmemcpy386,<FAR,PASCAL,PUBLIC,NODATA>,<ds>
  243.     ParmD    lpDst
  244.     ParmD    lpSrc
  245.     ParmD    cbMem
  246. cBegin
  247.     .386
  248.     push    edi
  249.     push    esi
  250.     cld
  251.  
  252.     mov    ecx,cbMem
  253.     jecxz    mc386_exit
  254.  
  255.     movzx    edi,di
  256.     movzx    esi,si
  257.     lds    si,lpSrc
  258.     les    di,lpDst
  259. ;
  260. ; calculate differance of pointers in "selector" space
  261. ;
  262.     mov    ax,si        ; DX:AX = lpSrc
  263.     mov    dx,ds
  264.  
  265.     mov    bx,es        ; BX = selector of ptr B
  266.  
  267.     mov    cx,__AHSHIFT    ; number of selector bits per 64K 'segment'
  268.     shr    dx,cl        ; linearize ptr A
  269.     shr    bx,cl        ; linearize ptr B
  270. ;
  271. ; DX and BX contain normalized selectors
  272. ;
  273.     sub    ax,di
  274.     sbb    dx,bx        ; do long subtraction.
  275.  
  276.     mov    ecx,cbMem
  277.  
  278.     or    dx,dx
  279.     jns    mc_copy_forward
  280.  
  281.     std
  282.     add    edi,ecx
  283.     add    esi,ecx
  284.  
  285.     sub    edi,4
  286.     sub    esi,4
  287.  
  288.     push    ecx
  289.     shr    ecx,2        ; get count in DWORDs
  290.     rep    movs dword ptr es:[edi], dword ptr ds:[esi]
  291.     db    67H        ; Fix strange 386 bug
  292.     add    edi,3
  293.     add    esi,3
  294.     pop    ecx
  295.     and    ecx,3
  296.     rep    movs byte ptr es:[edi], byte ptr ds:[esi]
  297.     db    67H        ; Fix strange 386 bug
  298.     jmp    mc386_exit
  299.  
  300. mc_copy_forward:
  301.     push    ecx
  302.     shr    ecx,2        ; get count in DWORDs
  303.     rep    movs dword ptr es:[edi], dword ptr ds:[esi]
  304.     db    67H
  305.     pop    ecx
  306.     and    ecx,3
  307.     rep    movs byte ptr es:[edi], byte ptr ds:[esi]
  308.     db    67H
  309.     nop
  310. mc386_exit:
  311.     cld
  312.     pop    esi
  313.     pop    edi
  314.     mov    dx,lpDst.sel    ; return destination address
  315.     mov    ax,lpDst.off
  316.     .286
  317. cEnd
  318.  
  319. cProc fmemcpy286,<FAR,PASCAL,PUBLIC,NODATA>,<ds,si,di>
  320.     ParmD    lpDst
  321.     ParmD    lpSrc
  322.     ParmD    cbMem
  323. cBegin
  324.     mov    cx,cbMem.lo    ; CX holds count
  325.     or    cx,cbMem.hi    ; or with high word
  326.     jnz    @f
  327.     jmp    empty_copy
  328. @@:
  329.     lds    si,lpSrc      ; DS:SI = src
  330.     les    di,lpDst      ; ES:DI = dst
  331. ;
  332. ; calculate differance of pointers in "selector" space
  333. ;
  334.     mov    ax,si        ; DX:AX = lpSrc
  335.     mov    dx,ds
  336.  
  337.     mov    bx,es        ; BX = selector of ptr B
  338.  
  339.     mov    cx,__AHSHIFT    ; number of selector bits per 64K 'segment'
  340.     shr    dx,cl        ; linearize ptr A
  341.     shr    bx,cl        ; linearize ptr B
  342. ;
  343. ; DX and BX contain normalized selectors
  344. ;
  345.     sub    ax,di
  346.     sbb    dx,bx        ; do long subtraction.
  347.  
  348.     mov    cx,cbMem.lo
  349.  
  350.     or    dx,dx
  351.     jns    forward_copy    ; difference is positive, so copy forward
  352.  
  353. ; see if the blocks intersect: is source + count > dest?
  354. ; equivalently, is source-dest + count > 0 ?
  355. ;    sub    ax,cx
  356. ;    sbb    dx,0
  357. ;    jnc    next        ; This looks wrong.  Recheck!
  358.  
  359.     add    ax,cx
  360.     adc    dx,cbMem.hi
  361.     jc    reverse_copy    ; carry, so >0, thus they do hit.
  362.  
  363. forward_copy:
  364.     jmp    next
  365.     
  366. reverse_copy:
  367. ; first, we have to set ds:si and es:di to the _ends_ of the blocks
  368.  
  369.     sub    cx,2
  370.     sbb    cbMem.hi,0    ; subtract 2 from (long) count
  371.     
  372.     xor    ax,ax        
  373.     add    si,cx
  374.     adc    ax,cbMem.hi
  375.  
  376.     push    cx
  377.     mov    cx,__AHSHIFT
  378.     shl    ax,cl
  379.     pop    cx
  380.     mov    bx,ds
  381.     add    ax,bx        ; advance DS
  382.     mov    ds,ax
  383.  
  384.     xor    ax,ax
  385.     add    di,cx
  386.     adc    ax,cbMem.hi
  387.  
  388.     push    cx
  389.     mov    cx,__AHSHIFT
  390.     shl    ax,cl
  391.     pop    cx
  392.     mov    bx,es
  393.     add    ax,bx        ; advance ES
  394.     mov    es,ax
  395.  
  396.     add    cx,2
  397.     adc    cbMem.hi,0    ; restore count
  398. ;
  399. ;    DS:SI += Count
  400. ;    ES:DI += Count
  401. ;    While Count != 0 Do
  402. ;        Num = MIN(Count,SI+1,DI+1)
  403. ;        Reverse Copy "Num" Bytes from DS:SI to ES:DI
  404. ;            (SI -= Num, DI -= Num)
  405. ;        Count -= Num
  406. ;        If Count == 0 Then
  407. ;            BREAK
  408. ;        If SI == 0xFFFF Then
  409. ;            DS -= __AHINCR
  410. ;        If DI == 0xFFFF Then
  411. ;            ES -= __AHINCR
  412. ;
  413. next_r:
  414.     mov    ax,si
  415.  
  416.     sub    ax,di
  417.     sbb    bx,bx
  418.     and    ax,bx
  419.     add    ax,di        ; AX = MIN(SI, DI)
  420.     
  421.     xor    bx,bx
  422.     add    ax,2        ; AX = Num = MIN(SI+2,DI+2)
  423.     adc    bx,0        ; bx==1 if exactly 64k
  424.  
  425.     test    cbMem.hi,-1    ; is high word not zero?
  426.     jnz    @f        ; at least 64k to go
  427.  
  428.     sub    ax,cx
  429.     sbb    bx,bx
  430.     and    ax,bx
  431.     add    ax,cx        ; AX = Num = MIN(Count,SI+2,DI+2)
  432.     adc    bx,0
  433.  
  434. @@:
  435.     xchg    ax,cx
  436.     sub    ax,cx        ; Count -= Num
  437.     sbb    cbMem.hi,bx
  438.  
  439.     std
  440.     shr    bx,1
  441.     rcr    cx,1        ; if bx==1, then cx ends up 0x8000
  442.     jnc    @f
  443.     inc    si        ; adjust pointers for byte move
  444.     inc    di
  445.     movsb            ; move first byte, if necessary
  446.     dec    si        ; realign pointers
  447.     dec    di
  448. @@:
  449.     rep    movsw
  450.     cld
  451.  
  452.     mov    cx,ax        ; restore cx
  453.     or    ax,cbMem.hi
  454.  
  455.     jz    done        ; If Count == 0 Then BREAK
  456.  
  457.     cmp    si,-2        ; if SI wraps, update DS
  458.     jnz    @f        
  459. ;
  460.     mov    ax,ds
  461.     sub    ax,__AHINCR
  462.     mov    ds,ax        ; update DS if appropriate
  463. @@:
  464.     cmp    di,-2        ; if DI wraps, update ES
  465.     jnz    next_r
  466. ;
  467.     mov    ax,es
  468.     sub    ax,__AHINCR
  469.     mov    es,ax        ; update ES if appropriate
  470.     jmp    next_r
  471.  
  472. ;
  473. ;    While Count != 0 Do
  474. ;        If (Count + SI > 65536) OR (Count + DI > 65536) Then
  475. ;            Num = Min(65536-SI, 65536-DI)
  476. ;        Else
  477. ;            Num = Count
  478. ;        Copy "Num" Bytes from DS:SI to ES:DI (SI += Num, DI += Num)
  479. ;        Count -= Num
  480. ;        If Count == 0 Then
  481. ;            BREAK
  482. ;        If SI == 0 Then
  483. ;            DS += __AHINCR
  484. ;        If DI == 0 Then
  485. ;            ES += __AHINCR
  486. ;
  487. next:
  488.     mov    ax,cx
  489.     dec    ax
  490.  
  491.     mov    ax,di
  492.     not    ax        ; AX = 65535-DI
  493.  
  494.     mov    dx,si
  495.     not    dx        ; DX = 65535-SI
  496.  
  497.     sub    ax,dx
  498.     sbb    bx,bx
  499.     and    ax,bx
  500.     add    ax,dx        ; AX = MIN(AX,DX) = MIN(65535-SI,65535-DI)
  501.  
  502.     ; problem: ax might have wrapped to zero
  503.  
  504.     test    cbMem.hi,-1
  505.     jnz    plentytogo    ; at least 64k still to copy
  506.     
  507.     dec    cx        ; this is ok, since high word is zero
  508.     sub    ax,cx
  509.     sbb    bx,bx
  510.     and    ax,bx
  511.     add    ax,cx        ; AX = MIN(AX,CX)
  512.     inc    cx
  513.  
  514. plentytogo:
  515.     xor    bx,bx
  516.     add    ax,1        ; AX = Num = MIN(count,65536-SI,65536-DI)
  517.                 ; we must check the carry here!
  518.     adc    bx,0        ; BX could be 1 here, if CX==0 indicating
  519.                 ; exactly 64k to copy
  520.     xchg    ax,cx
  521.     sub    ax,cx        ; Count -= Num
  522.     sbb    cbMem.hi,bx
  523.  
  524.     shr    bx,1
  525.     rcr    cx,1        ; if bx==1, then cx ends up 0x8000
  526.     rep    movsw
  527.     jnc    @f
  528.     movsb            ; move last byte, if necessary
  529. @@:
  530.     mov    cx,ax        ; put low word of count back in cx
  531.     or    ax,cbMem.hi
  532.  
  533.     jz    done        ; If Count == 0 Then BREAK
  534.  
  535.     or    si,si        ; if SI wraps, update DS
  536.     jnz    @f
  537. ;
  538.     mov    ax,ds
  539.     add    ax,__AHINCR
  540.     mov    ds,ax        ; update DS if appropriate
  541. @@:
  542.     or    di,di        ; if DI wraps, update ES
  543.     jnz    next
  544. ;
  545.     mov    ax,es
  546.     add    ax,__AHINCR
  547.     mov    es,ax        ; update ES if appropriate
  548.     jmp    next
  549. ;
  550. ; Restore registers and return
  551. ;
  552. done:
  553. empty_copy:
  554.     mov    dx,lpDst.sel    ; return destination address
  555.     mov    ax,lpDst.off
  556. cEnd
  557.  
  558. sEnd
  559.  
  560. sEnd CodeSeg
  561. end
  562.