📄 rand.asm
字号:
;;============================================================================
;;History: mm/dd/yy | Who | Description Of Changes.
;; ---------+---------+------------------------------------------
;; 09/30/93 | Eric W. | Original draft.
;; 01/03/96 | Alex T. | Optimized code.
;; 09/01/97 | Jeff A. | Vectorized code.
;;============================================================================
;;============================================================================
;;
;; Module Names: InitRand16, Rand16
;;
;;----------------------------------------------------------------------------
;;
;; Usage ASM: To initialize:
;;
;; call InitRand16
;;
;; To get the next random number:
;;
;; call Rand16
;;
;;----------------------------------------------------------------------------
;;
;; Input: rndnum
;;
;; Modifies: SPM
;; OVM
;; DP
;; P
;; T
;;
;; Output: ACCL = rndnum = 16-bit Random Number
;; ACCH = 0
;;
;;----------------------------------------------------------------------------
;;
;; Algorithm: rndnum(n) = ((rndnum(n-1) * RNDMULT) + RNDINC) MOD M
;;
;; where: M = modulus (set at 65536, i.e. 64K)
;; n = 2 to ??? (number of random #s generated)
;; rndnum(1) = RNDSEED (arbitrary constant)
;; RNDMULT = multiplier (unique constant)
;; RNDINC = increment value (unique constant)
;;
;; Description: This algorithm is called the "Linear Congruential Method"
;; introduced by D. Lehmer in 1951. Many random number
;; generators exist, but this method is arguably the fastest
;; for a 16-bit value. If a 32-bit value is needed, the code
;; can be modified by performing a 32-bit multiply and using
;; 32-bit constants (RNDMULT, RNDINC). This method, however,
;; does have one major disadvantage: it is VERY sensitive to
;; the values of RNDMULT and RNDINC.
;;
;; Much research has been done to identify the optimal choices
;; of these constants to avoid degeneration. The constants used
;; in the subroutine below were chosen based on this research.
;; Extreme care must be taken if changes to the original
;; constants are made:
;;
;; M: The modulus value. This routine returns a random number
;; - from 0 to 65536 (64K) and is NOT internally bounded. If
;; the user needs a min/max limit, this must be coded
;; externally to this routine.
;;
;; RNDSEED: An arbitrary constant. Can be chosen to be any
;; ------- value representable by the uP (0-64K). If 0 (zero)
;; is chosen, RNDINC should be some larger value than
;; 1. Otherwise, the first two values will be 0 and 1.
;; This is ok if the generator is given three cycles
;; to "warm up". To change the set of random numbers
;; generated by this routine, simply change the
;; RNDSEED value. RNDSEED=21845 is used in this
;; routine because it is 65536/3.
;;
;; RNDMULT: Should be chosen such that the last three digits
;; ------- are even-2-1 (such as xx821, x421, etc).
;; RNDMULT=31821 is used in this routine.
;;
;; RNDINC: In general, this constant can be any prime number
;; ------ related to M (or 64K in this case). Two values
;; were actually tested: 1 and 13849. Research
;; shows that RNDINC (the increment value) should be
;; chosen by the following formula:
;;
;; RNDINC = ((1/2 - (1/6 * SQRT(3))) * M)
;;
;; Using M=65536: RNDINC=13849 (as indicated above).
;; RNDINC=1 was also tested and works fine.
;; RNDINC=13849 is used in this routine.
;;
;; 8-bit #: If an 8-bit number is desired (0-255), the lower or
;; ------- higher byte of the low accumulator can be used.
;; However, the "randomness" or "uniqueness" of each
;; number is NOT guaranteed. When choosing only 8
;; bits out of 16, duplications might exist.
;; Therefore, it is NOT recommended to a portion of
;; the 16-bit result to implement scaling. Scaling
;; should be done mathematically external to this
;; routine.
;;
;; CAUTION: This routine can only be used for 16-bit values.
;; ------- Do not use for 32-bit values (upper half of ACC
;; is not necessarily random because only the lower
;; half is saved from the previous result). Do NOT
;; save the result with a shift (e.g. SACL RndNum,1) -
;; the algorithm immediately degenerates.
;;
;;============================================================================
;;
;; MEMORY REFERENCES:
;;
;;
;; DEFINE CONSTANTS:
;;
RNDMULT .set 31821 ; Multiplier value
RNDINC .set 13849 ; Increment value
;;
;; Generate Next Random Number:
;;
.include "ccall.asm"
.ref rndnum
.def _ti_rand
_ti_rand:
pre_ccall 2,AR_Z,AR_N
; Modify any registers needed
; Note: Overflow mode is off in C.
; End C Preprocessing
ldp #rndnum ; set data page to point to RndNum
lt rndnum ; TREG = previous rndnum
; Local variables
; N%8 - stack[0]
; N/8 - stack[1]
; Compute N%7 to make N divisible by 8 in the unrolled loop
sar AR_N,* ; stack[0]=N
lacl *+ ; acc=N
and #07h ; acc&=0111b - Unroll 8 iterations
sacl *- ; stack[1] = N % 0111b
lacc *,13 ; acch=N>>3
sach *+ ; stack[0]=N>>3
lar AR_N,*+,AR_N ; AR_N = stack[1] = N%7
banz NEXT0,AR_Z ; Skip loop if AR_N = 0
b NEXT1
NEXT0:
splk #RNDMULT,rndnum ; Store temporarely in rndnum
mpy rndnum ; PREG = rndnum * RNDMULT
pac ; ACC = rndnum * RNDMULT
add #RNDINC ; ACC = (rndnum * RNDMULT) + RNDINC
sacl * ; Store result
lt *+,AR_N ; TREG = previous rndnum
banz NEXT0,AR_Z
NEXT1:
mar *,AR_STACK
sbrk #2 ; SP=stack[0]
lar AR_N,*+ ; AR_N = stack[0]=N>>3
mar *-,AR_N ; SP=stack[1]
banz NEXT2,AR_Z ; Go to 8x loop if AR_X > 0
b DONE
NEXT2:
; z[AR_Z++]=x[AR_X++]*y[AR_K++]
.loop 7
splk #RNDMULT,rndnum ; Store temporarely in rndnum
mpy rndnum ; PREG = rndnum * RNDMULT
pac ; ACC = rndnum * RNDMULT
add #RNDINC ; ACC = (rndnum * RNDMULT) + RNDINC
sacl * ; Store result
lt *+ ; TREG = previous rndnum
.endloop
splk #RNDMULT,rndnum ; Store temporarely in rndnum
mpy rndnum ; PREG = rndnum * RNDMULT
pac ; ACC = rndnum * RNDMULT
add #RNDINC ; ACC = (rndnum * RNDMULT) + RNDINC
sacl * ; Store result
lt *+,AR_N ; TREG = previous rndnum
; while(AR_N--)
banz NEXT2,AR_Z
mar *-
lacl *,AR_STACK ; Save last random number
sacl rndnum ; rndnum = ACC
; SP=stack[1]
; Begin C Post Processing
DONE:
post_ccall 2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -