MIPS - help converting code from C - c

I am a beginner in MIPS and I am trying to write a simple code that runs over a given array in memory that is smaller than 10 cells, lets say 9 cells, and prints on screen the biggest number.
I wrote a C code that solves this issue, but I don't know how to convert it (without mips gcc) to a working MIPS assembly code.
The code I wrote:
int N = 9 , i = 0 , biggest = 0 ;
int arr [N] = -2 , 3 , 9 , -1 , 5 , 6 , 10 , 52 , 9 ;
while ( i <= N )
{
if ( arr [i] > biggest )
biggest = arr [i] ;
i++ ;
}
printf ( "biggest number is: %d" , biggest ) ;
I will be more than happy if someone can write that code in MIPS assembly, and explain it to me.
Thank you !

Just focusing on the loop, try something like that:
.text
.set noreorder
.global get_max
get_max:
li $4, array // start pointer
li $5, array_end-array-4 // end pointer
li $2, 0 // 'biggest' as result
lw $6, 0($4) // load first table entry
1: slt $3, $2, $6 // boolean flag (biggest<arr[i])
movn $2, $6, $3 // update 'biggest' when flag is set
lw $6, 4($4) // load next table entry
bne $4, $5, 1b // continue until we hit end of array
addiu $4, 4 // advance to next cell (using bne delay slot)
jr $31 // return to the caller
nop // safely fill the delay slot
.data
array: .long -2 , 3 , 9 , -1 , 5 , 6 , 10 , 52 , 9
array_end: .long 0
Compile this into a separate assembly source file and link with your main C code.
Don't forget to call the function from your C code:
printf("biggest=%d\n",get_max());

You have a problem with your initialization...

Related

writing generated numbers to a table in assembler

I am generating 5 random numbers and I want to write them down to a table. At the end, in the variable array, I have one digit, that is, the last one that was generated. How can I make sure that they are all, the previous figure is also saved?
_DATA SEGMENT
array dd 5 dup(?)
_DATA ENDS
_TEXT SEGMENT
main proc
; -- generating random numbers --
call GetTickCount
push eax
call nseed
mov ecx, 5
generateRandomNumbers:
push ecx
;--- generating random numbers from 0 to 9 ---
push 9
call nrandom
mov array, eax
pop ecx
loop generateRandomNumbers
; -- end --
push 0
call ExitProcess
main endp
_TEXT ENDS
My output:
&array = 2
I would like to receive
&array = 5, 1, 7, 6, 4

Sorting only odd/even numbers in assembly, how to copy an array without using already allocated memory?

TL;DR: How to copy elements from one array to another (not all but some)?
I want to perform a sorting algorithm on some array, but so that I only sort odd or even numbers in it, depending on a flag. So my idea was to set a flag on either 0 or 1 and then I'd extract all the numbers that have to be sorted into another array and put -1 (as a marker) on the positions where those numbers were. After that I'd just insert the sorted numbers back into the original array, for example:
arr1: 5 8 2 4 13 9 14 10 9
arr2: 8 2 4 14 10
arr2 (sorted): 2 4 8 10 14
arr1 (without even numbers): 5 -1 -1 -1 13 9 -1 -1 9
arr1 (final): 5 2 4 8 13 9 10 14 9
Now while writing this in a higher language is rather trivial for me, doing it in assembly which I'm learning for a class isn't. The part where I sort the numbers works just fine, but the part that causes me problems is the one where I have to copy the numbers into another array. My main method looks like this:
section .data
arr dd 6,8,1,7,4,2,9,107,10,8,12,16,14,5
len equ ($-arr) / 4 - 1
section .bss
section .text
extern sort
global _start
_start:
mov r8, len
mov esi, arr ; esi points to the start of the array/top of it
call sort
mov rax, 60
mov rdi, 0
syscall
And the subroutine which will do the job (showing only the problematic part):
mov r9d, esi
.export:
mov eax, [r9d]
cdq
div dword [divider]
cmp edx, [flag]
je .add
.continue:
add r9d, 4 ; point to the next number
inc dword [i]
cmp r8d, [i]
jg .export
.add:
mov edi, [r9d]
mov dword [r9d], -1 ; put the number in the old array to -1
sub edi, 4
inc dword [lenNewArray] ; inc the total number of elements in new array
jmp .continue
Anyway what I want to accomplish is that I add an element that matches the condition to some location and then point rdi to that location, when I want to add another element I subtract -4 from rdi so it points to the lower location and put that element there, in the end I'd have rdi pointing to the last element which was extracted, is that possible to be done, and is it a bad way?

