;	  RANDOM.COM		       Designed and written by Wilson Seto
;	  Version 1.10		       Inspired by Nathan Hull and Ettiene Martin
;				       Idea borrowed from TURBO C & PASCAL
;
;	  Terminate and stay resident random number generator.
;
;	  HOW TO ASSEMBLE:	       tasm random.asm
;				       tlink random.obj /t
;
;	  HOW THIS WORKS: First check to see if already installed, if not then
;	  do so, else abort.  Print the appropriate message.  To get a random
;   number do an INT 62H with AX equal to the desired range value.
;	  The random number is created by shifting, adding, multiplying, and
;	  dividing the seed values.  The number returned in AX is between
;	  0 and the range value, all other registers are unchanged.
	  page	 60,130
cseg	  segment
	  assume cs:cseg, ds:cseg
	  assume es:cseg, ss:cseg
	  org	 100h
start:	  jmp	 short check
;---------TSR routine-----------------------------------------------------------
constant  dw	 8405h		       ;multiplier value
seed1	  dw	 ?
seed2	  dw	 ?		       ;random number seeds
int_62h   proc   far
	  or	 ax,ax		       ;range value <> 0?
	  jz	 abort		       ;if not then abort
	  push	 bx
	  push	 cx
	  push	 dx
	  push	 ds
	  push	 ax		       ;save the range value
	  push	 cs
	  pop	 ds		       ;ds = cs
	  mov	 ax,seed1
	  mov	 bx,seed2	       ;load seeds
	  mov	 cx,ax		       ;save seed
	  mul	 constant	       ;(dx,ax) = ax * constant
	  shl	 cx,1
	  shl	 cx,1
	  shl	 cx,1
	  add	 ch,cl
	  add	 dx,cx
	  add	 dx,bx
	  shl	 bx,1		       ;begin scramble algorithm
	  shl	 bx,1
	  add	 dx,bx
	  add	 dh,bl
	  mov	 cl,5
	  shl	 bx,cl
	  add	 ax,1
	  adc	 dx,0
	  mov	 seed1,ax
	  mov	 seed2,dx	       ;save results as the new seeds
	  pop	 bx		       ;get back range value
	  xor	 ax,ax		       ;clear register
	  xchg	 ax,dx		       ;adjust ordering
	  div	 bx		       ;ax = trunc((dx,ax) / bx), dx = (r)
	  xchg	 ax,dx		       ;return remainder as the random number
	  pop	 ds
	  pop	 dx
	  pop	 cx
	  pop	 bx
abort:	  iret			       ;return to caller
int_62h   endp
;-------------------------------------------------------------------------------

;---------Initialization routine------------------------------------------------
check:	  mov	 ax,3000h	       ;get DOS version
	  int	 21h
	  cmp	 al,3		       ;DOS version 3.0 or higher?
	  jae	 chk_vec
	  mov	 dx,offset wrong_dos   ;incorrect DOS version, inform user
quit:	  mov	 ah,9
	  int	 21h
	  int	 20h		       ;back to DOS
chk_vec:  mov  ax,3562h        ;get interrupt vector for int 62h - es:bx
	  int	 21h
    mov  di,bx           ;es:di points to int 62h
    mov  si,offset int_62h     ;point to our copy of int 62h
	  mov	 cx,16		       ;# of bytes to compare
	  cld			       ;forward string movement
	  repe	 cmpsb		       ;compare memory regions
	  jnz	 install	       ;if not identical then not installed
	  mov	 dx,offset loaded      ;already loaded, inform user
	  jmp	 short quit
install:  mov	 ah,2ch 	       ;get current time
	  int	 21h
	  mov	 seed1,cx
	  mov	 seed2,dx	       ;save as initial seeds
	  mov	 dx,offset ready
	  mov	 ah,9		       ;print ready message
	  int	 21h
    mov  dx,offset int_62h     ;point to routine to install - ds:dx
    mov  ax,2562h        ;change interrupt 62h vectors
	  int	 21h
	  mov	 dx,offset check       ;end of resident code
	  int	 27h		       ;TSR
;-------------------------------------------------------------------------------

;---------Data area-------------------------------------------------------------
wrong_dos db     13,10,10,'Requires DOS V3.0 or higher!',13,10,10,7,7,36
loaded    db     13,10,10,'Random number generator is already loaded.'
	  db	 13,10,10,7,7,36
ready     db     13,10,10,'Random number generator V1.1 loaded.',13,10,10,36
;-------------------------------------------------------------------------------
cseg	  ends
	  end	 start