123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- %include "defs.asm"
- ; ----------------------------- MOTHER64.ASM -----------------------------
- ; Author: Agner Fog
- ; Date created: 1998
- ; Last modified: 2013-09-11
- ; Source URL: www.agner.org/optimize
- ; Project: asmlib.zip
- ; Language: assembly, NASM/YASM syntax, 64 bit
- ; Description:
- ; Mother-of-All random number generator by Agner Fog
- ; 64-bit mode version for x86-64 compatible microprocessors.
- ;
- ; This is a multiply-with-carry type of random number generator
- ; invented by George Marsaglia. The algorithm is:
- ; S = 2111111111*X[n-4] + 1492*X[n-3] + 1776*X[n-2] + 5115*X[n-1] + C
- ; X[n] = S modulo 2^32
- ; C = floor(S / 2^32)
- ;
- ; C++ prototypes:
- ; extern "C" void MotRandomInit(void * Pthis, int seed); // Initialization
- ; extern "C" int MotIRandom(void * Pthis, int min, int max); // Get integer random number in desired interval
- ; extern "C" double MotRandom(void * Pthis); // Get floating point random number
- ; extern "C" unsigned int MotBRandom(void * Pthis); // Output random bits
- ;
- ; Copyright (c) 2008-2013 GNU General Public License www.gnu.org/licenses
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- default rel
- ; structure definition and constants:
- %INCLUDE "randomah.asi"
- ; publics:
- global MotherBRandom, MotBRandom, ?Windows_MotBRandom
- global MotherRandom, MotRandom, MotherIRandom, MotIRandom
- global MotherRandomInit, MotRandomInit
- section .data
- align 16
- ; Data for single instance of random number generator
- MotherInstance: ISTRUC CRandomMotherA
- IEND
- ; Size of structure
- MotherSize equ $-MotherInstance
- SECTION .CODE ALIGN=16 ; code segment
- ; Single threaded version:
- ; extern "C" unsigned int MotherBRandom(); // Output random bits
- MotherBRandom: ; PROC ; entry for both Windows and Linux call
- lea rcx, [MotherInstance] ; Point to instance
- jmp ?Windows_MotBRandom
- ;MotherBRandom ENDP
- ; Thread-safe version:
- ; extern "C" unsigned int MotBRandom(void * Pthis); // Output random bits
- MotBRandom: ; PROC
- %IFDEF UNIX
- mov rcx, rdi ; translate calling convention
- %ENDIF
- ?Windows_MotBRandom:
- and rcx, -16 ; align
- movdqa xmm1, oword [rcx+CRandomMotherA.M3] ; load M3,M2,M1,M0
- mov eax, [rcx+CRandomMotherA.M0] ; Retrieve previous random number
- movdqa xmm2, xmm1 ; copy
- movdqa xmm3, oword [rcx+CRandomMotherA.MF3] ; factors
- psrlq xmm2, 32 ; move M2,M0 down
- movq qword [rcx+CRandomMotherA.M4], xmm1 ; M4=M3, M3=M2
- movhps qword [rcx+CRandomMotherA.M2], xmm1 ; M2=M1, M1=M0
- pmuludq xmm1, xmm3 ; M3*MF3, M1*MF1
- psrlq xmm3, 32 ; move MF2,MF0 down
- pmuludq xmm2, xmm3 ; M2*MF2, M0*MF0
- paddq xmm1, xmm2 ; P2+P3, P0+P1
- movhlps xmm2, xmm1 ; Get high qword
- paddq xmm1, xmm2 ; P0+P1+P2+P3
- paddq xmm1, oword [rcx+CRandomMotherA.MC] ; +carry
- movq qword [rcx+CRandomMotherA.M0], xmm1 ; Store new M0 and carry
- ; convert to double precision float
- psllq xmm1, 32 ; Discard carry bits
- psrlq xmm1, 12 ; Get bits into mantissa position
- por xmm1, oword [rcx+CRandomMotherA.one] ; Add exponent bits to get number in interval [1,2)
- movq [rcx+CRandomMotherA.RanP1], xmm1 ; Store floating point number
- ret
-
- ;MotBRandom ENDP
-
- ; Single threaded version:
- ; extern "C" unsigned int MotherRandom(); // Get floating point random number
- MotherRandom:
- %IFDEF UNIX
- lea rdi, [MotherInstance] ; Point to instance
- %ENDIF
- %IFDEF WINDOWS
- lea rcx, [MotherInstance] ; Point to instance
- %ENDIF
- ; Thread-safe version:
- ; extern "C" double MotRandom(void * Pthis); // Get floating point random number
- MotRandom:
- %IFDEF UNIX
- mov rcx, rdi ; translate calling convention
- %ENDIF
- and rcx, -16 ; align
- ; get previously prepared random number
- movsd xmm0, [rcx+CRandomMotherA.RanP1]
- subsd xmm0, [rcx+CRandomMotherA.one]
- ; make new random number ready for next time
- call ?Windows_MotBRandom
- ret
- ;MotherRandom ENDP
- ; Single threaded version:
- ; extern "C" unsigned int MotherIRandom(int min, int max); // Get integer random number in desired interval
- MotherIRandom: ; PROC
- %IFDEF UNIX
- mov r8d, esi ; max
- mov edx, edi ; min
- lea rcx, [MotherInstance] ; Pthis = point to instance
- jmp ?Windows_MotIRandom
- %ENDIF
- %IFDEF WINDOWS
- mov r8d, edx ; max
- mov edx, ecx ; min
- lea rcx, [MotherInstance] ; Pthis = point to instance
- jmp ?Windows_MotIRandom
- %ENDIF
- ; MotherIRandom ENDP
- ; Thread-safe version:
- ; extern "C" int MotIRandom(void * Pthis, int min, int max); // Get integer random number in desired interval
- MotIRandom:
- %IFDEF UNIX
- ; translate calling convention
- mov r8d, edx ; max
- mov edx, esi ; min
- mov rcx, rdi ; Pthis
- %ENDIF
-
- ?Windows_MotIRandom: ; LABEL NEAR ; entry for Windows call
- and rcx, -16 ; align
- push r8
- push rdx
- call ?Windows_MotBRandom ; make random number
- pop rcx ; min
- pop r8 ; max
- sub r8d, ecx
- js short rerror ; max < min
- inc r8d ; interval = max - min + 1
- mul r8d ; multiply random number eax by interval and truncate
- lea eax, [rdx+rcx] ; add min to interval*BRandom >> 32
- ret ; ret 8 if not _cdecl calling
- rerror: mov eax, 80000000h ; error exit
- ret ; ret 8 if not _cdecl calling
- ;MotIRandom ENDP
- ; Single threaded version:
- ; extern "C" unsigned int MotherRandomInit(int seed); // Initialization
- MotherRandomInit: ; PROC
- %IFDEF UNIX
- mov edx, edi ; seed
- lea rcx, [MotherInstance] ; Pthis = point to instance
- jmp ?Windows_MotRandomInit
- %ENDIF
- %IFDEF WINDOWS
- mov edx, ecx ; seed
- lea rcx, [MotherInstance] ; Pthis = point to instance
- jmp ?Windows_MotRandomInit
- %ENDIF
- ;MotherRandomInit ENDP
- ; Thread-safe version:
- ; extern "C" void MotRandomInit(void * Pthis, int seed); // Initialization
- MotRandomInit: ; PROC
- %IFDEF UNIX
- ; translate calling convention
- mov edx, esi ; seed
- mov rcx, rdi ; Pthis
- %ENDIF
-
- ?Windows_MotRandomInit: ; LABEL NEAR ; entry for Windows call
- and rcx, -16 ; align
- ; clear my buffer
- push rdi
- push rcx
- mov rdi, rcx ; Pthis
- add rdi, 16
- mov ecx, (MotherSize - 16) / 4
- xor eax, eax
- cld
- rep stosd
- pop rcx
-
- ; insert constants
- mov dword [rcx+CRandomMotherA.one+4], 3FF00000H ; high dword of 1.0
- mov dword [rcx+CRandomMotherA.MF0], 5115 ; factors
- mov dword [rcx+CRandomMotherA.MF1], 1776
- mov dword [rcx+CRandomMotherA.MF2], 1492
- mov dword [rcx+CRandomMotherA.MF3], 2111111111
-
- ; initialize from seed
- mov eax, edx ; seed
- ; make random numbers and put them into buffer
- mov edx, 29943829
- imul eax, edx
- dec eax
- mov [rcx+CRandomMotherA.M0], eax
- imul eax, edx
- dec eax
- mov [rcx+CRandomMotherA.M1], eax
- imul eax, edx
- dec eax
- mov [rcx+CRandomMotherA.M2], eax
- imul eax, edx
- dec eax
- mov [rcx+CRandomMotherA.M3], eax
- imul eax, edx
- dec eax
- mov [rcx+CRandomMotherA.MC], eax
- ; randomize some more
- mov edi, 20 ; loop counter
- r90: call ?Windows_MotBRandom ; (rcx and rdi unchanged)
- dec edi
- jnz r90
- pop rdi
- ret
- ;MotRandomInit ENDP
- ; END
|