classRNG.asm

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

A EQU 1103515245
M EQU 70000000h
C EQU 12345
section .data
    RNG_SEED: dq 1  ; the x in the LCG random  number generator
    RAND_TEST_FMT: db `%d   %d\n`,0
    RANGE_FMT: db  `Range %d to %d -> %d\n`,0

    ArrayValueFmt: db `A[%d]= %d\n`,0

section .bss

section .text

global main
main:

    mov rdi, 20
    mov rsi, 1000
    call TEST_ROLL

    ;mov rdi, format1
    ;mov rsi, -1
    ;call CallPrintf 
  
    ;mov rdi, 5
    ;call TEST_RAND

    ;mov r12, 0
;.top:
    ;cmp r12, 20
    ;je  .done
;
;    mov rdi, 3
;    mov rsi, 22
;    call RAND_IN_RANGE
;
;    mov rdi, RANGE_FMT
;    mov rsi, 3
;    mov rdx, 22
;    mov rcx, rax
;    call CallPrintf

;    inc r12
;    jmp .top
;.done:
    
    jmp Exit

; rdi will hold the size of the die 0 to rdi -1
; rsi will hold the number of trials to execute

;  TestRoll(int maxSides, int trials)
;      int counts[maxSides]
;
;      for(i =0; i << maxSides; ++i) {
;          counts[i] = 0
;      }
;
;      for(i =0; i << trials; ++i) {
;          counts[randInRange(0, max) ] ++
;      }
;
;      for(i =0; i << maxSides; ++i) {
;          cout << i << " "  << counts[i] << endl 
;      }
TEST_ROLL:

    push rbp
    mov rbp, rsp

    ; declare the array
    ;   I added this line in debugging.  Probably not needed.
    mov rdx, 0
    mov rax,rdi
    mov r8, 8
    mul r8
    sub rsp, rax

    ; temporarly store the base address of the array in rax
    mov rax, rsp
    
    push r12
    push r13
    push r14
    push r15

    ; r12 will hold maxvalue or max sides
    mov r12, rdi
    ; r13 will hold  the LCV
    ; r14 will hold the base address of the array
    ;    mov r14, rsp
    ;    add r14, 32
    mov r14 , rax
    ; r15 will hold the number of trials
    mov r15, rsi

    ;for i =0; i < max; ++i)  array[i] = 0

    mov r13, 0
InitLoopTop:
    ;   We had an arry out of bounds because we had the wrong variable here
    ;   r15 holds the number of trials
    ;   r12 holds the number of sides
    ;cmp r13, r15
    cmp r13, r12
    je .InitLoopDone

    mov qword [r14 +r13*8], 0
    inc r13
    jmp InitLoopTop

.InitLoopDone:

    ; call the RNG a bunch of times.

    ;for i =0; i < max; ++i)  cout << i << array[i] 
    mov r13, 0
PrintLoopTop:
    ;   We had an arry out of bounds because we had the wrong variable here
    cmp r13, r12
    je .PrintLoopDone

    mov rdi, ArrayValueFmt
    mov rsi, r13
    mov rdx, [r14 +r13*8]
    call CallPrintf

    inc r13
    jmp PrintLoopTop

.PrintLoopDone:

TestRollDone:
    pop r15
    pop r14
    pop r13
    pop r12

    mov rsp, rbp
    pop rbp
    ret


TEST_RAND_IN_RANGE:
   ;   void TestRandInRange(long low, long high, long iterations) {
   ;      if low >= high 
   ;        return 
   ;      else
   ;        range = high-low
   ;        long counts[range]
   ;
   ;        for(int i =0; i < range; ++i) {
   ;           counts[i] = 0
   ;        }
   ;
   ;        for(int i =0; i < iterations; ++i) {
   ;             counts[RandInRange(low,high)-low]++
   ;        }
   ; 
   ;        for(int i =0; i < range; ++i) {
   ;           cout << i+low << " " << counts[i];
   ;        }
   ;}
   ;
   ;    register dictionary
   ;       r12 will hold the base address of counts

   push rbp
   mov rbp, rsp
   ; r12 will be the base address of the array
   ; r13 will be the lcv
   push r12
   push r13


   ; restore preserveds
   pop r13
   pop r12

   ; restore the stack
   pop rbp
   ret

; this routine will compute a random value in a given range.
; long RAND_IN_RANGE(long low, long high) {
;     range = high - low
;     long value = low + rand() % range
;     return value
;}
;

RAND_IN_RANGE:
     push rbp
     mov rbp, rsp
    
     ; r12 will be used for low
     push r12

RANGE_OFFSET: equ -16
     ; local variable for range
     ; range will be at rbp-16
     add rsp, -8

     mov r12, rdi
     ; value = low + rand() % range

     ; range = high -low
     mov rax, rsi
     sub rax, rdi
     mov [rbp + RANGE_OFFSET], rax

     call RAND

     ; find %range
     mov rdx, 0
     div qword [rbp - 16]
     mov rax, rdx

     ; add low
     add rax, rdi 

; EXIT STUFF
     add rsp, 8
     pop r12
     pop rbp
     ret


; this routine will test the rand function.
; It has one parameter, n which is positive
;
; void TEST_RAND(long n) {
;   for(long i =0; i < n; ++i) {
;      cout << i << " " << n  << endl;
;   }
; }

; Register Use
;    RAX will be used for function call return value (RAND)
;        and also for the cout statement (return value)
;    rdi will be used for printf
;        will also contain n on call
;    r12 will be used to hold n
;    rsi will be used for printf
;    rdx will be used for printf

TEST_RAND:

    push rbp
    mov rbp, rsp

    ; r12 will be used to hold n
    push r12  

    mov r12, rdi

    ; r8 will be the LCV
    ; for i = 0; i < n ; ++i
    mov r8, 0

top:
    cmp r8, r12
    je .done

    push r8
    call RAND
    pop r8
    ; cout << i << "  " << rand()
    mov rdi, RAND_TEST_FMT
    mov rdx, rax
    mov rsi, r8

    push r8
    ; save r8 across the function call
    call CallPrintf
    ; restore r8
    pop r8

    inc r8
    jmp top
.done:

    ; restore preserveds that I used
    pop r12

    pop rbp
    ret
   
RAND:
  ; Xn+1 = (A * Xn + C) % M
  ; return Xn+1 in rax
  ; no parameters

  push rbp
  mov  rbp, rsp

  mov r8, 10909910189

  ; compute AX
  mov rax, [RNG_SEED]
  mov rcx, A
  mov rdx, 0
  mul rcx

  ; compute AX + C
  add rax, C

  ; compute (AX + C ) % M
  mov rcx, M
  div rcx

  ; set up for return
  mov rax, rdx
  ; and save X for next computation
  mov [RNG_SEED], rax

  pop rbp
  ret