MIPS offsets with variables - 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)

Related

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;

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

Why is this postscript calculator (type 4) shading so slow to render at high zoom?

In an effort to produce a smooth gradient to specifications, I have tried my hand at using type 4 (postscript calculator) shading, so that I can write the function that specifies the color at each point. Here is the function I produced, which accepts two real numbers (x and y coordinates on [0,1] x [0,1]) and returns three real numbers (the r, g, b components of the color):
2 copy 0.25 sub exch 0.25 sub exch dup mul exch dup mul add dup .0001 le {pop 10000.0} {1.0 exch div} ifelse
3 1 roll 2 copy 0.75 sub exch 0.75 sub exch dup mul exch dup mul add dup .0001 le {pop 10000.0} {1.0 exch div} ifelse
3 1 roll 2 copy 0.75 sub exch 0.25 sub exch dup mul exch dup mul add dup .0001 le {pop 10000.0} {1.0 exch div} ifelse
3 1 roll 0.25 sub exch 0.75 sub exch dup mul exch dup mul add dup .0001 le {pop 10000.0} {1.0 exch div} ifelse
4 copy 0.0 add add add add 1.0 exch div
dup 3 1 roll mul 5 1 roll
dup 3 1 roll mul 5 1 roll
dup 3 1 roll mul 5 1 roll
dup 3 1 roll mul 5 1 roll pop
4 copy 0.0 exch 0 mul add exch 1 mul add exch 0 mul add exch 1 mul add 5 1 roll
4 copy 0.0 exch 0 mul add exch 1 mul add exch 1 mul add exch 0 mul add 5 1 roll
0.0 exch 1 mul add exch 0 mul add exch 0 mul add exch 0 mul add
Here is the Asymptote code that produced the string above as well as the actual pdf file:
// input: a nonnegative real number r^2 (the square of the distance)
// output: min(1/r^2, 10000.0)
string ps_weight_rsquared = ' dup .0001 le {pop 10000.0} {1.0 exch div} ifelse';
// input: x and y coordinates of a vector
// output: x^2 + y^2
string ps_distsquared = ' dup mul exch dup mul add';
//input: x and y coordinates
//output: the weight at (x,y)
string ps_weight_displacement = ps_distsquared + ps_weight_rsquared;
//input: x, y
//output: weight at the vector ((x,y) - point)
string ps_naiveWeight_pair(pair point) {
// compute displacement:
string toreturn = ' ' + (string)point.y + ' sub exch ' + (string)point.x + ' sub exch' ;
// compute weight from displacement:
return toreturn + ps_weight_displacement;
}
/* The string will be an postscript calculator formula that accepts
* a pair and returns a list of naive weights, with the deepest weight
* on the stack corresponding to points[0].
*/
string ps_naiveWeights_pair(pair[] points) {
string toreturn = '';
for (int i = 0; i < points.length; ++i) {
if (i < points.length - 1)
toreturn += ' 2 copy';
toreturn += ps_naiveWeight_pair(points[i]);
if (i < points.length - 1)
toreturn += ' 3 1 roll';
}
return toreturn;
}
// input: x,y
// output: the weights of all the displacement vectors ((x,y) - points[i]), normalized so that their sum is one
string ps_partitionWeights_pair(pair[] points) {
string toreturn = ps_naiveWeights_pair(points);
// compute the sum of the all the naive weights:
toreturn += ' ' + (string)points.length + ' copy 0.0';
for (int i = 0; i < points.length; ++i)
toreturn += ' add';
// take the reciprocal of the sum:
toreturn += ' 1.0 exch div';
for (int i = 1; i <= points.length; ++i) {
// multiply a weight by the sum reciprocal and roll the new weight to the back:
toreturn += ' dup 3 1 roll mul ' + (string)(1+points.length) + ' 1 roll';
}
//discard the sum reciprocal, which is no longer needed:
toreturn += ' pop';
return toreturn;
}
// Assumes the weights are already on the stack, with the deepest weight
// corresponding to summands[0].
string ps_weighted_sum(real[] summands) {
// At each step, the top element of the stack should be the sum so far:
string toreturn = ' 0.0';
while(summands.length > 0) {
toreturn += ' exch ' + (string)(summands.pop()) + ' mul add';
}
return toreturn;
}
// input: real numbers x, y
// output: shading function based on a weighted sum of the colors, with the weight of the color of point p equal to 1/(dist to p)^2 (and the weights normalized to have sum one)
string ps_interpolate_shade(path g, pair[] points, pen[] pointcolors) {
pair min = min(g);
pair max = max(g);
real[] reds, greens, blues;
for (pen thecolor : pointcolors) {
real[] thecolors = colors(rgb(thecolor));
reds.push(thecolors[0]);
greens.push(thecolors[1]);
blues.push(thecolors[2]);
}
transform t = scale(1/(max.x - min.x), 1/(max.y - min.y)) * shift(-min);
points = t * points;
string toreturn = ps_partitionWeights_pair(points);
toreturn += ' ' + (string)points.length + ' copy';
toreturn += ps_weighted_sum(reds);
toreturn += ' ' + (string)(points.length + 1) + ' 1 roll';
toreturn += ' ' + (string)points.length + ' copy';
toreturn += ps_weighted_sum(greens);
toreturn += ' ' + (string)(points.length + 1) + ' 1 roll';
toreturn += ps_weighted_sum(blues);
return toreturn;
}
void applyInterpolateShade(path g, pair[] points, pen[] pointcolors) {
string shader = ps_interpolate_shade(g, points, pointcolors);
write(shader); //output the ps string to the terminal
functionshade(g, fillrule=rgb(zerowinding), shader=shader);
}
/********************************************/
settings.tex = "pdflatex";
size(5cm);
applyInterpolateShade(unitcircle, new pair[] {(-.5,-.5), (.5,.5), (-.5,.5), (.5,-.5)}, new pen[] {red, green, yellow, blue});
And here is the output, converted to a png file:
It's pretty much what I had in mind.
The problem: If I open the pdf file (using either Apple Previewer or Adobe Reader) and zoom in, the rendering program slows to a crawl and (according to Activity Monitor) uses 100% of the CPU (from one core; fortunately I have other cores, so other applications keep responding). Am I doing something in the postscript function that is too computationally intensive? If so, am I using bugs or bad coding practices (memory leakage, too many rolls,...) or is it simply an inevitable consequence of the algorithm I am using (e.g., can the renderer not handle five divisions per pixel)?
Either way, why does this only show up when I zoom in? Is the renderer trying to render the whole zoomed-in image internally in case I scroll around?
You don't say which pdf viewer you are using, but different viewers will be optimised very differently.
Shadings are designed to be interpolated, i.e. selected coordinates within the shading should be evaluated using your PS evaluator function. The vast majority of the pixels between these should be linearly interpolated. The selection of the evaluated coordinates depends on the current smoothness. In PDF that is selected using the SM entry of an ExtGState dictionary. The shading area will be decomposed until small regions are detected as being "smooth" relative to the SM value. You could try changing SM; the default in Acrobat is 0.02, but YMMV.
If your shading is taking a long time a few things could be happening. The function could be highly non-linear; exponential functions and functions with a sharp edge can prevent the detection of linearity until the regions become very small, possibly as small as 1 pixel. Alternatively, your pdf viewer just isn't optimised for shading. Or quite possibly both of these. FWIW. I can't say if this PS calculator function is a bad fit for decomposition because I can't tell what it's doing.

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