How to use bne in mips? - conditional-statements

So I am trying to bne as if statements in my code to jump to labels. From what i understand bne is does not equal go to label specified. But the problem is i'm not getting any output for my print statements. Am i using bne wrong? I apologize for the ugly code, it's my first time using mips.
# Arthor: Christian Soto
#
# Simple conditional statements
.data
MSG: .asciiz "Copying from alpha to charlie. Before: "
string2: .asciiz " After: "
string3: .asciiz " alpha was the same as bravo."
string4: .asciiz "alpha was the same as charlie."
string5: .asciiz "bravo was the same as charlie."
string6: .asciiz "\n"
string7: .asciiz "alpha-bravo-charlie="
my_var: .word 1
copy: .word 2
dups: .word 1
alpha: .word 2
charlie: .word 2
bravo: .word 2
.text
.globl studentMain
studentMain:
addiu $sp, $sp, -24 # allocate stack space -- default of 24 here
sw $fp, 0($sp) # save caller’s frame pointer
sw $ra, 4($sp) # save return address
addiu $fp, $sp, 20 # setup main’s frame pointer
#Load vaiables
#set $s0 = copy
la $t0, copy
lw $s0, 0($t0)
#set $s1 = dups
la $t0, dups
lw $s1, 0($t0)
#set $s2 = subtract
#la $t0, subtract
#lw $s2, 0($t0)
#set $s3 = print
#la $t0, print
#lw $s3, 0($t0)
#set $s4 = alpha
la $t0, alpha
lw $s4, 0($t0)
#set $s5 = bravo
la $t0, bravo
lw $s5, 0($t0)
#set $s6 = charlie
la $t0, charlie
lw $s6, 0($t0)
#set $s7 = my_var
la $t0, my_var
lw $s7, 0($t0)
#Task 1: copy
bne $s7, $s0, DO_DUPS #if they do not equal then do dups
li $v0, 4
la $a0, MSG
syscall
la $t0, charlie #t0 = &charlie
lw $t0, 0($t0) #t0 = charlie
li $v0, 1
la $a0, ($t0)
syscall
li $v0, 4
la $a0, string2
syscall
la $t1, alpha #t1 = $alpha
lw $t2, 0($t1) #t2 = alpha
add $s6, $zero, $t2 #s6 = t2
li $v0, 1
la $a0, ($s6)
syscall
#Task 2: Dups
DO_DUPS:
bne $s7, $s1, DO_SUBTRACT #if they do not equal then do subtract
bne $s4, $s5, DO_NEXT #compare alpha and bravo else print message
li $v0, 4
la $a0, string3
DO_NEXT:
bne $s4, $s6, DO_NEXT2 #compare alpha and charlie else print message
li $v0, 4
la $a0, string4
DO_NEXT2:
bne $s5, $s6, DO_SUBTRACT #compare charlie and bravo else print message
li $v0, 4
la $a0, string5
DO_SUBTRACT:
#Task 3: Subtract
#Task 4: Print
j DONE
DONE: # Epilogue for main -- restore stack & frame pointers and return
lw $ra, 4($sp) # get return address from stack
lw $fp, 0($sp) # restore the caller's frame pointer
addiu $sp, $sp, 24 # restore the caller's stack pointer
jr $ra # return to caller's code

i forgot to add a syscall to see the results but i fixed it now

Related

Awk - print the number of row between a selected range from variable in awk and increment his value when variable change after user keypress

