Largest and Smallest number ...in 32bit arm Assembly language - arrays

This is a homework problem I have been struggling with all week.
The Guidelines:
" Write a program that asks the user to enter positive nonzero integer values. The user enters a -999 to signal the end of the data series. After all the numbers have been entered, the program should output the largest and smallest numbers entered.
Largest Number: XXXX
Smallest Number: XXXX
If a negative value is entered other than -999 the program should stop with an error message.
I would love to use an array, but can't find a way to use an array to store integers that a user has entered.
I realize it may be a mess, but here is the code I've adapted for a previous program:
.global main
.func main
#Starts Program
main:
sub sp, sp, #24 #stack
ldr r0, =userPrompt #calls prompt
bl printf #prints to screen
ldr r0, =format #calls format
mov r1, SP #Add Stack to register 1
bl scanf
ldr r3, [sp] #stores user input
add sp, sp, #16 #restores stack
mov r5, #0 #Moves 0 into R5
cmp r3, #0 #Compares r3 to 0
blt ex #branches to exception
// bgt ex2 #branches to exception2
storeValue:
STR r1, [r4]
add sp, sp, #24
getNum:
ldr r0, =userPrompt #calls prompt
bl printf #prints to screen
ldr r0, =format #Calls Format
mov r1, sp #Add Stack to register 1
bl scanf #Prints to Screen
ldr r3, [sp] #stores user input
add sp, sp, #16 #restores stack
mov r5, #0 #Moves 0 into R5
cmp r3, #0 #Compares r3 to decimal 0
blt exception #branches to excption if r3 = less than 0
loop: #Beginning of loop
cmp r4, r3 #Compares r3 to r4 to see if equal
bgt end #Greater than Branch
str r4,[] r4, r4, #1 #increases by 1
beq loop #branch if equal
blt loop #branch if less than
#End Program
mov r7, #1 #syscall
swi 0
ex:
ldr r0, = exception #calls exception to print(e)
bl printf #prints to screen
b getNum #branches to getNum to re-ask for a number
LrgNum:
.data
output: .asciz "\n\nLargest Number Entered %d is: %d\n\n\n" "\n\nSmallest Number Entered %d is: %d\n\n\n"
usrPrompt: .asciz "\n\nEnter positive numbers to compare. To see results enter -199 \t"
exception: .asciz "\nInvalid Entry. Enter a positive number greater than 0\n\n"
format: .asciz "%d"
input: .word 0
blanklines: .asciz "\n\n"
exitcom: .word "-199"
.end

For this very specific task, you don’t need an array at all: the minimum and maximum of a sequence can be computed “on-the-fly”, with no need for storing earlier values.
Now I won’t give you assembly code, but I think you already know how to implement all of it.
For the record: storing a sequence of unknown, arbitrarily long length would be much trickier, as you would need to allocate an initial buffer, then increase its capacity each time your buffer is full, by reallocating it with a larger capacity and copying its values. Last, but certainly not least: I am not entirely sure about ARM assembly, but I believe that, to be able to “allocate”, you would have to implement your own small memory manager (i.e., a malloc routine).

Related

I can input number and display what number I input. If i input 10, I need all even numbers between 1-10 added and all odd numbers

