; 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

