; random.asm
;
; a fast subtractive method
;
; Here is a 386 real-mode version by Joe Koss
;
; assumes DS -> .data
;
; randomize(EAX)     init the generator
; random()           EAX = 0 to (2**32)-1    ...32bit bits a random
; rnd(EAX)           EAX = 0 to EAX-1        ...pick your range
;
 
.model small
.data
 
  tablex dd 55 dup (?)  ; table of seeds
 
  index0 dw ?           ; indexes into table of seeds
  index1 dw ?
 
.code
.386
 
  public randomize, random, rnd
 
  randomize proc
 
    ; in: eax = seed
 
    push bx si edx
    mov edx, 1
 
    ; fill table with values
 
    mov bx, 216
    DO_0:
     mov tablex[bx], edx
     sub eax, edx
     xchg eax, edx
     sub bx, 4
    jge DO_0
 
    ; "warm up" the generator ..
 
    mov bx, 216
    DO_1:
     push bx
     DO_2:
      mov si, bx
      add si, 120
      cmp si, 216
      jbe skip
       sub si, 216
      skip:
      mov eax, tablex[bx]
      sub eax, tablex[si]
      mov tablex[bx], eax
      sub bx, 4
     jge DO_2
     pop bx
     sub bx, 4
    jge DO_1
 
    ; init the index's
 
    sub ax, ax
    mov index0, ax
    mov ax, 124
    mov index1, ax
 
    ; finished
 
    pop edx si bx
    ret
 
  endp
 
  random proc           ; did you remember to randomize?
 
    ;out: EAX = 0..(2**32)-1
 
    push bx si
 
    ; setup indexes
 
    mov bx, index0
    mov si, index1
 
    ; generate new random
 
    mov eax, tablex[bx]
    sub eax, tablex[si]
 
    ; save random
 
    mov tablex[bx], eax
 
    ; decrement indexes, wrapping
    ;
    ; the branches are normally avoided for speed
 
    sub si, 4
    jl fixSI
  fixedSI:
    mov index1, si
 
    sub bx, 4
    jl fixBX
  fixedBX:
    mov index0, bx
 
    pop si bx
    ret
 
  fixSI:
    mov si, 216
    jmp fixedSI
 
  fixBX:
    mov bx, 216
    jmp fixedBX
 
  endp
 
  rnd proc                      ; would make a good macro
    ; in: eax = range
    ;out: eax = random between 0..range-1
    push edx
     mov edx, eax
     call random
     mul edx
     xchg eax, edx
    pop edx
    ret
  endp
 
end