This question is more further developed with reference to the following case awk print the number of columns between a selected range from awk
I have the next short script:
#!/bin/bash
#Control del buffer
#awk en stackowerflow
#https://stackoverflow.com/questions/74483916/awk-print-the-number-of-columns-between-a-selected-range-from-awk/74483975?noredirect=1#comment131485506_74483975
if [ $# -eq 1 ]; then
FICH="${1}"
else
FICH="donaciones"
fi
#_INIT valores globales para mostrar debajo en la ultima linea
#alto_INIT necesario para poner texto abajo en la ultima linea
alto_INIT=`tput lines`
alto=`expr $alto_INIT - 2`
largo=`tput cols`
TOTAL_LINEAS_INIT=`cat "$FICH" | wc -l`
TOTAL_LINEAS=$TOTAL_LINEAS_INIT
#Mostramos solo las lineas dependiendo del alto del terminal
#Numero de paginas que hay que mostrar
LINEA=`expr $TOTAL_LINEAS - $alto`
NUM_PAG=`echo "scale=1; $TOTAL_LINEAS / $alto"|bc`
#Si el sresto de dividdir NPAG entre n lineas es +0 sumanos 1 pag. mas
if [ "${NUM_PAG##*.}" -gt 0 ]; then
NUM_PAG=`echo "scale=0; ${NUM_PAG}" + 1 |bc`
NUM_PAG=${NUM_PAG%%.*}
fi
buffer=`awk -v total_lineas="$TOTAL_LINEAS" -v linea="$LINEA" 'NR>=linea&&NR<=total_lineas' "$FICH"`
function Arriba(){
TOTAL_LINEAS=`expr $TOTAL_LINEAS - $alto`
DESDE=`expr $TOTAL_LINEAS - $alto`
HASTA=$TOTAL_LINEAS
if [[ $DESDE -lt 0 ]] ; then
DESDE=0
HASTA=`expr $DESDE + $alto`
fi
buffer=`awk -v desde="$DESDE" -v hasta="$HASTA" 'NR>=desde&&NR<=hasta' "$FICH"`
TOTAL_LINEAS=`expr $HASTA + 1`
}
function Abajo(){
DESDE=$TOTAL_LINEAS
HASTA=`expr $TOTAL_LINEAS + $alto`
if [[ $HASTA -gt $TOTAL_LINEAS_INIT ]] ; then
HASTA=$TOTAL_LINEAS_INIT
fi
buffer=`awk -v desde="$DESDE" -v hasta="$HASTA" 'NR>=desde&&NR<=hasta' "$FICH"`
TOTAL_LINEAS=$HASTA
}
while true; do
clear
printf "$buffer"
tput cup $alto_INIT 0 && printf "Total Lineas: $TOTAL_LINEAS_INIT | Total Pag: $NUM_PAG |Buffer: De $DESDE hasta $HASTA | $TOTAL_LINEAS | (w) Ayuda"
read -rsn1 TECLA
case $TECLA in
h) Arriba ;;
j) Abajo ;;
w) Help ;;
q) printf "\n" && break ;;
esac
done
exit 0
The goal here is show the number of line from a range of lines invoked by awk.
The program calculate the global lines of terminal and made a pagination from a file.Like
less, but i want to show only the portion of the file when the user press a "h" or "j" key. Every time the user press the key "h" the buffer ( portion of file) change and show
the correct part of file in dependence of number of rows. And when the user press the "j" key the buffer return to the previous key.
The program works ok but i want that when awk show the buffer , give me the number of line that correspond to this global line of the file. For this, i have the variable $TOTAL_LINEAS that increment or decrement every instruction buffer change. And this buffer instruction show from this TOTAL_LINEAS until the lines of terminal , and this every time the user press key. In the previous answer i can to add this number of line
but when the user press a key for change the new buffer text allways print the number for this buffer but not for the global buffer that correspond to real line of the file. In other words, allways print the number of line but in this portion of text not for the global text.
I.E: if i have
1 1:20220413:20:Curso Astrología:5:Vicente Ferrer
2 1:10042022:0:Donación instituto Samye:103:Propia
3 14:20220428:0:Candelario Yeshe Nyimpo Inc:9:Dudjom Tersar
4 1:20220512:60:Ayuda por el Hambre y Violencia:6:Vicente Ferrer
Total Lineas: 43 | Total Pag: 2 |Buffer: De 0 hasta 26 | 27
but in the next keypress for go to the next page i need:
5 1:20220413:20:111
6 1:10042022:0:22
7 14:20220428:0:33
8 1:20220512:60:44
Total Lineas: 43 | Total Pag: 2 |Buffer: De 27 hasta 43 | 43
and not:
1 1:20220413:20:111
2 1:10042022:0:22
3 14:20220428:0:33
4 1:20220512:60:44
Total Lineas: 43 | Total Pag: 2 |Buffer: De 27 hasta 43 | 43
Finally was easy:
buffer=`echo "$buffer" |awk -v i=$TOTAL_LINEAS 'NR==i !NF{print;next} NF{print ++i, $0}'`
Thanks all !!

I am writing HLA language to determine the input are the same or not the same

