;*******************************************************************************
;memset.asm - set a section of memory to all one byte
;
;       Copyright (c) Microsoft Corporation. All rights reserved.
;
;Purpose:
;       contains the memset() routine
;
;*******************************************************************************

.code

;***
;char *memset(dst, value, count) - sets "count" bytes at "dst" to "value"
;
;Purpose:
;       Sets the first "count" bytes of the memory starting
;       at "dst" to the character value "value".
;
;       Algorithm:
;       char *
;       memset (dst, value, count)
;               char *dst;
;               char value;
;               unsigned int count;
;               {
;               char *start = dst;
;
;               while (count--)
;                       *dst++ = value;
;               return(start);
;               }
;
;Entry:
;       char *dst - pointer to memory to fill with value
;       char value - value to put in dst bytes
;       int count - number of bytes of dst to fill
;
;Exit:
;       returns dst, with filled bytes
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************

        public  memset
memset proc
;
; On entry:  rcx=dest, rdx=value, r8=count
;
        test    r8,r8           ; 0?
        jz      short toend     ; if so, nothing to do

        xor     rax,rax         
        mov     al,dl           ; al = value
        mov     rdx,r8          ; rdx = "count"
        mov     r8,rcx          ; scroll away dest for return

; Align address on qword boundary

        push    rdi             ; preserve rdi
        mov     rdi,rcx         ; rdi = dest pointer

        cmp     rdx,8           ; if it's less then 8 bytes
        jb      tail            ; tail needs rdi and rdx to be initialized

        neg     rcx
        and     rcx,7           ; ecx = # bytes before dword boundary
        jz      short qwords    ; jump if address already aligned

        sub     rdx,rcx         ; edx = adjusted count (for later)
adjust_loop:
        mov     [rdi],al
        add     rdi,1
        sub     rcx,1
        jnz     adjust_loop

qwords:
; set all 8 bytes of eax to [value]
        mov     rcx,rax         ; rcx=0/0/0/0/0/0/0/value
        shl     rax,8           ; rax=0/0/0/0/0/0/value/0

        add     rax,rcx         ; rax=0/0/0/0/0/0/0/val/val

        mov     rcx,rax         ; rcx=0/0/0/0/0/0/0/val/val

        shl     rax,10h         ; rax=0/0/0/0/val/val/0/0

        add     rax,rcx         ; rax = all 4 bytes = [value]
        
        mov     rcx,rax         ; rcx =          0/0/0/0/val/val/val/val
        shl     rax,20h         ; rax = val/val/val/val/0/0/0/0/
        
        add     rax,rcx         ; rax = val/val/val/val/val/val/val/val
        

; Set qword-sized blocks
        mov     rcx,rdx         ; move original count to ecx
        and     rdx,7           ; prepare in edx byte count (for tail loop)
        shr     rcx,3           ; adjust ecx to be dword count
        jz      tail            ; jump if it was less then 4 bytes

        rep     stosq
main_loop_tail:
        test    rdx,rdx         ; if there is no tail bytes,
        jz      finish          ; we finish, and it's time to leave
; Set remaining bytes

tail:
        mov     [rdi],al        ; set remaining bytes
        add     rdi,1

        sub     rdx,1           ; if there is some more bytes
        jnz     tail            ; continue to fill them

; Done
finish:
        mov     rax,r8          ; return dest pointer
        pop     rdi             ; restore edi

        ret

toend:
        mov     rax,rcx         ; return dest pointer

        ret

memset  endp

        end