.equ READERROR, 0 #Used to check for scanf read error.
.global main # Have to use main because of C library uses.
main:
prompt:
# Ask the user to enter a number.
ldr r0, =strInputPrompt # Put the address of my string into the first parameter
bl printf # Call the C printf to display input prompt.
ldr r0, =numInputPattern # Setup to read in one number.
ldr r1, =intInput # load r1 with the address of where the
# input value will be stored.
bl scanf # scan the keyboard.
cmp r0, #READERROR # Check for a read error.
beq readerror # If there was a read error go handle it.
ldr r1, =intInput # Have to reload r1 because it gets wiped out.
ldr r1, [r1] # Read the contents of intInput and store in r1 so that
# it can be printed
ldr r0, =strOutputNum
bl printf
ldr r0, =strOutputEven
loop:
cmp r1, #101
beq end
cmp r1, #0
bne odd
cmp r1, #1
bne even
odd:
add r1, r1, LSL #1 /* r1 ← r1 + (r1 << 1) */
bl printf
even:
mov r1, r1, ASR #1 /* r1 ← (r1 >> 1) */
b end_loop
end_loop:
add r2, r2, #1 /* r2 ← r2 + 1 */
b loop /* branch to loop */
# Print the input out as a number.
# r1 contains the value input to keyboard.
b myexit # leave the code.
readerror:
# Got a read error from the scanf routine. Clear out the input buffer then
# branch back for the user to enter a value.
# Since an invalid entry was made we now have to clear out the input buffer by
# reading with this format %[^\n] which will read the buffer until the user
# presses the CR.
ldr r0, =strInputPattern
ldr r1, =strInputError # Put address into r1 for read.
bl scanf # scan the keyboard.
Not going to do anything with the input. This just cleans up the input buffer. The input buffer should now be clear so get another input.
b prompt
myexit:
End of my code. Force the exit and return control to OS
mov r7, #0x01 # SVC call to exit
svc 0 # Make the system call.
.data
Declare the strings and data needed
.balign 4
strInputPrompt: .asciz "Input a number between 1 and 100: \n"
.balign 4
strOutputNum: .asciz "You entered: %d \n"
.balign 4
strOutputEven: .asciz "The even numbers from 1 to %d are: \n"
Format pattern for scanf call.
.balign 4
numInputPattern: .asciz "%d" # integer format for read.
.balign 4
strInputPattern: .asciz "%[^\n]" # Used to clear the input buffer for invalid input.
.balign 4
strInputError: .skip 100*4 # User to clear the input buffer for invalid input.
.balign 4
intInput: .word 0 # Location used to store the user input.
.global printf
.global scanf
cannot get even and odd functions to work
The first problem is here:
cmp r1, #0
bne odd
cmp r1, #1
bne even
This actually compares the entire number to 0 or 1, when you only want the rightmost bit. You'll need to do something like this. I'll only list the even case, I think you can figure out the odd. I'm a bit rusty at ARM assembly and haven't tested this but something like it should work:
tst r1,#1 # sets the flags as you did "AND r1,r1,#1" but doesn't change r1
bne odd # now you will jump to label "odd" if r1 is odd, or keep
# going if it's even.
# if it isn't odd, it must be even, so your even code goes here!
push r1-r2 # technically this is a thumb mode only instruction but if your
# assembler allows unified syntax it should get assembled as the
# 32-bit instruction "STMFD sp!,{r1-r2}"
# this saves r1 and r2 on the stack, we get them back with POP.
# C functions assume the stack is aligned to 8 bytes so we have to push
# an even number of registers even though we only needed to push R1.
ldr r0,=strOutputEven # r1 still contains intInput
bl printf # prints "The even numbers from 1 to %d are,"
pop R1-R2 # unified syntax for "LDMFD sp!,{r1-r2}"
# now we'll do the loop:
ldr r0,=numInputPattern
mov r1,#0 # we don't need the input anymore
mov r2,#0 # the sum goes here
loop_even:
add r1,r1,#2
cmp r1,#101
bcc exitLoop # if R1 is greater than or equal to 101, exit.
PUSH R0-R3 # I can't remember what printf alters so better safe than sorry.
bl printf
POP R0-R3
add r2,r2,r1 # add R1 to R2 and store the result in R2.
b loop_even
exitloop:
mov r1,r2 # put the sum into r1 so we can print it
bl printf # print the string
b my_exit # we're done!
odd:
I would recommend reading up on the PUSH and POP instructions and how they work, it's a much more reliable way of temporarily preserving registers than the method you used with ldr r1,[r1]. Don't feel ashamed if you need to print out a reference list of the ARM instructions - I use one all the time.

Printing double digit numbers in LC-3

