Loop through array of characters in ARM assembly - arm

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

Related

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

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).

Loading Values From An Array In Assembly Language

I am working on one of the simple codes assigned for a ARM microprocessor course I'm taking. I am having a slight issue with getting my code to load a value of an array to compare using Keil. The program is supposed to compare 5 numbers and then store values if the comparison is true. When I run my program it will not load array values that I declared. My professor isn't much help either and doesn't seem to know why it's not working properly.
Here's what I have done so far. I also think my PUSH is wrong but I can probably figure that out after I at least get the array to load. I should be pushing those values onto the stack but I am pretty sure I'm just loading values in registers instead.
AREA main, CODE, READONLY
EXPORT __main
ENTRY
__main PROC
MOVS r5, #0
LDR r0, =NUMB
loop1
LDR r1, [r0]
CMP r5, #5
BEQ stop
loop
CMP r1, #10
BLT low10
CMP r1, #100
BLT mid
CMP r1, #255
BLT high100
low10
PUSH {r2}
MOVS r2, #2
ADDS r5, #1
B loop1
mid
PUSH {r3}
MOVS r3, #0
ADDS r5, #1
B loop1
high100
PUSH {r4}
MOVS r4, #1
ADDS r5, #1
B loop1
stop B stop
ENDP
AREA myDATA, DATA, READWRITE
ALIGN
NUMB DCD 1,11,111,11,1
END
With respect to the array, your element size is not 1-byte, it's 4-bytes.
Using GNU & GDB, if we examine the address at R0 and interpret as signed words (i.e, 4 byte form), we see the expected array values.
.data
NUMB: .word 1,11,111,11,1
...
LDR r0, =NUMB
(gdb) x/8wd $r0
0x200dc: 1 11 111 11
0x200ec: 1 4929 1634033920 16804194
So you will need to change your values in the context of R5 to assume a 4-byte word. E.g.,
CMP r5, #(4*5)
ADDS r5, #4
Is is sadly very simple, just change in myData READWRITE to READONLY :)

How do I get my dot: function to loop back up properly?

first timer here.
I am attempting to code an arm assembly morse code translator on my raspberry pi 3. The program should read the string literal (x), take the corresponding morse code string (h) and scan through the string (".... ") and output a dot on the LED set up on my breadboard for every period in the string.
My original code involved actually having a whole word to be scanned character by character and translated. My LED would just light up way before a function for lighting up the LED was even called and the program would stall. So I made this side program to try and translate only a single letter [in this case "H"] and have it output correctly on my LED.
My issue here is that I cannot get the code to loop back to LED_lp: (via exit_if:) after it branches into the dot: function in order to output the dots in the ".... " string out on the LED.
I've tried numerous things, including
pushing {lr} / popping {pc} in different areas of the labels in case it had something to do with the stack
moving away from the primary registers (r0, r1, etc.) in case it was conflicting with the wiringPi commands
[which I came to the conclusion that it does conflict, even if you are not trying to load a pin number or calling pinMode, it seemed that loading registers r0, r1 with values like 0 and 1 caused premature and unwanted changes to the pin modes / LED outputs.] Please let me know if I am incorrect about that conclusion.
Even my assembly professor was unsure of what was wrong with my code or why my LED output was not behaving properly when reviewing my original.
Apologies for the wall of text, but I assumed that a little extra backstory would save some time and avoid vagueness. I hope someone is able to assist, as I need to implement this to my final project.
Thanks in advance
.equ MY_PIN, 25
.equ OUTPUT, 1
.equ INPUT, 0
.equ LOW, 0
.equ HIGH, 1
.data
x: .asciz "H"
h: .asciz "...."
.text
.global main
main:
push {lr}
bl wiringPiSetup
ldr r4, =x
mov r5, #0
lp:
mov r6, r4 // mov r4 [x] into r6
cmp r6, #72 // check if r6 = H ascii code
beq _do_H // if equal branch to _do_H
_do_H:
ldr r4, =h
bl LED
LED:
push {lr}
mov r5, #0
LED_lp:
ldrb r6, [r4, +r5] // scan for first char in r6
cmp r6, #0 // cmp , if string done branch to exit_if
beq exit_LED
cmp r6, #46 // cmp, if first char is dash, branch to dash_check
bne check_dash
bl dot // else branch to dot
check_dash:
cmp r6, #45
beq dash
exit_if:
add r5, #1 // increment index for string scan
bal LED_lp
exit_LED:
pop {pc}
dot:
push {r0, r1,r2}
mov r0, #MY_PIN
mov r1, #HIGH
bl digitalWrite
mov r0, #100
bl delay
mov r0, #MY_PIN
mov r1, #LOW
bl digitalWrite
// bl exit_if $$ having this line BEFORE the pop causes LED to stay on
// for more than 100 ms, but seems to terminate the program after it
// lights up
pop {r0, r1,r2}
// bl exit_if $$ having this line AFTER the pop causes the led to stay on
// $$ for longer than 100 ms, and gets the program stuck running? after
// $$ execution
dash: // commented out dash to work on dot, left here for reference
// push {lr}
push {r0,r1,r2}
// mov r0, #MY_PIN
// mov r1, #HIGH
// bl digitalWrite
// mov r0, #1000
// bl delay
// mov r0, #MY_PIN
// mov r1, #LOW
// bl digitalWrite
pop {r0,r1,r2}
// pop {pc}
/////////end

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