PROGRAM 6: Same
Write an HLA Assembly language program that implements a function which correctly identifies when all four parameters are the same and returns a boolean value in AL (1 when all four values are equal; 0 otherwise). This function should have the following signature:
procedure theSame( w:int16; x:int16; y:int16; z:int16 ); #nodisplay; #noframe;
Shown below is a sample program dialogue.
Feed Me W: 215
Feed Me X: 215
Feed Me Y: 480
Feed Me Z: 91
Not the same. AL = 0
Feed Me W: 0
Feed Me X: 0
Feed Me Y: 0
Feed Me Z: 0
Same. AL = 1
Feed Me W: 0
Feed Me X: 221
Feed Me Y: 100
Feed Me Z: 40
Not the same. AL = 0
**My output are almost correct but when I entered
w : 2
x : 2
y : 2
z : 1
"the same" instead of "NOT the same"
Please help with any thoughts that I might be missing.**
I am not sure if register push and pop are the issue.
program Same;
#include ("stdlib.hhf");
static
iDataValue1 : int16 := 0;
iDataValue2 : int16 := 0;
iDataValue3 : int16 := 0;
iDataValue4 : int16 := 0;
procedure theSame( w : int16; x : int16; y : int16; z : int16); #nodisplay; #noframe;
static
returnAddress : dword;
temp: int16;
begin theSame;
pop (returnAddress);
pop (temp);
pop (z);
pop (y);
pop (x);
pop (w);
push (returnAddress);
push (BX);
//Perform Subtask
mov (z, BX);
cmp (y, BX); // Compare z & y
jne ReturnZero;
mov (y, BX);
cmp (x, BX); // Compare y & x
je ReturnOne;
jmp ReturnZero;
mov (x, BX);
cmp (w, BX); // Compare x & w
je ReturnOne;
jmp ReturnZero;
ReturnOne:
mov (1, AL);
jmp ExitSequence;
ReturnZero:
mov (0, AL);
jmp ExitSequence;
ExitSequence:
pop (BX);
ret();
end theSame;
begin Same;
stdout.put ("Feed Me W: ");
stdin.get (iDataValue1);
stdout.put ("Feed Me X: ");
stdin.get (iDataValue2);
stdout.put ("Feed Me Y: ");
stdin.get (iDataValue3);
stdout.put ("Feed Me Z: ");
stdin.get (iDataValue4);
push (iDataValue1);
push (iDataValue2);
push (iDataValue3);
push (iDataValue4);
call theSame;
cmp (AL, 1);
je NumbersAreSame;
jmp NumbersAreDifferent;
NumbersAreSame:
stdout.put ("Same. AL = 1");
jmp EndProgram;
NumbersAreDifferent:
stdout.put ("Not the same. AL = 0");
stdout.newln();
jmp EndProgram;
EndProgram:
end Same;
ENVIRONMENT
HLA (High Level Assembler - HLABE back end, LD linker)
Version 2.16 build 4463 (prototype)
Ubuntu 20.10
SOLUTION
Five values are pushed to the stack when calling theSame(), those are the return address, w, x, y, and z. However in the prologue for theSame() six values are currently popped off of the stack.
begin theSame;
pop (returnAddress);
pop (temp);
pop (z);
pop (y);
pop (x);
pop (w);
The additional pop (temp); seen above causes the temp variable to store the value passed in for z, z to store the value passed in for y, y to store the value passed in for x, x to store the value passed in for w, and w to store the next random value on the stack. Removing the pop (temp); instruction will result in your example case passing.
Feed Me W: 2
Feed Me X: 2
Feed Me Y: 2
Feed Me Z: 1
Not the same. AL = 0
However the following case will still fail due to errors in the comparison logic.
Feed Me W: 1
Feed Me X: 2
Feed Me Y: 2
Feed Me Z: 2
Same. AL = 1
In the following code if z, y, and x are equal then the code will jump to ReturnOne with out checking the value of w. This is corrected by removing the first je ReturnOne; and changing the first jmp ReturnZero; to jne ReturnZero;.
mov (z, BX);
cmp (y, BX); // Compare z & y
jne ReturnZero;
mov (y, BX);
cmp (x, BX); // Compare y & x
je ReturnOne;
jmp ReturnZero;
mov (x, BX);
cmp (w, BX); // Compare x & w
je ReturnOne;
jmp ReturnZero;
EXAMPLE
program Same;
#include("stdlib.hhf");
procedure theSame(w: int16; x: int16; y: int16; z: int16); #nodisplay; #noframe;
begin theSame;
pop(EDX); // Return Address
pop(z);
pop(y);
pop(x);
pop(w);
push(EDX); // Return Address
mov(z, BX);
cmp(y, BX); // Compare z & y
jne ReturnZero;
mov(y, BX);
cmp(x, BX); // Compare y & x
jne ReturnZero;
mov(x, BX);
cmp(w, BX); // Compare x & w
jne ReturnZero;
mov(1, AL);
jmp ExitSequence;
ReturnZero:
mov(0, AL);
ExitSequence:
ret();
end theSame;
begin Same;
stdout.put("Feed Me W: ");
stdin.geti16();
push(AX);
stdout.put("Feed Me X: ");
stdin.geti16();
push(AX);
stdout.put("Feed Me Y: ");
stdin.geti16();
push(AX);
stdout.put("Feed Me Z: ");
stdin.geti16();
push(AX);
call theSame;
cmp(AL, 1);
jne NumbersAreDifferent;
stdout.put("Same. AL = 1");
jmp EndProgram;
NumbersAreDifferent:
stdout.put("Not the same. AL = 0");
EndProgram:
end Same;