Been learning about LC-3 lately and was wondering how do I go about printing a number that's bigger then 9? In this program I made it asks for width and length and multiplies the two to get the area of the shape. My problem is any output bigger then 9 it starts printing a letter or a number not close to what I wanted. How should I go about doing this? my code:
.ORIG x3000
; Reset Registers
AND R0, R0, #0
AND R1, R1, #0
AND R2, R2, #0
AND R3, R3, #0
AND R4, R4, #0
AND R5, R5, #0
AND R6, R6, #0
AND R7, R7, #0
LEA R0, numberone
PUTS
GETC
OUT
LD R3, HEXN30
ADD R0, R0, R3
ADD R1, R0, #0
LEA R0, numbertwo
PUTS
GETC
OUT
ADD R0, R0, R3
ADD R6, R0, #0
LOOP
ADD R2, R2, R1
ADD R6, R6, #-1
BRp LOOP
LEA R0, MESG
PUTS
ADD R0, R2, x0
LD R2, NEG_TEN
ADD R2, R2, R0
BRn JUMP
AND R4, R4, #0
ADD R4, R4, R2
LD R0, ASCII_1
OUT
AND R0, R0, #0
ADD R0, R0, R4
JUMP
LD R3, HEX30 ;add 30 to integer to get integer character
ADD R0, R0, R3
OUT
HALT ;{TRAP 25}
numberone .stringz "\nPlease enter the length: "
numbertwo .stringz "\nPlease enter the width: "
MESG .STRINGZ "\n\nThe Area of the Rectangle is: "
HEXN30 .FILL xFFD0 ; -30 HEX
HEX30 .FILL x0030 ; 30 HEX
NEG_TEN .FILL #-10
ASCII_1 .FILL x0031 ; ASCII char '1'
.END
Example Output:
Please enter the length: 4
Please enter the width: 5
The area of the object is: 20
This code will always print 1:
LD R0, ASCII_1
OUT
There's no chance for it to print a 2 like you'd want from 4 times 5.
The next character prints as : because you have 10 in R4, as you haven't subtracted 10 enough times in the division by repetitive subtraction. You've only subtracted 10 once and 20 needs to have 10 subtracted twice (to get 0 as the remainder).
You should be able to see the first problem by simply reading the code there. How could loading an ascii 1 and printing it do anything other than print a 1? So there is some missing code there.
The latter problem is a form of off-by-one error (looping one to few iterations), which is something you should be looking for during single-step debugging. You want your division by repetitive subtraction to leave you with a remainder between 0 and 9 — definitely not 10!
Boundary conditions are very error prone. Using < when it should be <= (or vice vesa), for example, can result in an off by one error. What we do is try to use idioms to avoid these problems (like for(int i = 0; i < n; i++)), but when an idiom isn't applicable, then you want to be suspicious of and test those boundary conditions: at the boundary, at one less, at one more.

Loop through array of characters in ARM assembly

i have an assignment which requires me to loop through string of numbers and perform task based on each number. For example, if numbers are "24531", i have to blink the LED lights on my microprocessor boards which are on indices "2", "4", "5", "3" and "1".
I'm just stuck on the part where i need to loop through these string of numbers and have to interpret them individually in ARM assembly language.
Borrowing from original code by Colin__s
You can construe the string as byte size elements of some array.
Use ldrb to load byte from array at element n...
The code below will branch to "some function" when ASCII value for #4 is encountered. The code will fail to return; which is one of several things you will need to further resolve.
.data
array: .string "123456"
.equ len.array,.-array
.align
.text
.global main
main:
nop
ldr r2,=array // pointer
MOV r0, #0 // initialise loop index to 0
MOV r1, #len.array // number of elements
Loop:
ldrb r3, [r2,r0]
cmp r3, #0x34 // #4
beq _do_something
ADD r0, r0, #1 //increment loop index
CMP r0, r1
BLE Loop
_exit:
mov r7, #1
svc 0
_do_something:
ldr r10,=0xdeadc0de
I don't completely follow your question, but the code for a loop is below. You can add whatever it is you need to do on each iteration before the compare instruction.
MOV r0, #0 ;initialise loop index to 0
MOV r1, #100 ;number of iterations
Loop:
ADD r0, r0, #1 ;increment loop index
CMP r0, r1
BLE Loop

How do I loop through an array in LC-3 assembly and print out each item?

I have an array of size 10 that takes character input from a user. Now I just need to loop through the array and print out each character followed by a new line but I don't know where to start. LC-3 assembly is not my forte...
Here is my code so far:
LD R2, COUNTER
LEA R1, ARRAY
LD R4, COUNTER2
DO_WHILE_LOOP
GETC
STR R0, R1, #0
ADD R1, R1, #1
ADD R2, R2, #-1
BRp DO_WHILE_LOOP
END_DO_WHILE_LOOP
LEA R3, ARRAY
OUT_LOOP
END_OUT_LOOP
HALT
;Local Data
ARRAY .BLKW #10
COUNTER .FILL #10
NEWLINE .STRINGZ "\n"
COUNTER2 .FILL #10
.END
My question is basically what do i put inside the OUT_LOOP?
Well there are a number of different ways to do this. When you're printing the characters back to the user do you have to do it after you've received all of the user's input?
You could just print back to the user while they are typing:
DO_WHILE_LOOP
GETC
OUT
STR R0, R1, #0
ADD R1, R1, #1
ADD R2, R2, #-1
BRp DO_WHILE_LOOP
END_DO_WHILE_LOOP
If you have to print after collecting all of the user's input then you can just load the char array's memory location into R0 and then use the PUTs command.
Example:
LEA R0, ARRAY ; Load the ARRAY memory location into R0
PUTs ; Display all of the characters until it runs into null

