; ============================================================================= ; ; Litos8 random generator ; ; ============================================================================= ; General algorithm (new_seed = old_seed*17405 + 10395331) for the random ; generator is taken from interpreted BASIC and is described in Microsoft ; Knowledgebase article Q28150. Other possible coefficients are: ; 214013/2531011, 17405/10395331, 214013/13737667, (214013/10395331,) 69069/1 ; ; Random numbers in interval are usually calculated with modulo operation. ; Such random numbers are not evenly spreaded out, their density is lower at ; end of the interval. Therefore in this generator repeated generation is used ; of random numbers until suitable number is found, such numbers are spreaded ; evenly in whole interval. ; ----------------------------------------------------------------------------- ; Exported user functions (17): ; RandInit - initialize random generator ; RandShift - shift random generator with an event ; RandByte - get random byte ; RandWord - get random word ; RandDWord - get random dword ; RandByteMax - get random byte with max value ; RandWordMax - get random word with max value ; RandDWordMax - get random dword with max value ; RandSByteMax - get random signed byte with max value ; RandSWordMax - get random signed word with max value ; RandSDWordMax - get random signed dword with max value ; RandByteInt - get random byte in interval ; RandWordInt - get random word in interval ; RandDWordInt - get random dword in interval ; RandSByteInt - get random signed byte in interval ; RandSWordInt - get random signed word in interval ; RandSDWordInt - get random signed dword in interval ; ----------------------------------------------------------------------------- RNDCOEFF1 EQU 17405 ; random coefficient 1 (multiple) RNDCOEFF2 EQU 10395331 ; random coefficient 2 (add) RNDCOEFF2H EQU 9Eh ; random coefficient 2 HIGH (add) RNDCOEFF2L EQU 9EC3h ; random coefficient 2 LOW (add) CODE_SECTION ; ----------------------------------------------------------------------------- ; Initialize random generator ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = new random generator seed ; BL = flag, 0 = use pseudorandom sequence, 1 = enable events ; ----------------------------------------------------------------------------- ; ------------- set new seed value RandInit: mov [RandSeed],ax ; set seed LOW mov [RandSeed+2],dx ; set seed HIGH mov [RandEventEnable],bl ; set flag, enable events ; ------------- shuffle random generator push ax ; push AX push cx ; push CX mov cx,20 ; CX <- number of shuffles RandInit2: call RandNext ; next random generator value loop RandInit2 ; next value pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Shift random generator with an event ; ----------------------------------------------------------------------------- ; INPUT: AX,BX,CX = shift random value ; ----------------------------------------------------------------------------- RandShift: cmp byte [RandEventEnable],0 ; enabled events? je short RandShift2 ; events not enabled add [RandSeed+1],ah adc [RandSeed+2],al adc [RandSeed],bl adc [RandSeed+3],bh adc [RandSeed+1],cl adc [RandSeed+2],ch RandShift2: ret ; ----------------------------------------------------------------------------- ; Next random generator value, get random word ; ----------------------------------------------------------------------------- ; OUTPUT: AX = random word (0 to 0ffffh) ; ----------------------------------------------------------------------------- ; ------------- push registers RandWord: RandNext: push bx ; push BX push cx ; push CX push dx ; push DX push si ; push SI push di ; push DI ; ------------- prepare accumulator -> DI:SI:CX:BX xor di,di ; DI <- 0 xor si,si ; SI <- 0 mov cx,RNDCOEFF2H ; CX <- coefficient 2 HIGH mov bx,RNDCOEFF2L ; BX <- coefficient 2 LOW ; ------------- multiple seed with COEF1 and add to accumulator mov ax,RNDCOEFF1 ; AX <- coefficient 1 mov dx,[RandSeed] ; DX <- seed WORD 1 mul dx ; DX:AX <- multiple 1 add bx,ax ; BX <- add result to accumulator 1 adc cx,dx ; CX <- add result to accumulator 2 adc si,byte 0 ; SI <- carry 3 adc di,byte 0 ; DI <- carry 4 mov ax,RNDCOEFF1 ; AX <- coefficient 1 mov dx,[RandSeed+2] ; DX <- seed WORD 2 mul dx ; DX:AX <- multiple 2 add cx,ax ; CX <- add result to accumulator 2 adc si,dx ; SI <- add result to accumulator 3 adc di,byte 0 ; DI <- carry 4 mov ax,RNDCOEFF1 ; AX <- coefficient 1 mov dx,[RandSeed+4] ; DX <- seed WORD 3 mul dx ; DX:AX <- multiple 3 add si,ax ; SI <- add result to accumulator 3 adc di,dx ; DI <- add result to accumulator 4 mov ax,RNDCOEFF1 ; AX <- coefficient 1 mov dx,[RandSeed+6] ; DX <- seed WORD 4 mul dx ; DX:AX <- multiple 4 add di,ax ; DI <- add result to accumulator 4 ; ------------- save new seed value (in mixed order - to shuffle value) mov [RandSeed],si ; new value 1 <- old value 3 mov [RandSeed+2],di ; new value 2 <- old value 4 mov [RandSeed+4],cx ; new value 3 <- old value 2 mov [RandSeed+6],bx ; new value 4 <- olf value 1 ; ------------- pop registers xchg ax,cx ; AX <- new value 3, old value 2 pop di ; pop DI pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Get random byte ; ----------------------------------------------------------------------------- ; OUTPUT: AL = random byte (0 to 0ffh) ; ----------------------------------------------------------------------------- RandByte: push dx ; push DX push ax ; push AX call RandNext ; next global random seed (-> AX) xchg ax,dx ; DX <- save random word pop ax ; pop AX mov al,dl ; AL <- random byte pop dx ; pop DX ret ; ----------------------------------------------------------------------------- ; Get random double word ; ----------------------------------------------------------------------------- ; OUTPUT: DX:AX = random double word (0 to 0ffffffffh) ; ----------------------------------------------------------------------------- RandDWord: call RandWord ; get random word (-> AX) xchg ax,dx ; DX <- first random word call RandWord ; get random word (-> AX) ret ; ----------------------------------------------------------------------------- ; Get random unsigned byte with max value ; ----------------------------------------------------------------------------- ; INPUT: AL = maximal unsigned value (0 to 0ffh) ; OUTPUT: AL = random byte (0 to maximal value) ; ----------------------------------------------------------------------------- ; ------------- Check maximal value 0 RandByteMax: or al,al ; zero maximal value? jz short RandByteMax8 ; maximal value is 0 ; ------------- Push registers push cx ; push CX push dx ; push DX ; ------------- preset mask value -> DL mov dl,0ffh ; DL <- preset mask 0ffh cmp al,0fh ; check max. value ja short RandByteMax2 ; max. value is greater mov dl,0fh ; DL <- preset mask 0fh ; ------------- Prepare mask of maximal value -> CL RandByteMax2: mov cl,dl ; CL <- mask shr dl,1 ; DL <- mask/2 cmp dl,al ; check mask jae short RandByteMax2 ; new mask is ok, use it ; ------------- Find required value -> AL xchg ax,dx ; DL <- required maximum value RandByteMax4: call RandByte ; get random byte (-> AL) and al,cl ; mask result cmp al,dl ; is this value allowed? ja short RandByteMax4 ; invalid value, next attempt ; ------------- Pop registers pop dx ; pop DX pop cx ; pop CX RandByteMax8: ret ; ----------------------------------------------------------------------------- ; Get random signed byte with max value ; ----------------------------------------------------------------------------- ; INPUT: AL = maximal signed value (-128 to +127) ; OUTPUT: AL = random byte (0 to maximal value) ; ----------------------------------------------------------------------------- RandSByteMax: or al,al ; is it unsigned value? jns short RandByteMax ; it is unsigned value or zero neg al ; correct maximal value call RandByteMax ; generate random byte neg al ; correct result ret ; ----------------------------------------------------------------------------- ; Get random unsigned word with max value ; ----------------------------------------------------------------------------- ; INPUT: AX = maximal unsigned value (0 to 0ffffh) ; OUTPUT: AX = random word (0 to maximal value) ; ----------------------------------------------------------------------------- ; ------------- Check maximal value 0 RandWordMax: or ax,ax ; zero maximal value? jz short RandWordMax8 ; maximal value is 0 ; ------------- Push registers push cx ; push CX push dx ; push DX ; ------------- preset mask value -> DX mov dx,0ffffh ; DX <- preset mask 0ffffh cmp ax,0ffh ; check max. value ja short RandWordMax2 ; max. value is greater mov dx,0ffh ; DX <- preset mask 0ffh ; ------------- Prepare mask of maximal value -> CX RandWordMax2: mov cx,dx ; CX <- mask shr dx,1 ; DX <- mask/2 cmp dx,ax ; check mask jae short RandWordMax2 ; new mask is ok, use it ; ------------- Find required value -> AX xchg ax,dx ; DX <- required maximum value RandWordMax4: call RandWord ; get random word (-> AX) and ax,cx ; mask result cmp ax,dx ; is this value allowed? ja short RandWordMax4 ; invalid value, next attempt ; ------------- Pop registers pop dx ; pop DX pop cx ; pop CX RandWordMax8: ret ; ----------------------------------------------------------------------------- ; Get random signed word with max value ; ----------------------------------------------------------------------------- ; INPUT: AX = maximal signed value (-32768 to +32767) ; OUTPUT: AX = random word (0 to maximal value) ; ----------------------------------------------------------------------------- RandSWordMax: or ax,ax ; is it unsigned value? jns short RandWordMax ; it is unsigned value or zero neg ax ; correct maximal value call RandWordMax ; generate random word neg ax ; correct result ret ; ----------------------------------------------------------------------------- ; Get random unsigned double word with max value ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = maximal unsigned value (0 to 0ffffffffh) ; OUTPUT: DX:AX = random double word (0 to maximal value) ; ----------------------------------------------------------------------------- ; ------------- Check maximal value 0 RandDWordMax: or ax,ax ; zero maximal value? jnz short RandDWordMax2 ; not zero value or dx,dx ; zero maximal value? jz short RandDWordMax8 ; maximal value is 0 ; ------------- Push registers RandDWordMax2: push cx ; push CX push si ; push SI push di ; push DI push bp ; push BP ; ------------- preset mask value -> BP:DI xor bp,bp ; BP <- 0 dec bp ; BP <- 0ffffh mov di,bp ; DI <- 0ffffh or dx,dx ; check max. value HIGH jnz short RandDWordMax4 ; greater than 0ffffh xor bp,bp ; BP <- 0 ; ------------- Prepare mask of maximal value -> SI:CX RandDWordMax4: mov cx,di ; CX <- mask LOW mov si,bp ; SI <- mask HIGH shr bp,1 ; BP <- mask/2 HIGH rcr cx,1 ; CX <- mask/2 LOW cmp bp,dx ; check mask HIGH jb short RandDWordMax5 ; mask found OK ja short RandDWordMax4 ; use new mask cmp di,ax ; check mask LOW jae short RandDWordMax4 ; use new mask ; ------------- Find required value RandDWordMax5: xchg ax,di ; DI <- max. value LOW mov bp,dx ; BP <- max. value HIGH RandDWordMax6: call RandDWord ; get random double word (-> DX:AX) and ax,cx ; mask result LOW and dx,si ; mask result HIGH cmp dx,bp ; check result HIGH jb short RandDWordMax7 ; result is OK ja short RandDWordMax6 ; try next value cmp ax,di ; check result LOW ja short RandDWordMax6 ; try next value ; ------------- Pop registers RandDWordMax7: pop bp ; pop BP pop di ; pop DI pop si ; pop SI pop cx ; pop CX RandDWordMax8: ret ; ----------------------------------------------------------------------------- ; Get random signed double word with max value ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = maximal signed value (-80000000h to +7fffffffh) ; OUTPUT: DX:AX = random double word (0 to maximal value) ; ----------------------------------------------------------------------------- RandSDWordMax: or dx,dx ; is it unsigned value? jns short RandDWordMax ; it is unsigned value or zero neg ax ; correct maximal value LOW adc dx,byte 0 ; carry neg dx ; correct maximal value HIGH call RandDWordMax ; generate random double word neg ax ; correct result LOW adc dx,byte 0 ; carry neg dx ; correct result HIGH ret ; ----------------------------------------------------------------------------- ; Get random byte in interval ; ----------------------------------------------------------------------------- ; INPUT: AL = maximal value (signed or unsigned) ; AH = minimal value (signed or unsigned) ; OUTPUT: AL = random byte (min to max) ; ----------------------------------------------------------------------------- RandByteInt: RandSByteInt: sub al,ah ; AL <- new maximal value call RandByteMax ; generate random byte add al,ah ; AL <- add minimal value ret ; ----------------------------------------------------------------------------- ; Get random word in interval ; ----------------------------------------------------------------------------- ; INPUT: AX = maximal value (signed or unsigned) ; DX = minimal value (signed or unsigned) ; OUTPUT: AX = random word (min to max) ; ----------------------------------------------------------------------------- RandWordInt: RandSWordInt: sub ax,dx ; AX <- new maximal value call RandWordMax ; generate random word add ax,dx ; AX <- add minimal value ret ; ----------------------------------------------------------------------------- ; Get random double word in interval ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = maximal value (signed or unsigned) ; BX:CX = minimal value (signed or unsigned) ; OUTPUT: DX:AX = random double word (min to max) ; ----------------------------------------------------------------------------- RandDWordInt: RandSDWordInt: sub ax,cx ; AX <- new maximal value LOW sbb dx,bx ; BX <- new maximal value HIGH call RandDWordMax ; generate random double word add ax,cx ; AX <- add minimal value LOW adc dx,bx ; DX <- add minimal value HIGH ret ; ----------------------------------------------------------------------------- ; Uninitialised data ; ----------------------------------------------------------------------------- DATA_SECTION ; ------------- Seed for random generator align 4, resb 1 RandSeed: resb 8 ; seed for random generator RandEventEnable:resb 1 ; flag 0: pseudo, not 0: enable events