Program in Assembly Language, Code Generating Random Numbers

In this assignment, students have to make use of a starter code and string library in order to generate a new program. The program is required to produce and display a series of ten random numbers. In this project random numbers are to be generated in a range of 0 to 9.

SOLUTION : –

/*    Frank Emanuel

*    String Library

*

*    This library of String (byte array) functions allows the user

*    to easily work with strings in assembler. Each function is

*    described in its own comment block.

*

*/

@     Declarations of functions in library

.equ        STDOUT, 1   @ set a constant for the standard output

.equ        STDIN,      0     @ set a constant for the standard input

.global           _strLen           @ returns the length of an array in bytes

.global           _strCat           @ concatonates two bchar arrays

.global           _strUpper   @ replaces all lowercase letters with uncials

.global           _sPrint           @ prints a string onto the STDOUT

.global           _sInput           @ takes in a string from the STDIN flushing buffer

/* String Length Function

*

*    This function takes the address of a null terminated array of bytes

*    in register 1 and returns the number of characters in the array in

*    register 2.

*

*/

_strLen:

MOV         r2, #0                  @ start the element counter at 0

findEnd:

LDRB  r0, [r1], #1      @ r1 contains the address of the byte to

@ load into r0, increment the address in r1

ADD         r2, r2, #1        @ increment the byte counter

CMP         r0, #0                  @ set the status register by comparing the

@ value in r0 with null (#0)

BNE         findEnd                 @ if r0 is not null continue looping

SUB         r2, r2, #1        @ fix that we counted the null character

MOV         pc, lr                  @ restore control to calling code

/* String to Upper Case Function

*

* Takes the addresses of a null terminated string and converts any

* lower case letters to their uncial (upper case) equivalent.

*

*/

_strUpper:

LDRB  r0, [r1]                @ load the next byte of array 1

CMP         r0, #97                       @ compare byte to ‘a’

BLT         writeChar               @ preserve non-lowercase letter

CMP         r0, #122                @ compare to ‘z’

SUBLE r0, r0, #32             @ change to uppercase

writeChar:

STRB  r0, [r1], #1            @ if not end of array 1 store value

CMP         r0, #0                        @ look for end of string

BNE         _strUpper               @ loop until end of string

MOV   pc, lr                        @ return to calling environment

/* String Printer

*

* Takes the address of a null terminated string array and outputs

* that string to STDOUT (console). String address in register 1

*

*/

_sPrint:

MOV   r0, #STDOUT             @ set the output to the console

PUSH  {r0-r1, lr}             @ save the working registers and LR

BL          _strLen                       @ set register 2 to string length

POP         {r0-r1, lr}             @ restore working registers and LR

MOV         r7, #4                        @ set the syscall to WRITE

SWI         0                             @ make the syscall

MOV         pc, lr                        @ return to calling environment

/* String Inputer

*

* Takes the address for a string in register 1 and the number of

* characters to read in register 2. Makes the syscall to READ from

* STDIN and then flushes any remaining characters from the buffer.

*

*/

_sInput:

PUSH  {r1-r2, lr}             @ preserve values for function

MOV   r0, #STDIN              @ set the input to the console

MOV         r7, #3                        @ set the syscall to READ

SWI   0                             @ make the syscall

POP         {r1-r2, lr}             @ restore values sent to function

sInputStrStart:

CMP         r2, #0                        @ memory bounds checker

MOVLE r0, #0                        @ if no more characters put null in R1

STRLEB      r0, [r1]                @ if no more characters store null in array

BLE         sInputEnd               @ if no more characters exit

LDRB  r0, [r1]                @ load in the next byte of sent array

CMP         r0, #10                       @ check for newline character

MOVEQ r0, #0                        @ if end put null charater in R1

STRB  r0, [r1], #1            @ write byte out at end of array 1

SUB         r2, r2, #1              @ decrement letter counter

BNE         sInputStrStart          @ loop until newline

sInputEnd:

MOV         pc, lr                        @ return to calling environment

/*    Frank Emanuel

*    Random Number Generator

*

*    In order to generate a random number we need a seed value.

*    Traditionally this seed value comes from the clock. This creates

*    a pseudo-random number which is usually good enough for our

*    programming examples.

*

*/

.equ  RNDBOUNDS, 10           @ we want to generate numbers from 0 to 9

.global     _start

_start:

LDR         r1, =message      @ place the address string in r1

BL          _sPrint           @ use library function to display string

MOV         r5, #10                 @ I want to loop 10 times.

mainloop:

CMP         r5, #0                  @ condition check for while loop

BEQ         _end              @ loop until r5 is 0

SUB         r5, r5, #1        @ decrement loop condition

/*    Step 1 fetch the time from the processor

*

*    Syscall #78 will take an address of memory large enough to hold

*    the

*/

MOV   r7, #78         @ gettimeofday syscall (#78) returns time_t

LDR         r0,   =time       @ address of holder for time_t

MOV   r1, #0          @ put a null in tz field (time zone not needed)

SWI         #0

/*    Step 2 convert to a number within the range

*

*    The number of milliseconds will easily fill a long integer. The

*    formula for converting from a number to a range is to use the

*    modulus when dividing our number by the target range.

*

*    Seed Value MOD 10 = number between 0 and 10 (the remainder).

*

*  In ARM you do not usually have a division operator and even when you

*    do it simply discards the modulus (or remainder).

*

*/

@     YOUR CODE GOES HERE

LDR         r1,   =time             @ address of holder for time_t

LDR  r1,[r1, #4]             @ load second byte from time_t

@ calculate division by repeated subtraction

divloop:

CMP         r1, #10                       @ if the number is less than 10

BLT         endloop                       @ we have completed the division, end loop

SUB         r1, r1, #10             @ if not, subtract 10 from it

BAL         divloop                       @ repeat the loop

endloop:

/*    Step 3      Convert the number (decimal value) into an ASCII number

*

*    If we try to print out the number with a WRITE call, we will get

*    strange results. WRITE prints out an array of ASCII characters. So

*    we must convert the number to print it out.

*

*/

@     YOUR CODE GOES HERE

ADD   r0, r1, #48             @ convert remainder to ascii

LDR         r1, =number             @ set r1 to address of comma

STRB r0, [r1]                @ save digit in number

BL          _sPrint                       @ print digit

/*    Step 4      Print out a comma if needed, note that this portion needs r5

*    so if you modify r5 elsewhere in the code you will have problems here.

*

*/

CMP         r5, #0                        @ is comma needed? (r5 set at top of loop)

LDRNE r1, =comma              @ set r1 to address of comma

BLNE  _sPrint                       @ print comma if needed

B           mainloop

_end:

LDR         r1, =period             @ at end add period

BL          _sPrint                       @ print final period

MOV         r7, #1                        @ set EXIT syscall

SWI         0                             @ execute syscall

.data

message:    .asciz      “The following are randomly generated numbers.\n”

number:           .asciz      “#”               @ you will write the ASCII value here

comma:            .asciz      “, ”

period:           .asciz      “.\n”

time:       .space  8               @ enough space to accomodate time_t

.align