MIPS offsets with variables

When I load a variable using 4-byte offset, how would I load that variable into an array?
For example... if I have the C assignment statement:
B[8] = A[i] + A[j]
lw $t0, 4j($s6) # load A[j] into $t0
lw $ti, 4i($s6) # load A[i] into $t1
add $t0, $t0, $t1 # Register $t0 gets A[i] + A[j]
sw $t0, 32($s7) # Stores A[i] + A[j] into B[8]
Would this be the correct way to do the offset for variable? The 4j and 4i part is where I'm really confused.
Edit: i and j have the registers $s3 and $s4, but I don't know how to use
You're pretty close, you just need to calculate the offsets:
li $s2, 4 # put constant 4 in s2
multu $s2, $s3 # multiply s3 by 4
mflo $s3 # put multiplication result back in s3
multu $s2, $s4 # multiply s4 by 4
mflo $s4 # put multiplication result back in s4
add $s4, $s6, $s4 # s4 = pointer to A[j]
add $s3, $s6, $s3 # s3 = pointer to A[i]
lw $t0, ($s4) # load A[j] into t0
lw $t1, ($s3) # load A[i] into t1
add $t0, $t0, $t1 # t0 = A[j] + A[i]
sw $t0, 32($s7) # B[8] = A[i] + A[j]
Assume $s0 stores i and $s1 stores j. Base address of A and B are $s6, $s7 respectively.
sll $t0, $s0, 2 #offsets 4*i
sll $t1, $s1, 2 #offsets 4*j
add $t0, $t0, $s6 #Pointer to A[i]
add $t1, $t1, $s6 #Pointer to A[j]
lw $t0, 0($t0) #loads A[i] to $t0
lw $t1, 0($t1) #loads A[j] to $t1
add $t2, $t1, $t0 #A[i]+A[j]
sw $t2, 32($s7) #stores A[i]+A[j] to B[8]
I don't think that is correct, in ASM language you don't have "variables" you must access a register which contains the i and j, you normaly have a pointer to base array, which seems to be $s6, and your offsets are missing, and its not calculated correctly, what you is use a temporary register to calculate the add $t2, $base, $offset, each in their own register, and then use (What 4i means is number which is 4*i, and 4j is a number which is 4*j, but cannot be inputted directly, as are variables, and are contained withing a register)
lw $ti, $t2
See what I mean? That asm is assuming you are doing i and j multiplication like
4*i and 4*j as offset, but offset can't be a register, so what you do is you add 4 (bytes) assuming each element in the array has size of 4 bytes. assuming the result of 4*i and 4*j are in $t4 and $t5 respectively:
add $t1, $s6, $t4
lw $t2, $t1
add $t1, $s6, $t5
lw $t3, $t1
add $t0, $t2, $t3
sw $t0, 32($s7)

Simple MIPS error relating to div, $HI, and a branch statement

