This popped up on my Youtube feed today. I wonder what the results would be for other CPU's.
Tested out NinjaTech AI (https://www.ninjatech.ai/product/ai-code-generator)
Z80 Random number generator range 0-255
; Z80 Random Number Generator (0-255 range)
; Uses 16-bit Linear Congruential Generator with 8-bit output
ORG 8000h
; 16-bit seed storage
RND_SEED: DEFW 1234h ; Initial seed value
;==============================================================================
; Initialize random number generator
; Input: HL = 16-bit seed value
; Destroys: None
;==============================================================================
RND_INIT:
LD (RND_SEED), HL
RET
;==============================================================================
; Generate random number 0-255
; Output: A = random number (0-255)
; Destroys: HL, DE
;==============================================================================
RANDOM:
LD HL, (RND_SEED) ; Load current seed
; LCG formula: next = (a * seed + c) mod 65536
; Using a = 75 (good multiplier for 16-bit)
LD D, H ; Copy seed to DE
LD E, L
; Multiply by 75 using shifts and adds (75 = 64 + 8 + 2 + 1)
ADD HL, HL ; HL = seed * 2
LD BC, HL ; Save seed * 2
ADD HL, HL ; HL = seed * 4
ADD HL, HL ; HL = seed * 8
ADD HL, BC ; HL = seed * 10
ADD HL, HL ; HL = seed * 20
ADD HL, HL ; HL = seed * 40
ADD HL, DE ; HL = seed * 41
ADD HL, HL ; HL = seed * 82
SUB HL, DE ; HL = seed * 81
SUB HL, DE ; HL = seed * 80
SUB HL, DE ; HL = seed * 79
SUB HL, DE ; HL = seed * 78
SUB HL, DE ; HL = seed * 77
SUB HL, DE ; HL = seed * 76
SUB HL, DE ; HL = seed * 75
; Add constant c = 74
LD DE, 74
ADD HL, DE
; Store new seed
LD (RND_SEED), HL
; Return high byte for better distribution
LD A, H
RET
;==============================================================================
; Alternative simpler version using XOR shift
; Output: A = random number (0-255)
; Destroys: HL
;==============================================================================
RANDOM_XOR:
LD HL, (RND_SEED)
; XOR shift algorithm
LD A, L
XOR H
LD L, A
LD A, H
RRA
RRA
RRA
XOR L
LD H, A
LD A, L
RLA
XOR H
LD L, A
; Store new seed
LD (RND_SEED), HL
; Return low byte
LD A, L
RET
;==============================================================================
; Fast 8-bit LCG (most efficient)
; Output: A = random number (0-255)
; Destroys: None
;==============================================================================
RND_SEED8: DEFB 1 ; 8-bit seed
RANDOM8:
LD A, (RND_SEED8) ; Load 8-bit seed
; Multiply by 5 (shift left twice + original)
LD B, A ; Save original
ADD A, A ; A = seed * 2
ADD A, A ; A = seed * 4
ADD A, B ; A = seed * 5
; Add constant 1
INC A
; Store new seed
LD (RND_SEED8), A
RET
;==============================================================================
; Get random number in specific range 0 to N-1
; Input: B = upper limit (N, where result will be 0 to N-1)
; Output: A = random number (0 to N-1)
; Destroys: HL, DE, C
;==============================================================================
RANDOM_RANGE:
CALL RANDOM ; Get random 0-255
; Simple modulo using repeated subtraction
LD C, 0 ; Counter
RANGE_LOOP:
CP B ; Compare with limit
JR C, RANGE_DONE ; If A < B, we're done
SUB B ; A = A - B
INC C ; Increment counter
JR RANGE_LOOP
RANGE_DONE:
RET ; A now contains result
;==============================================================================
; More efficient range function using multiplication method
; Input: B = upper limit (1-255)
; Output: A = random number (0 to B-1)
; Destroys: HL, DE
;==============================================================================
RANDOM_RANGE_FAST:
CALL RANDOM ; Get random 0-255 in A
; Multiply A * B, then take high byte
LD H, 0
LD L, A ; HL = random value
LD D, 0
LD E, B ; DE = range
; 16-bit multiplication HL = HL * DE
CALL MULTIPLY16
; Take high byte as result (gives good distribution)
LD A, H
RET
;==============================================================================
; 16-bit multiplication helper: HL = HL * DE
; Destroys: BC
;==============================================================================
MULTIPLY16:
LD BC, 0 ; Initialize result
LD A, 16 ; 16 iterations
MULT_LOOP:
ADD HL, HL ; Shift HL left
JR NC, MULT_SKIP ; Skip if no carry
ADD BC, DE ; Add DE to result
MULT_SKIP:
DEC A
JR NZ, MULT_LOOP
LD H, B ; Move result to HL
LD L, C
RET
;==============================================================================
; Demo/Test program
;==============================================================================
DEMO:
; Initialize with seed
LD HL, 12345
CALL RND_INIT
; Generate some random numbers
CALL RANDOM ; A = random 0-255
CALL RANDOM ; A = another random 0-255
; Generate random number 0-9 (for dice, etc.)
LD B, 10
CALL RANDOM_RANGE ; A = random 0-9
; Generate random number 0-99
LD B, 100
CALL RANDOM_RANGE_FAST ; A = random 0-99
RET
;==============================================================================
; Utility: Get a "random" seed from user timing
; Call this after user presses a key, uses timing for entropy
; Output: HL = pseudo-random seed
;==============================================================================
GET_TIMING_SEED:
LD HL, 0
TIMING_LOOP:
INC HL
; Check for keypress (system-specific)
; This is a placeholder - replace with your system's key check
IN A, (0) ; Replace with actual port
AND 1 ; Check key bit
JR Z, TIMING_LOOP ; Keep counting until key pressed
RET ; HL contains timing-based seed
END
; Initialize
LD HL, 54321
CALL RND_INIT
; Get random byte (0-255)
CALL RANDOM ; Result in A
; Get random number 0-9
LD B, 10
CALL RANDOM_RANGE ; Result in A
; Get random number 0-99
LD B, 100
CALL RANDOM_RANGE_FAST ; Result in A
I'll test this out later.