I am trying to translate
while ((getchar()) != '\n');
into assembly but am finding it difficult.
You would use something like this:
li s0, 10
again:
call getchar
bne a0, s0,again
Related
Hello i am a beginer risc-v learner and i want to do a scanf of an int and print it on console
upon searching a lot on the internet i couldnt find how to proper do it, i try
using compiler explorer https://godbolt.org/ i want to use this c code
#include<stdio.h>
int main(){
int number;
printf("enter a number:");
scanf("%d",&number);
printf("number is:%d ",number);
return 0;
}
and its giving me this risc-v code
main: # #main
addi sp, sp, -32
sw ra, 28(sp) # 4-byte Folded Spill
sw s0, 24(sp) # 4-byte Folded Spill
addi s0, sp, 32
mv a0, zero
sw a0, -20(s0) # 4-byte Folded Spill
sw a0, -12(s0)
lui a0, %hi(.L.str)
addi a0, a0, %lo(.L.str)
call printf
lui a0, %hi(.L.str.1)
addi a0, a0, %lo(.L.str.1)
addi a1, s0, -16
call scanf
lw a1, -16(s0)
lui a0, %hi(.L.str.2)
addi a0, a0, %lo(.L.str.2)
call printf
lw a0, -20(s0) # 4-byte Folded Reload
lw s0, 24(sp) # 4-byte Folded Reload
lw ra, 28(sp) # 4-byte Folded Reload
addi sp, sp, 32
ret
.L.str:
.asciz "enter a number:"
.L.str.1:
.asciz "%d"
.L.str.2:
.asciz "number is:%d "
but the part
call printf
call scanf
doesnt work and i cant figure how to do such a esy work any tips?
linker will give undefined reference error because directly you not compiled it in C instead took assembly code from gcc and gave it to linker.
if you directly compile with c you will get reference to printf and scanf and for risk v you can tell c to give static binary instead of dynamic
If i not understood what you want to know than plz explain
Just have one little thing I got stuck on while translating this C code into assembly. This is the line of code I am stuck on.
if (input == '\n')
My assembly code thus far(for this line) is
movl input, %eax #%eax = input
cmpl ___, %eax
How do I compare input to '\n'? Do I just compare it outright or do I move it into the memory first? Thanks.
Try
cmp 0x0D,%eax
0x0D is the ascii code for carriage return, or you can try 0x0A for line feed.
Compare it directly, cmp allows for immediate values.
Quick question. I'm looking to translate this C code into MIPS assembly language:
f=g-A[B[4]]
I can use any registers to place the variables so I used the following:
$s1=f, $s2=g, $s3=A, $s4=B, $t0=B[4], $t1=A[B[4]]
Here is the code I have tried so far but I am not sure if it is correct or not:
lw $t0, 16($s4)
add $t0, $t0, $s3
lw $t1, 0($t0)
sub $s1, $s2, $t1
Can you guys help me edit this? Thank you in advance.
Looks like you didn't scale the index of A by the size of the A elements. You probably want to multiply $t0 by 4 before adding $s3.
If you have some C code you can compile it to assembly using gcc
gcc-mipsel-linux-gnu -save-temps program.c
cat program.S
this assumes you have a mipsel [cross-]compiler installed, get one from
http://www.emdebian.org/crosstools.html
or
https://wiki.debian.org/BuildingCrossCompilers
How would I convert this code into Mips?
int n = 100; int sum = 0; while (n>0) {
sum = sum + n;
n--; }
I have this so far and am not sure what to do to finish this.
.data
n: .word 100
.text
main:
la $t0, n
lw $t1, 0(t0)
li $so, 0
Loop:
bgt $t1, $zero, EXIT
add $t1, $s0, $t1
addi $t1, $t1, -1
j Loop
exit:
Change the line:
add $t1, $s0, $t1
To:
add $s0, $s0, $t1
Also, there is no need for use of the data segment. Just set $t1 using:
li $t1, 100
"Mips" isn't a language. MIPS an Instruction Set Architecture (ISA). Are you trying to figure out how to turn the C code into MIPS assembly code?
This looks like a homework assignment from the Patterson and Hennessy textbook. If so, you should go to your professor's office hours to get help. Almost every university includes in its academic handbook a statement that it's unethical to ask for homework help online.
If your request isn't a homework assignment, then the best way to convert that C code into MIPS assembly code is with a compiler. For simple loops, the compiler will generate more effective code than you can generate by hand. For example, "gcc -march=native -O3" will generate code that optimizes for the exact CPU on which you're compiling, taking into account pipeline depth and cache latencies.
If you absolutely need to see the assembly code, use "gcc -S" to produce an assembly file.
Mips doesn't have loops per-say, instead what your going to do is use a jump statement with conditions and loop with that.
I think bgt $t1, $zero, EXIT is the opposite of what you want. It seems like you want to convert while(n > 100), it would help if you make another method to do the codes inside of the while loop, then bgt $t1, $zero, . Correct me if I'm wrong.
I have a simple question for a Comp Sci class I'm taking where my task is to convert a function into MIPS assembly language. I believe I have a correct answer but I want to verify it.
This is the C function
int strlen(char *s) {
int len;
len=0;
while(*s != '\0') {
len++;
s++;
}
return len;
}
Thanks!
strlen:
add $v0, $zero, $zero # len = 0
loop: # do{
lbu $t0, 0($a0) # tmp0 = load *s
addi $a0, $a0, 1 # s++
addi $v0, $v0, 1 # len++
bne $t0, $zero, loop # }while(tmp0 != 0)
s_end:
addi $v0, $v0, -1 # undo counting of the terminating 0
j $ra
Yeah, you have a correct asm version, and I like the fact that you do as much work as possible before testing the value of t0 to give as much time as possible for loading from memory.
(Editor's note: the add of -1 after the loop corrects for off by 1 while still allowing an efficient do{}while loop structure. This answer proposes a more literal translation from C into an if() break inside an unconditional loop.)
I think the while loop isn't right in the case of *s == 0.
It should be something like this:
...
lbu $t0, 0($a0)
loop:
beq $t0, $zero, s_end # *
...
b loop
s_end:
...
*You could use a macro instruction (beqz $t0, s_end) instead of beq instruction.
Yes, looks correct to me, and fairly efficient. Implementing a while loop with asm structured like a do{}while() is the standard and best way to loop in asm. Why are loops always compiled into "do...while" style (tail jump)?
A more direct transliteration of the C would check *s before incrementing len.
e.g. by peeling the first iteration and turning it into a load/branch that can skip the whole loop for an empty string. (And reordering the loop body, which would probably put the load close to the branch, worse for performance because of load latency.)
You could optimize away the len-- overshoot-correction after the loop: start with len=-1 instead of 0. Use li $v0, -1 which can still be implemented with a single instruction:
addiu $v0, $zero, -1
A further step of optimization is to only do the pointer increment inside the loop, and find the length at the end with len = end - start.
We can correct for the off-by-one (to not count the terminator) by offsetting the incoming pointer while we're copying it to another reg.
# char *s input in $a0, size_t length returned in $v0
strlen:
addiu $v0, $a0, 1 # char *start_1 = start + 1
loop: # do{
lbu $t0, ($a0) # char tmp0 = load *s
addiu $a0, $a0, 1 # s++
bne $t0, $zero, loop # }while(tmp0 != '\0')
s_end:
subu $v0, $a0, $v0 # size_t len = s - start
jr $ra
I used addiu / subu because I don't want it to fault on signed-overflow of a pointer. Your version should probably use addiu as well so it works for strings up to 4GB, not just 2.
Untested, but we can think through the correctness:
For an empty string input (s points at a 0): when we reach the final subtract, we have v0=s+1 (from before the loop) and a0=s+1 (from the first/only iteration which falls through because it loads $t0 = 0). Subtracting these gives len=0 = strlen("")
For a length=1 string: v0=s+1, but the loop body runs twice so we have a0=s+2. len = (s+2) - (s+1) = 1.
By induction, larger lengths work too.
For MIPS with a branch-delay slot, the addiu and subu can be reordered after bne and jr respectively, filling those branch-delay slots. (But then bne is right after the load so classic MIPS would have to stall, or even fill the load-delay slot with a nop on a MIPS I without interlocks for loads).
Of course if you actually care about real-world strlen performance for small to medium strings (not just tiny), like more than 8 or 16 bytes, use a bithack that checks whole words at once for maybe having a 0 byte.
Why does glibc's strlen need to be so complicated to run quickly?