I'm trying to replicate the following C code in MIPS:
//sum, n and added are integers and have already been initialized
if(n%3 == 0){
sum = sum + n;
added = added + 1;
}
Here is what I tried doing.
#Let t0 = n
#Let s0 = sum
#Let a0 = added
#All have been set earlier in the program
addi $t1, $zero, 3 #Let t1 = 3 for division
div $t0, $t1 #Remainder will be stored in $HI
bne $HI, $zero, ENDIF #skip to ENDIF when remainder != 0; same as if(n%3 == 0)
add $s0, $s0, $t0
addi $a0, $a0, 1
ENDIF:
When I run it in my MIPS simulator (I'm using QtSpim), I get a compiler error on the if statement. It reads:
bne $HI, $zero, ENDIF #skip to ENDIF when remainder != 0; same as if(n%3 == 0)
^
What is wrong with the statement, exactly? I can see that the ^ is under $HI. Is something wrong with my div statement, causing the error in $HI? Or can $HI not be used in a branch like that? Will I need to move $HI into a temporary register? Or is something wrong with the branch statement anyway?
Thanks for the help!
Yes, you need to move $HI into a register (MIPS branch instructions compare registers).
You can't access the HI register directly, use mfhi to get the value in it.
#Let t0 = n
#Let s0 = sum
#Let a0 = added
#All have been set earlier in the program
addi $t1, $zero, 3 #Let t1 = 3 for division
div $t0, $t1 #Remainder will be stored in $HI
mfhi $t2 #Store the value from $HI in $t0
bne $t2, $zero, ENDIF #skip to ENDIF when remainder != 0; same as if(n%3 == 0)
add $s0, $s0, $t0
addi $a0, $a0, 1
ENDIF:

How can I convert hex string to binary?

My problem is getting a 64-bit key from user. For this I need to get 16 characters as string which contains hexadecimal characters (123456789ABCDEF). I got the string from user and I reached characters with the code below. But I don't know how to convert character to 4-bit binary
.data
insert_into:
.word 8
Ask_Input:
.asciiz "Please Enter a Key which size is 16, and use hex characters : "
key_array:
.space 64
.text
.globl main
main:
la $a0, Ask_Input
li $v0, 4
syscall
la $a0, insert_into
la $a1, 64
li $v0, 8
syscall
la $t0, insert_into
li $t2, 0
li $t3, 0
loop_convert:
lb $t1, ($t0)
addi $t0, $t0, 1
beq $t1, 10, end_convert
# Now charcter is in $t1 but
#I dont know how to convert it to 4 bit binary and storing it
b loop_convert
end_convert:
li $v0, 10 # exit
syscall
I don't think masking with 0x15 as #Joelmob's opinion is the right solution, because
'A' = 0x41 → 0x41 & 0x15 = 0
'B' = 0x42 → 0x42 & 0x15 = 0
'C' = 0x43 → 0x43 & 0x15 = 1
'D' = 0x44 → 0x44 & 0x15 = 4
'E' = 0x45 → 0x45 & 0x15 = 5
'F' = 0x46 → 0x46 & 0x15 = 4
which doesn't produce any relevant binary values
The easiest way is subtracting the range's lower limit from the character value. I'll give the idea in C, you can easily convert it to MIPS asm
if ('0' <= ch && ch <= '9')
{
return ch - '0';
}
else if ('A' <= ch && ch <= 'F')
{
return ch - 'A' + 10;
}
else if ('a' <= ch && ch <= 'f')
{
return ch - 'a' + 10;
}
Another way to implement:
if ('0' <= ch && ch <= '9')
{
return ch & 0x0f;
}
else if (('A' <= ch && ch <= 'F') || ('a' <= ch && ch <= 'f'))
{
return (ch & 0x0f) + 9;
}
However this can be further optimized to a single comparison using the technique describes in the following questions
Fastest way to determine if an integer is between two integers (inclusive) with known sets of values
Check if number is in range on 8051
Now the checks can be rewritten as below
if ((unsigned char)(ch - '0') <= ('9'-'0'))
if ((unsigned char)(ch - 'A') <= ('F'-'A'))
if ((unsigned char)(ch - 'a') <= ('f'-'a'))
Any modern compilers can do this kind of optimization, here is an example output
hex2(unsigned char):
andi $4,$4,0x00ff # ch, ch
addiu $2,$4,-48 # tmp203, ch,
sltu $2,$2,10 # tmp204, tmp203,
bne $2,$0,$L13
nop
andi $2,$4,0xdf # tmp206, ch,
addiu $2,$2,-65 # tmp210, tmp206,
sltu $2,$2,6 # tmp211, tmp210,
beq $2,$0,$L12 #, tmp211,,
andi $4,$4,0xf # tmp212, ch,
j $31
addiu $2,$4,9 # D.2099, tmp212,
$L12:
j $31
li $2,255 # 0xff # D.2099,
$L13:
j $31
andi $2,$4,0xf # D.2099, ch,
Have a look at this ASCII table you will see that hex-code for numbers from 9 and below are 0x9 and for capital letters this is between 0x41 and 0x5A A-Z determine if its a number or character, you see if theres a number its quite done, if it were a character mask with 0x15 to get the four bits.
If you want to include lowercase letters do same procedure with masking and determine if its a char between 0x61 and 0x7A