MIPS Constructing Loops

Okay, so this might be a really silly question but I don't quite have the hang of Assembly yet. I have to write a program that calculates the summation of a series of numbers. It should behave like so:
Enter the first integer in the series: 5
Enter the number of integers in the series: 3
Enter the offset between integers in the series: 4
The series is: 5, 9, 13.
The summation of the series is 27.
Would you like to calculate another summation (Y/N)? y
Enter the first integer in the series: 4
Enter the number of integers in the series: 5
Enter the offset between integers in the series: 27
The series is 4, 31, 58, 85, 112.
The summation of the series is 290.
Would you like to calculate another summation (Y/N)? Y
Enter the first integer in the series: -16
Enter the number of integers in the series: -22
There must be a positive number of integers in the series.
Would you like to calculate another summation (Y/N)? n
This is what I have so far:
li $v0, 4 #put 4 in as main parameter in v0
la $a0, Q1 #syscall will print string query 1
syscall
Store first integer in series in s0
li $v0, 5 #put 5 in as main parameter in v0
syscall #syscall will read integer from Q1
move $s0, $v0 #move integer in v0 to s0
Request number of integers in series
li $v0, 4 #put 4 in as main parameter in v0
la $a0, Q2 #syscall will print string query 2
syscall
Store number of integers in series in s1
li $v0, 5 #put 5 in as main parameter in v0
syscall #syscall will read integer from Q2
move $s1, $v0 #move integer in v0 to s1
Request offset of integers
li $v0, 4 #put 4 in as main parameter in v0
la $a0, Q3 #syscall will print string query 3
syscall
Store offset of integers in s2
li $v0, 5 #put 5 in as main parameter in v0
syscall #syscall will read integer from Q3
move $s2, $v0 #move integer in v0 to s1
Set counter
li $s3, 1 #Set counter to zero
li $t0, 1 #iterator count is in t0
I'm just curious as to where to start my loop? And how exactly would I go about printing the entire series? Any advice would be greatly appreciated.
I'm not sure what you do in "set counter" part, as the s1 already contains number of series members.
And s0 contains current element.
All you need (additional information) is to clear current_sum, let's say as s3:
add $s3, $zero, $zero ; or "move $s3, $zero" if you prefer the pseudo-ops
So for your first example s0-s3 will be set to [5, 3, 4, 0] before first loop iteration. This is everything ("world state") you need, any other value you will set up is probably some temporary for particular sub-task like displaying some value and similar, but as long as the core computation goes, these four values represent all you need, and everything else can be based upon them.
If s1 is already less than 1 (<=0 test), report wrong input.
Then the loop algorithm:
add current element (s0) to current sum (s3) ; summing up all numbers
display current element (s0)
; handle the correct count of series' members
decrement counter s1
if s1 is zero, then goto exit_loop
; preparing for next loop iteration
add offset (s2) to current element (s0)
display ", "
jump to first step
exit_loop: logic will involve printing end of line, summation text description, current sum value (s3), another new line(s) and asking for repeat y/n.
For example that 4 core values will evolve during iterations like this:
[5, 3, 4, 0] => displays "5, " + all the updating of values
[9, 2, 4, 5] => displays "9, " + all the updating of values
[13, 1, 4, 14] => modifies s3 to 27, displays "13", --s1, jumps to exit_loop
At exit_loop the core values are [13, 0, 4, 27], code will display 27 as series sum.

