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

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:

Related

Is this an issue with pre-solve or how AMPL uses arrays?

I am modeling a production problem in AMPL with start and end inventories to be zero.
Simple 3 products being produced over 4 day span, on a single machine.
however my model keeps having problems with the bigM constraint and no inventory is allocated.Model is infeasible per AMPL presolve.
I would really appreciate if someone could point whats wrong or what i should try. Thanks in advance!
HERE IS THE CODE -
param n;
param m;
param M;
param T;
set I := {1..n};
set J := {1..m};
param r {I} integer; #productionrate
param stp {I} integer; #setuptime
param rev {I} integer; #sellingprice
param h {I} integer; #inventorycost
param d {I,J} integer; #demand
var t {I,J} integer >= 0, <=480 default 50; #production time allocated for product i on day j
var s {I,J} integer >= 0 default 50; #inventory of product i on day j
var z {I,J} binary default 1; #setup for product i done on day j or not
#sum of revenue - sum of inventory cost
maximize K: sum {i in I,j in J}(rev[i] * t[i,j] * r[i] * z[i,j]) - sum {i in I,j in J}(h[i] * s[i,j]);
#inventory equation
s.t. c2 {i in I,j in 2..4}: s[i,j] = s[i,j-1] + t[i,j]*r[i] - d[i,j];
s.t. c14 {i in I}: s[i,1] = t[i,1]*r[i] - d[i,1];
#initial and end inventories
s.t. c3 {i in I}: s[i,1] = 0;
s.t. c4 {i in I}: s[i,4] = 0;
#ensuring time allocation only when setup
s.t. c5 {i in I,j in J}: t[i,j] <= M*z[i,j];
#ensuring demand is satisfied
s.t. c6 {i in I,j in 2..4}: s[i,j-1] + t[i,j]*r[i] = d[i,j];
s.t. c11 {i in I}: t[i,1]*r[i] = d[i,1];
#production time constraint
s.t. c7 {j in J}: sum{i in I}(z[i,j]*stp[i]) + sum{i in I}(t[i,j]) <= T;
#other non-negativity constraints
s.t. c12 {i in I,j in J}: s[i,j] >= 0;
#s.t. c13 {i in I,j in J}: t[i,j] >= 0;
end;
HERE IS THE DATA -
param n :=3;
param m :=4;
param T :=480;
param M :=480;
#param o :=2;
param d: 1 2 3 4 :=
1 400 600 200 800
2 240 440 100 660
3 80 120 40 100;
param r:=
1 5
2 4
3 2;
param stp:=
1 45
2 60
3 100;
param rev:=
1 50
2 70
3 120;
param h:=
1 2
2 1
3 3;
end;
RUN FILE -
#RESET THE AMPL ENVIROMENT
reset;
#LOAD THE MODEL
model 'EDX 15.053 Production problem.mod';
#LOAD THE DATA
data 'EDX 15.053 Production problem.dat';
#DISPLAY THE PROBLEM FORMULATION
expand K;
expand c2;
#expand c3;
expand c4;
expand c5;
expand c6;
expand c7;
expand c11;
#let s[3,3] := 20;
#CHANGE THE SOLVER (optional)
#option solver CBC;
option solver cplex, cplex_options ’presolve 0’;
option show_stats 1;
option send_statuses 0;
#option presolve 0;
#SOLVE
solve;
print {j in 1.._nvars:_var[j].status = "pre"}: _varname[j];
print {i in 1.._ncons:_con[i].status = "pre"}: _conname[i];
display solve_message;
display solve_result_num, solve_result;
#SHOW RESULTS
display t,s,z,K;
end;

AHDL dff resets to it default value

I'm doing variable frequency clock on AHDL. Algoritm is: one counter (trigger) counts from 0 to x, and when it reaches x - we have pulse. I have another trigger which is used to store that X. Also I have two inputs plus and minus which are used to change frequency (increase or decrease X value).
And I have following code:
constant maximum = 9;
constant minimum = 1;
constant default = 5;
subdesign generator(
plus, minus, clk: input;
pulse, level[3..0], curr_val[3..0]: output;
)
variable
level[3..0]: dff;
curr_val[3..0]: dff;
begin
defaults
level[].d = default; % load 5 as default X value %
end defaults;
level[].clk = clk;
curr_val[].clk = clk;
pulse = (curr_val[] == level[]); % if main counter reached X - send one pulsation %
% main counter %
if curr_val[] < level[] then
curr_val[] = curr_val[] + 1;
elsif curr_val[] == level[] then
curr_val[] = 0;
end if;
% buttons %
if plus then
if (level[].q > minimum) then % if X == maximum ignore button %
level[].d = level[].q - 1;
end if;
end if;
if minus then
if (level[].q < maximum) then
level[].d = level[].q + 1;
end if;
end if;
end;
The problem is - after one tick when I change X (level[]) value - it goes back to default value. Am I missing something?
Syntax highlighting is wrong since wrong tag. % text % is commentary.
Found the problem.
The defaults block works everytime if value was not set. So, if you want to store same value you should set it at every time.

How to use bne in mips?

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

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)

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