rng.asm

URL: https://mirkwood.cs.edinboro.edu/~bennett/class/cmsc3100/spring2026/notes/functions/code/rng.asm
 
%include "CONSTANTS.h"

MAX_SIZE equ 10
MAX_VALUE equ 100

; for the RNG, glibc values
A EQU 1103515245	
M EQU 70000000h
C EQU 12345

section .data

; global seed for the rng
      RNG_SEED dq 1

      rngTestFmt: db `The new rng value is %d\n`,0
      rngTestFmt2: db `%d occured %d times\n`,0

      fmt1: db `\n\ntesting %d to %d %d times\n`,0
      fmt2: db `\n\nTesting distribution of a d20\n`,0

section .bss
     array: resq MAX_SIZE

section .text

global main
main:

     ; init the RNG
     mov RAX, 100   ; 100 is the time system call
     mov rdi, 0     ; the only argument is nullptr
     syscall

     ; the time  will be stored in rax.
     mov qword[RNG_SEED], rax

     mov rdi, fmt1
     mov rsi, 20
     mov rdx, 30
     mov rcx, 15 
     call CallPrintf

     mov rdi, 15
     mov rsi, 20
     mov rdx, 30

     call SIMPLE_RNG_TEST

     mov rdi, fmt2
     call CallPrintf

     call COMPLEX_RNG_TEST

     jmp Exit

SIMPLE_RNG_TEST:
; this will just print n  random values between low and high
; rdi the first parameter will hold n
; rsi the second parameter will hold low
; rdx the third parameter will hold high
;
;  I need to have
;    r12 the lcv  0 to n-1
;    r13 the range rdx - rsi
;    r14 the low value

;    prolog
      push rbp
      mov rbp, rsp

      ; save the perm registers
      push r12
      push r13
      push r14

      ; save rdi at the bottom of the stack
      ; consider this  a local variable
      push rdi

      ; r13 = max
      mov r13, rdx 
      ; r13 = max - min
      sub r13, rsi 

      ; r14 = min
      mov r14, rsi  ; base of rng

      ; i = 0;
      mov r12,0
SIMPLE_RNG_LOOP_TOP:
      ; while i <  min
      cmp r12, qword [rsp]
      je SIMPLE_RNG_LOOP_BOTTOM

      mov rdi, r13
      mov rsi, r14
      call RAND_IN_RANGE

      mov rdi, rngTestFmt
      mov rsi, rax
      call CallPrintf

      inc r12
      jmp SIMPLE_RNG_LOOP_TOP

SIMPLE_RNG_LOOP_BOTTOM:


;     epilogue 
 
      ; remember, we stuck rdi on the stack to store it.
      pop rdi

      ; restore the perm registers
      pop r14
      pop r13
      pop r12

      pop rbp
      ret

COMPLEX_RNG_TEST:
; this will test my rng.
; I will generate 1000 values between 0 and 19
; and hope that they each show up the same "number of times"
;
;   I will use r12 as my index, so I need to save that.
;   I will use r13 to hold the base address of my array

     ; prologue
     ; save the base pointer and fix the stack pointer
     push rbp
     mov rbp, rsp

     ; save the permanant registers I wish to use
     push r12
     push r13

     ; i need a local array, so increment the stack pointer by this amount
     sub rsp, (20+1) * 8

     mov r13, rsp

     mov r12, 0
TOP_OF_INIT_LOOP:
     cmp r12, 20
     jg  OUT_OF_INIT_LOOP

     mov qword [r12*8 + r13],0
     inc r12
     jmp TOP_OF_INIT_LOOP

OUT_OF_INIT_LOOP:

     mov r12, 0
TOP_OF_GENERATE_LOOP:
     cmp r12, 10000
     je PRINT_RESULTS

     mov rdi, 20
     mov rsi, 0 
     call RAND_IN_RANGE

     inc qword [r13 + 8 *rax]

     inc r12
     jmp TOP_OF_GENERATE_LOOP

     
PRINT_RESULTS:

     mov r12, 0
TOP_OF_PRINT_LOOP:
     cmp r12, 20
     je EXIT_FUNCTION

     mov rdi, rngTestFmt2
     mov rsi, r12
     mov rdx, [r13 + r12 * 8]
     call CallPrintf

     inc r12
     jmp TOP_OF_PRINT_LOOP

EXIT_FUNCTION:
     ; epilogue

     ; eliminate the local array, decrement put the stack pointer back 
     add rsp, (20+1) * 8

     ; restore the permenant registers
     pop r13     
     pop r12

     ; restore the base pointer
     pop rbp
     ret

RAND_IN_RANGE: 
; this function will generate a random number in a range.
; Input: rdi: parameter 1: the size of the range 
;        rsi: parameter 2: the min value
;
; Output: rax: the value
;
; So this should do rand() % size + minValue
;  
; This is not a leaf routine, so I will need to save rdi and rsi
;    Well not really, beacuse RAND (below) does not use these, but.

       ; preamble
       push rbp
       mov rbp, rsp

       push rsi
       push rdi

       call RAND

       ; rax will now hold the random number, 
       ; I need to mod this by rdi
       pop rdi
       mov rdx, 0
       div rdi
       
       ;rdx will now hold the remaind
       ; I need to add rsi to it
       pop rsi
       add rdx, rsi

       ; place the final answer in rax
       mov rax, rdx

       ; epilogue
       pop rbp
       ret

RAND:
; rng, see https://en.wikipedia.org/wiki/Linear_congruential_generator
; we could use the system call, but we need some functions
;    seed_new = (seed_old * a + c ) % m 
;
;    we will put use the global RNG_SEED for the see, 
;       this is the default behaviaor
;    we will need to use rax, rdx, for computations
;    we will return the value in rax
;
;    This is a leaf node, so we can be very sloppy here
;    in fact, there is no need to build an activation record
;   

        mov rax, [RNG_SEED]
        mov rbx, A
        mov rdx, 0
        mul rbx
        add rax, C
        mov rbx, M
        div rbx
        mov rax, rdx
        mov [RNG_SEED], rax

        ret