C increment/decrement operators [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
Determine the value of each variable after calculation is performed. All variables have value 5 before execution.
A1/=++B1/--C1
A2+=++B2%C2--
please tell me how this work
Variables:
int A1 = 5;
int B1 = 5;
int C1 = 5;
int A2 = 5;
int B2 = 5;
int C2 = 5;
Your code:
A1 /= ++B1 / --C1;
A2 += ++B2 % C2--;
Will probably compile into something similar too:
++B1;
--C1;
A1 /= B1 / C1;
++B2;
A2 += B2 % C2;
C2--;
You can output the ASM using your compiler, with GCC its the -S flag. Here is the ASM output with GCC on my computer (I added the comments):
movl $5, -20(%rbp) // A1 = 5
movl $5, -24(%rbp) // B1 = 5
movl $5, -28(%rbp) // C1 = 5
movl $5, -32(%rbp) // A2 = 5
movl $5, -36(%rbp) // B2 = 5
movl $5, -40(%rbp) // C2 = 5
Then for the first one calculation, this is performed (comments simplified for easier understanding):
addl $1, -24(%rbp) // ++B1
subl $1, -28(%rbp) // --C1
movl -24(%rbp), %eax //
cltd
idivl -28(%rbp) // divide B1 by C1
movl %eax, %esi //
movl -20(%rbp), %eax //
cltd
idivl %esi // divide A1 by the previous
movl %eax, -20(%rbp)
By the C Operator Precedence Table: http://www.difranco.net/compsci/C_Operator_Precedence_Table.htm
For 1:
A1 /= ++B1 / --C1
C1 will first be decremented by 1 to 4
B1 will then be incremented by 1 to 6
B1 (6) will be divided by C1 (4), result of which will be 1
A1 will be assigned with the result of the division A1 (5) and 1, which is 5
Results for each will be 5, 6 and 4 for A1, B1 and C1, respectively.
For 2:
A2 += ++B2 % C2--
C2 will first be marked to get decremented close to the end of the statement, remains 5 for now
B2 will then be incremented by 1 to 6
The remainder from the division B2 (6) by C2 (5) will get calculated, which is 1
A2 will be assigned with the result of the addition of A2 (5) and 1, which is 6
C2 will be decremented by 1 to 4
Results for each will be 6, 6 and 4 for A2, B2 and C2, respectively.
Pardon me if I have made any mistakes, you can always check these with your compiler.

nested loop in 8086 assembly language

I am having problem on how exactly should i use loop to get the desire output in this program,
What i want to do is to take input any number from the user and then sort that number in descending order,
I tried my best here to explain every step of the code in the comment.
here is my code,
STSEG SEGMENT
DB 64 DUP(?)
STSEG ENDS
DTSEG SEGMENT
SNAME DB 24 DUP("$")
DTSEG ENDS
CDSEG SEGMENT
MAIN PROC
ASSUME CS:CDSEG, DS:DTSEG, SS:STSEG
MOV AX,DTSEG
MOV DS,AX
MOV ES, AX ;ES:DI
MOV DX, OFFSET STRNG1
MOV AH,09
INT 21H
XOR DX,DX
MOV BYTE PTR SNAME, 40
MOV DX, OFFSET SNAME
MOV AH, 0AH
INT 21H
PUSH DX ;Hold the input number in a stack until we clear the screen and set the cursor
; The clear screen and cursor position code is here which i didn't really mention.
;What we need to do now is to compare first number to each other number and store the greatest
of two on first position.
MOV BX,DX ;Copy un-sorted number to BX,
MOV AX,BX[1] ;the length of the number which is stored on the first position of the string
XOR AH,AH ;Empty AH
MOV CL,AL ;MOVE AL into CL for looping 6 times
SUB CL,1
MOV SI,02H ;the number is stored in string array from the 2nd position
;Suppose the input number is the following,
;[6][3][9][1][8][2][6]
;this is how it should work,
; Loop 6 times , CX = 6
[7][6][3][9][1][8][2][6] ; 7 is length of the number which is already copied in CX above.
; but we need 6 iterations this is why we subtract 1 from CL above.
; 6 > 3 ?
; Yes, then BX[SI] = 6 and BX[SI+1] = 3
; 6 > 9 ?
; NO, then BX[SI] = 9 and BX[SI+2] = 6
; 9 > 1
; Yes, then BX[SI] = 9 and BX[SI+3] = 1
; 9 > 8
; Yes, then BX[SI] = 9 and BX[SI+4] = 8
; 9 > 2
; Yes, then BX[SI] = 9 and BX[SI+5] = 2
; 9 > 6
; Yes, then BX[SI] = 9 and BX[SI+6] = 6
; After first iteration the incomplete sorted number is,
;[9][3][6][1][8][2][6]
;Similarly here i need to loop 5 times now by comparing the 2nd number which is a 3 with all ;the number after it and then loop 4 times then 3 times then two times and then 1 time.
L1:
;Loop 1 must iterate 6 time for the supposed input number,
;but i couldn't be able to write the proper code as i always get out of registers. kindly help me out
L2:
LOOP L2
Loop L1
Kindly help me with the nested loop where i've stucked.
The loop instruction uses the cx register.
So you must either preserve cx for the outer loop with e.g. push cx (before L2:) and pop cx (after loop L2):
mov cx,5
L1:
push cx
mov cx,6
L2:
. . . do stuff inner
loop L2
pop cx
. . . do stuff outer
loop L1
or remember that loop is roughly equal to dec cx jnz, so do e.g.
mov dx,5
L1:
mov cx,6
L2:
... do stuf inner
loop L2
.. do stuff outer
dec dx
jnz L1
Possible off-by-one errors are intended and meant as an exercise for the reader :-)

Resources