Printf Change values in registers, ARM Assembly

I'm new to assembly programing and I'm programing for ARM.
I'm making a program with two subroutines: one that appends a byte info on a byte vector in memory, and one that prints this vector. The first address of the vector contains the number of elements that follows, up to 255. As I debug it with GDB, I can see that the "appendbyte" subroutine works fine. But when it comes to the "printvector" one, there are some problems. First, the element loaded in register r1 is wrong (it loads 0, when it should be 7). Then, when I read the registers values with GDB after I use the "printf" function, a lot of register get other values that weren't supposed to change, since I didn't modify them, I just used "printf". Why is "printf" modyfing the values.
I was thinking something about the align. I'm not sure if i'm using the directive correctly.
Here is the full code:
.text
.global main
.equ num, 255 # Max number of elements
main:
push {lr}
mov r8, #7
bl appendbyte
mov r8, #5
bl appendbyte
mov r8, #8
bl appendbyte
bl imprime
pop {pc}
.text
.align
printvector:
push {lr}
ldr r3, =vet # stores the address of the start of the vector in r3
ldr r2, [r3], #1 # stores the number of elements in r2
.align
loop:
cmp r2, #0 #if there isn't elements to print
beq fimimprime #quit subroutine
ldr r0, =node #r0 receives the print format
ldr r1, [r3], #1 #stores in r1 the value of the element pointed by r3. Increments r3 after that.
sub r2, r2, #1 #decrements r2 (number of elements left to print)
bl printf #call printf
b loop #continue on the loop
.align
endprint:
pop {pc}
.align
appendbyte:
push {lr}
ldr r0, =vet #stores in r0 the beggining address of the vector
ldr r1, [r0], #1 #stores in r1 the number of elements and makes r0 point to the next address
add r3, r0, r1 #stores in r3 the address of the first available position
str r8, [r3] #put the value at the first available position
ldr r0, =vet #stores in r0 the beggining address of the vector
add r1, r1, #1 # increment the number of elements in the vector
str r1, [r0] # stores it in the vector
pop {pc}
.data # Read/write data follows
.align # Make sure data is aligned on 32-bit boundaries
vet: .byte 0
.skip num # Reserve num bytes
.align
node: .asciz "[%d]\n"
.end
The problems are in
ldr r1, [r3], #1
and
bl printf
I hope I was clear on the problem.
Thanks in advance!
The ARM ABI specifies that registers r0-r3 and r12 are to be considered volatile on function calls. Meaning that the callee does not have to restore their value. LR also changes if you use bl, because LR will then contain the return address for the called function.
More information can be found on ARMs Information Center entry for the ABI or in the APCS (ARM Procedure Call Standard) document.
printvector:
push {lr}
ldr r3, =vet # stores the address of the start of the vector in r3
ldr r2, [r3], #1 # stores the number of elements in r2
.align
loop:
cmp r2, #0 #if there isn't elements to print
beq fimimprime #quit subroutine
ldr r0, =node #r0 receives the print format
ldr r1, [r3], #1 #stores in r1 the value of the element pointed by r3. Increments r3 after that.
sub r2, r2, #1 #decrements r2 (number of elements left to print)
bl printf #call printf
b loop #continue on the loop
.align
endprint:
pop {pc}
that is definitely not how you use align. Align is there to...align the thing that follows on some boundary (specified in an optional argument, note this is an assembler directive, not an instruction) by padding the binary with zeros or whatever the padding is. So you dont want a .align in the code flow, between instructions. You have done that between the ldr r1, and the cmp r2 after loop. Now the align after b loop is not harmful as the branch is unconditional but at the same time not necessary as there is no reason to align there the assembler is generating an instruction flow so the bytes cant be unaligned. Where you would use .align is after some data declaration before instructions:
.byte 1,2,3,4,5,
.align
some_code_branch_dest:
In particular one where the assembler complains or the code crashes.

Resources