normalDist.asm

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

%define DEBUG  1

extern rand
extern time
extern srand
extern printf

;
; struct ResultT {
;     int value
;     int count
;     long percent

VALUE_OFFSET EQU 0
COUNT_OFFSET EQU 4
PCT_OFFSET EQU 8
RESULT_SIZE EQU  16

ROLLS EQU 3
SIDES EQU 6

section .data
     RollResult: db `%d `,0
     RollSum: db ` = %d \n`,0
     TimesLine: db `%2d occured %8d times or %8.4f%\n`,0

     trials: dq 1000000

     hundred: dq 100.00


section .bss
     ary: resq (ROLLS + ROLLS*SIDES ) * 2

section .text

global main

SYS_TIME equ 100

main:

    ; initialize the random number generator 
    ;  srand(time(nullptr))
    mov rdi, 0
    call time
    mov rdi, rax
    call srand
   
    ; for(int i =0; i <= ROLLS * SIDES; ++i) {
    ;    int sum = 0
    ;    for(int j =0; j < ROLLS; ++j)
    ;       sum += rand() % SIDES + 1
    ;    }
    ;    ++ ary[sun].count;

    ; r12 is the outer lcv
    mov r12, 0

.topGenLoop:
    cmp r12, [trials]
    je .doneGenLoop

    ; r13 is the sum of three throws
    mov r13, 0
    ; r14 is the inner lcv
    mov r14, 0

.topOneRoll:
    cmp r14, ROLLS
    je  .doneWithRoll

    ; tmp = rand;
    mov rax, 0
    call rand

    ; tmp = (tmp % sides) + 1
    mov r8, SIDES
    mov rdx, 0
    div r8
    mov rax, rdx
    inc rax

    ; sum += tmp
    add  r13, rax

%ifdef DEBUG
    ; cout << tmp << " " 
    mov rdi, RollResult
    mov rsi, rax
    call CallPrintf
%endif

    inc r14
    jmp .topOneRoll

.doneWithRoll:
 
%ifdef DEBUG
    ;cout << " = " << sum
    mov rdi, RollSum
    mov rsi, r13
    call CallPrintf
%endif

    ; you an only multiply a register by 2, 4, 8 in an address computation
    ;   so compute the array offset in rax
    mov rax, RESULT_SIZE
    mul r13

    ; ++ary[sum].count
    inc qword [ary + rax + COUNT_OFFSET ]

    inc r12
    jmp .topGenLoop


.doneGenLoop:

    ; I did not want to do strange indexing, so I will ignore
    ;   the first rolls locations in the array
    ;   IE for 1 die, we can never have a 0
    ;      for 2 die, we can never have a 0 or a 1
    ; i = rolls
    ;
    ;  for(i = rolls ; i <= ROLLS * SIDES; ++i) {
    ;    float denom = static_cast<double> trials
    ;    float result = static_cast<double> ary[i].count
    ;    result /= denom
    ;    result * = 100
    ;    ary[i].pct = result
    ;    ary[i].value = i
    ;}
    mov r12, ROLLS 

.topCalcLoop:
    cmp r12, ROLLS*SIDES + 1
    je  .doneCalcLoop

    ; compute the offset
    mov rax, RESULT_SIZE
    mul r12
    mov r8, rax

    ; xmm0 = ary[i].count/trials * 100
    cvtsi2sd xmm1, [trials]
    cvtsi2sd xmm0, qword[ary + r8 + COUNT_OFFSET] 
    divsd xmm0, xmm1

    mulsd xmm0, [hundred] 

    ;    ary[i].value = i
    ; probably not needed, but I intended to sort this.
    mov [ary + r8 + VALUE_OFFSET], r12d
    ;    ary[i].pct = result
    movsd qword [ary + r8 + PCT_OFFSET], xmm0

    inc r12,
    jmp .topCalcLoop

.doneCalcLoop:

    ; for(int i =rolls; i <= rolls*sides; ++i) {
    ;   cout << ary[i].value << " " << ary[i].count << " " << ary[i].pct 
    ;}
    mov r12, ROLLS
.topPrintLoop:
    cmp r12, ROLLS * SIDES + 1
    je .donePrintLoop

    ; compute the offset
    mov rax, RESULT_SIZE
    mul r12
    mov r8, rax

    mov rdi, TimesLine
    mov rsi, [ary + r8 + VALUE_OFFSET]
    mov edx, dword [ary + r8 + COUNT_OFFSET]
    movsd xmm0, [ary + r8 + PCT_OFFSET]

    mov rax, 1
    
    mov r15, rsp
    and rsp, -16
    call printf
    mov rsp, r15

    inc r12
    jmp .topPrintLoop

.donePrintLoop:

.done:
   
    jmp Exit