PseudoRandom,  RandomBYTE,  and  RandomULONG

Purpose: Generate a "random" number or a scaled (i.e., range-limited) value based upon it.
Assumes: Two random seed variables, ulRandomValue1 and ulRandomValue2, have been initialized and will be updated.
Both RandomBYTE and RandomULONG call PseudoRandom.
Passed: Nothing  (for PseudoRandom, the parent routine) OR
R24 BYTE bLimit (for RandomBYTE) 0 for unscaled, or the maximum value desired, 1 to 255 OR
R25:R24:R23:R22 ULONG   ulLimit (for RandomULONG) 0 for unscaled, or the maximum value desired, 1 to 0xFFFFFFFF
Returns:   R25:R24:R23:R22 LONG lValue (for PseudoRandom) OR
R24 BYTE bScaled (for RandomBYTE) OR
R25:R24:R23:R22 ULONG ulScaled (for RandomULONG)
Alters: R0, R18 through R27, which includes the Registers returned (note that R28 to R31 are preserved)
Example: 
   .ORG  0x1000
Demo_PseudoRandom:
   CALL    APseudoRandom        ; This simply generates a new ULONG value
LocalRegOutput:
   JMP     ADumpRegs_Begin      ; A single FAR call to display the Registers

   .ORG  0x1010
Demo_RandomBYTE:
   RCALL   ALocalParseValue     ; Get any limiting BYTE value passed
   MOV     R24, R22             ; Set R24 = the LSByte of any value parsed
   RCALL   ALocalRegOutput      ; Display values before the call
   CALL    ARandomBYTE
   RJMP    ALocalRegOutput      ; The return value is ONLY in R24
   
   .ORG  0x1020
Demo_RandomULONG:
   RCALL   ALocalParseValue     ; Get any limiting ULONG value passed
   RCALL   ALocalRegOutput
   CALL    ARandomULONG
   RJMP    ALocalRegOutput

LocalParseValue:
   LDI     R22, 0               ; Initialize R25:R24:R23:R22 to 0 in case the
   LDI     R23, 0               ;  parsing routine is skipped entirely
   MOVW    R24, R22
   ADIW    R26, 0               ; If R27:R26 passed is zero, no command line
   BREQ    ALocalRet            ;  parameter was passed, so parse nothing
   MOVW    R24, R26             ; Point to the command line tail and parse the
   CALL    AParseValue          ;  value that was entered
;  SBR_    R21, BIT_PV_VALID    ; No need; R25:R24:R23:R22 will be 0 if invalid
   RCALL   ALocalRegOutput      ; The first Register output if there are 3
LocalRet:
   RET
Test it:
m>@ 0x1000   ; Immediately after a reboot

 10   32   54   76   98  1110 1312 1514 1716 1918 2120 2322 2524 2726 2928 3130
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
00D4 0527 0905 0528-0004 0000 0000 4000-0021 4650 0000 2C23-D631 A860 0280 0800
m>@ 0x1000

 10   32   54   76   98  1110 1312 1514 1716 1918 2120 2322 2524 2726 2928 3130
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
0092 00ED 0908 0828-0004 0000 0000 4000-0021 4650 0000 7D30-3393 5CF0 0280 0800
m>@ 0x1000

 10   32   54   76   98  1110 1312 1514 1716 1918 2120 2322 2524 2726 2928 3130
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
0020 0718 0909 0928-0004 0000 0000 4000-0021 4650 0000 4B1F-F708 3F00 0280 0800
m>@ 0x1000

 10   32   54   76   98  1110 1312 1514 1716 1918 2120 2322 2524 2726 2928 3130
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
007A 049C 090B 0B28-0004 0000 0000 4000-0021 4650 0000 1512-C2F9 F3B0 0280 0800
m>@ 0x1000

 10   32   54   76   98  1110 1312 1514 1716 1918 2120 2322 2524 2726 2928 3130
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
00EC 0120 090D 0D28-0004 0000 0000 4000-0021 4650 0000 9542-EF6C 81A0 0280 0800
m>@ 0x1010 128       ; This is ParseBYTE with a limit

 10   32   54   76   98  1110 1312 1514 1716 1918 2120 2322 2524 2726 2928 3130
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
0000 04C7 0918 1828-0004 0000 0000 4000-0021 0000 090A 0080-0000 0000 0280 0804
0000 04C7 0918 1828-0004 0000 0000 4000-0021 0000 090A 0080-0080 0000 0280 0804
000C 04C7 0918 1828-0004 0000 0000 4000-0021 4650 0000 000C-8034 B080 0280 0804
m>@ 0x1010

 10   32   54   76   98  1110 1312 1514 1716 1918 2120 2322 2524 2726 2928 3130
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
0000 04A4 09A4 A428-0004 0000 0000 4000-0021 0000 0D10 0000-0000 0000 0280 0808
00B6 04A4 09A4 A428-0004 0000 0000 4000-0021 4650 0000 8ECE-D0CE 6600 0280 0808
m>                                                                              
Notes: The values generated are not truly random (therefore the name "PseudoRandom"), but are calculated, using both the prior ULONG seed values, which are updated back to SRAM for use the next time.
The Operating System initializes ulRandomValue1 to 0x56DFAB42 and ulRandomValue2 to 0x84C3790E from constant values located within the last 16 bytes of visible FLASH.
Those two seed values can be changed at any time being careful not to set them to zeros.
Dropin: 
(setup
code)
;   Setup for the PseudoRandom() call:
; Passed:  Nothing.
; Returns: R25:R24:R23:R22 ULONG ulValue
; Alters:  R0, R18 through R27 (including R22 through R25 above)
;
;   Setup for the RandomBYTE() call:
; Passed:  R24 BYTE bLimit maximum value: 1 through 255  or 0, not limited
; Returns: R24 BYTE bValue the scaled pseudo-random value
; Alters:  R0, R18 through R27 (including R24 above)
;
;   Setup for the RandomULONG() call:
; Passed:  R25:R24:R23:R22 ULONG  ulLimit maximum value; if 0, not limited
; Returns: R25:R24:R23:R22 ULONG  ulValue the scaled pseudo-random value
; Alters:  R0, R18 through R27 (including R22 through R25 above)
Also see:  The Mode 8 (Dimdown) sequencer example, which uses RandomBYTE with limits (using R14) to select new pixel colors.