; ---------------------------------------------------------------------------
; FILE: well512.Asm
; DATE: January 16, 2022
; ---------------------------------------------------------------------------
align 16
proc well512_next
; ---------------------------------------------------------------------------
; Output:
;   st0 = next random value in [0..1]
; ---------------------------------------------------------------------------
    local   a:DWORD
    local   b:DWORD
    local   c:DWORD
    local   d:DWORD

    pusha
    mov     ebx, [glb_Well512]
    mov     ecx, [ebx + TWell512.Index]
    lea     esi, [ebx + TWell512.State]
    ;
    ; a = state[index];
    ;
    mov     eax, [esi + ecx*4]
    mov     [a], eax
    ;
    ; c = state[(index+13)&15];
    ;
    lea     edx, [ecx + 13]
    and     edx, 15
    mov     eax, [esi + edx*4]
    mov     [c], eax
    ;
    ; b = a^c^(a<<16)^(c<<15);
    ;
    mov     eax, [a]
    mov     edx, eax
    xor     eax, [c]
    shl     edx, 16
    xor     eax, edx
    mov     edx, [c]
    shl     edx, 15
    xor     eax, edx
    mov     [b], eax
    ;
    ; c = state[(index+9)&15];
    ;
    lea     edx, [ecx + 9]
    and     edx, 15
    mov     eax, [esi + edx*4]
    mov     [c], eax
    ;
    ; c ^= (c>>11);
    ;
    shr     eax, 11
    xor     [c], eax
    ;
    ; a = state[index] = b^c;
    ;
    mov     eax, [b]
    xor     eax, [c]
    mov     [a], eax
    mov     [esi + ecx*4], eax
    ;
    ; d = a^((a<<5)& 0xDA442D24);
    ;
    mov     edx, eax
    shl     eax, 5
    and     eax, 0xDA442D24
    xor     edx, eax
    mov     [d], edx
    ;
    ; index = (index+15)&15;
    ;
    add     ecx, 15
    and     ecx, 15
    mov     [ebx + TWell512.Index], ecx
    ;
    ; a = state[index];
    ;
    mov     eax, [esi + ecx*4]
    mov     [a], eax
    ;
    ; state[index] = a^b^d^(a<<2)^(b<<18)^(c<<28);
    ;
    mov     edx, eax
    shl     edx, 2
    xor     eax, [b]
    xor     eax, [d]
    xor     eax, edx
    mov     edx, [b]
    shl     edx, 18
    xor     eax, edx
    mov     edx, [c]
    shl     edx, 28
    xor     eax, edx
    mov     [esi + ecx*4], eax
    ;
    ; divide EAX by 0x100000000 using FPU
    ;
    push    0 eax
    fild    qword [esp]
    push    1 0
    fild    qword [esp]
    fdivp
    add     esp, 16

    popa
    ret
endp

align 16
proc well512_sum uses ecx, count:DWORD
; ---------------------------------------------------------------------------
; Output:
;   st0 = a SUM of [count] random values
; ---------------------------------------------------------------------------
    mov     ecx, [count]
    fldz

@@:
    call    well512_next
    faddp
    loop    @r
    ret
endp

align 16
proc well512_tholian_xy
; ---------------------------------------------------------------------------
; Output:
;   eax = 1 or 10
; ---------------------------------------------------------------------------
    call    well512_next
    stdcall math_cmp_st0_float32, 0.5
    ja      @f

    xor     eax, eax
    inc     eax
    ret

@@:
    push    10
    pop     eax
    ret
endp

align 16
proc well512_iran low:DWORD, high:DWORD
; ---------------------------------------------------------------------------
; Output:
;   eax = Int32 value in range [low..high]
; ---------------------------------------------------------------------------
    mov     eax, [high]
    sub     eax, [low]

    call    well512_next

    push    eax
    fimul   dword [esp]
    fistp   dword [esp]
    pop     eax
    add     eax, [low]
    ret
endp

align 16
proc well512_iran8 uses edi eax, pquad:DWORD
; ---------------------------------------------------------------------------
    mov     edi, [pquad]
    stdcall well512_iran, 1, 8
    stosb

    stdcall well512_iran, 1, 8
    stosb
    ret
endp

align 16
proc well512_iran10 uses edi eax, psect:DWORD
; ---------------------------------------------------------------------------
    mov     edi, [psect]
    stdcall well512_iran, 1, 10
    stosb

    stdcall well512_iran, 1, 10
    stosb
    ret
endp

align 16
proc well512_seed_by_text ansi:DWORD
; ---------------------------------------------------------------------------
    pusha
    xor     eax, eax
    xor     edx, edx
    mov     ecx, 5381
    mov     esi, [ansi]

    .while ([esi] <> dl)
        lodsb

        mov     ebx, ecx
        shl     ecx, 5
        add     ecx, ebx
        add     ecx, eax
    .endw

    stdcall well512_seed, ecx
    popa
    ret
endp

align 16
proc well512_seed seed:DWORD
; ---------------------------------------------------------------------------
    local   tm:SYSTEMTIME
    local   tf:FILETIME

    pusha
    mov     edx, [seed]
    ;
    ; if seed value=0 -- use the # of seconds since 1970
    ;
    .if (~edx)
        lea     edi, [tm]
        invoke  GetLocalTime, edi
        sub     [edi + SYSTEMTIME.wYear], 400

        lea     esi, [tf]
        invoke  SystemTimeToFileTime, edi, esi

        fild    qword [esi]
        push    10000000
        fidiv   dword [esp]
        fistp   dword [esp]
        pop     edx
    .endif
    ;
    ; use XorShift32 to make 16 DWORDs into TWell512.State array
    ;
    push    16
    pop     ecx

    mov     ebx, [glb_Well512]
    lea     edi, [ebx + TWell512.State]
    mov     eax, edx

@@:
    shl     edx, 13
    xor     eax, edx

    mov     edx, eax
    shr     edx, 17
    xor     eax, edx

    mov     edx, eax
    shl     edx, 5
    xor     eax, edx

    stosd
    mov     edx, eax
    loop    @r
    ;
    ; reset the next index
    ;
    xor     eax, eax
    mov     [ebx + TWell512.Index], eax

    popa
    ret
endp





