I have a piece of code in MIPS I am failing to understand. Namely the register convention using the "read" linux syscall:
...
move a0,zero #a0 = 0
move a1,s0 #a1 = some adress in memory
li v0,4003 #v0 = 4003 = SYSCALL READ
syscall
bnez a3, label #What is in a3??
li v1,1
bne v0,v1
...
Now I get understand it as
char buffer;
int v0 = read(0, &buffer, 1);
????
What I do not get at all is what is the meaning of reg a3 in this context? v0 is the return value of read, but a3 should be parameter and not ret value. Is it errno?
It's a boolean indicating whether or not there was an error:
On a few architectures, a register is used as a boolean (0
indicating no error, and -1 indicating an error) to signal
that the system call failed.
Arch/ABI Instruction System Ret Ret Error
call # val val2
-------------------------------------------------------------
mips syscall v0 v0 v1 a3
source
I am writing a palindrome checker in MIPS, and I was trying to make it accent insensitive so that something like "ahà" would be considered a palindrome too. However, it doesn't look so simple as the case insensitive scenario where there is a fixed value between a lowercase and an uppercase letter.
I asked my teacher about it and she said that I could check the entire string and replace any "è" with "e", then check it again to replace any "é" with "e" and so on, but she told me there is a better solution and asked me to think about it.
The only thing I have noticed so far is that the accents are in the extended ASCII code, so > 127, but I can't seem to understand what to do. Can someone help me? Even just a hint would be appreciated, thank you in advance.
You're going to have to hardcode this one with a lookup table like Alain Merigot suggested. How you do this depends on your string encoding scheme (ASCII vs. UTF-8, etc.)
For ASCII, I whipped this up and it should work:
.data
ascii_strip_accent_table:
# index: U+nnnn offset, minus 128
.space 0x40 ;table doesn't really start until U+00C0
.ascii "AAAAA"
.byte 0xC6
.ascii "C"
.ascii "EEEE"
.ascii "IIII"
.ascii "D"
.ascii "N"
.ascii "OOOOO" ;these are capital Os, not zeroes
.byte 0xD7
.ascii "O" ;this is a capital O, not a zero
.ascii "UUUU"
.ascii "Y"
.byte 0xDE,0xDF
.ascii "aaaaa"
.byte 0xE6
.ascii "c"
.ascii "eeee"
.ascii "iiii"
.ascii "d"
.ascii "n"
.ascii "ooooo"
.byte 0xF7
.ascii "o"
.ascii "uuuu"
.ascii "y"
.byte 0xFE
.ascii "y"
MyString:
.asciiz "Pokémon"
.text
la $a0,ascii_strip_accent_table
la $a1,MyString
li $t2,128
loop:
lbu $t0,($a1) # read from string
beqz $t0,done
bltu $t0,$t2,continue # if char < 128, skip
subu $t0,$t0,$t2 # subtract 128 to get array index
move $a2,$a0 # backup table base
addu $a2,$a2,$t0 # add array index to table base
lbu $t0,($a2) # load from table
sb $t0,($a1) # store in string
continue:
addiu $a0,$a0,1
j loop
done:
li $v0,10
syscall
EDIT: Now if you're like me and you can't stand unnecessary padding, you can actually remove that .space 40 at the beginning if you la $a0,ascii_strip_accent_table-64 instead. Whether you're willing to take that risk, is up to you.
I need to extract the value in bits 22 down to 4 from register $t0, compute the half of this value (assumed unsigned integer), and use the new value to replace bits 24 down to 6 in register $t1 without changing the others bits in $t1. The value isn't given but I don't think that should be an issue. There are 32 bits per register
I'm a bit new to MIPs so I'm not sure how to go about solving this problem
I've broken down the invidual steps of the algorithm. I then created a C prototype/test program. And, finally, I created a mips asm program.
Those are the steps I would recommend for you [or anybody else], particularly when getting started.
Writing the code in C first [or at least prototyping it in C-like pseudo code], makes debugging of the algorithm easier.
From the C program, I was able to create test data for the mips program. The test data includes the solution that the C program got.
The mips program would treat this as a pass/fail diagnostic. This might seem like overkill, but in the first version of the asm program, there was a bug. I had used a wrong register in the srlv instruction's third argument and the diagnostic actually failed the tests (e.g. I used $t0 instead of $t1).
Terminology:
This is the matchup of the terms:
xval: $t0
xhi: 22
xlo: 4
yval: $t1
yhi: 24
ylo: 6
Extract step (1):
Given a value xval, whenever you see "extract bits xhi to xlo", the first thing to do is right shift xval by xlo:
xshf = xval >> xlo
But now, xshf still has the bits that were to the left of xhi, so we need to mask them.
Formulas:
The bit width of an "inclusive" bit range is:
wid = (hi - lo) + 1
So, the "right justified" mask is:
rmsk = (0xFFFFFFFF >> (32 - wid))
The "left justified" mask is:
lmsk = (rmsk << lo)
Note: The above equations work dynamically [as above]. Or, if we have fixed numbers, we can calculate the final values by hand to produce constants.
Extract step (2):
So, to get the isolated value for the bit range, we now apply the mask:
xshf &= xrmsk
This is the first part of the problem. We've isolated the necessary bits, so they are now in the rightmost bits of xshf (i.e. bits (xwid-1) to 0).
Extract step (3):
The above was for general bit extraction. The specific problem requires that we divide by 2:
xshf >>= 1
Merge step (1):
The second part of the problem is that we have to apply the xshf to the target value yval.
yval has a different range: yhi to ylo. We apply the formulas to get the appropriate values for yval.
We must clear out the old bits in yval:
yval &= ~ylmsk
Merge step (2):
We need to do two things to xshf:
"clean up" xshf so that only the correct bits in yval get modified
Shift xshf into the correct position for merging with yval
We can accomplish this in one of two ways. The following two sequences are equivalent:
xshf &= yrmsk
xshf <<= ylo
Or:
xshf <<= ylo
xshf &= ylmsk
Note: Because the bit widths in the specific problem are the same, the masking step can be eliminated (i.e. xshf had already been masked by xrmsk and it is the same as yrmsk. So, either masking step is not required).
Merge step (3):
Now, we merge in the shifted value:
yval |= xshf
That's it--we're done ...
Prototype:
Here's some C code that combines all this.
Because the bit range values are fixed, the mask values are precalculated once. If they had to vary, the mask code would have to recalculate them on each merge call.
Also note that the masks are constants because the ranges are fixed.
#include <stdio.h>
#include <stdlib.h>
int opt_v;
typedef unsigned int u32;
u32 xval;
#define XHI 22
#define XLO 4
u32 yval;
#define YHI 24
#define YLO 6
u32 xrmsk;
u32 xlmsk;
u32 yrmsk;
u32 ylmsk;
#define WID(_hi,_lo) (((_hi) - (_lo)) + 1)
#define RMSK(_hi,_lo) (0xFFFFFFFF >> (32 - WID(_hi,_lo)))
#define LMSK(_hi,_lo) (RMSK(_hi,_lo) << (_lo))
#define SHOW(_sym) \
show(_sym,#_sym)
#define SHOWX(_sym) \
if (opt_v) \
SHOW(_sym)
void
show(u32 val,const char *sym)
{
u32 bitmsk;
u32 bitval;
printf("%8.8X ",val);
for (bitmsk = 1u << 31; bitmsk != 0; bitmsk >>= 1) {
bitval = val & bitmsk;
printf("%d",bitval ? 1 : 0);
}
printf(" %s\n",sym);
}
void
merge(void)
{
u32 xshf;
SHOW(xval);
SHOW(yval);
// extract (1):
xshf = xval >> XLO;
SHOW(xshf);
// extract (2):
SHOWX(xrmsk);
xshf &= xrmsk;
SHOW(xshf);
// extract (3):
xshf >>= 1;
SHOW(xshf);
// merge (1):
SHOWX(yrmsk);
SHOWX(ylmsk);
yval &= ~ylmsk;
SHOW(yval);
// merge (2):
xshf &= yrmsk; // belt and ...
SHOW(xshf);
xshf <<= YLO;
SHOW(xshf);
xshf &= ylmsk; // ... suspenders
SHOW(xshf);
// merge (3)
yval |= xshf;
SHOW(yval);
}
void
test(u32 y,u32 x)
{
printf("\n");
yval = y;
xval = x;
merge();
}
// main -- main program
int
main(int argc,char **argv)
{
char *cp;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'v':
opt_v = ! opt_v;
break;
default:
break;
}
}
xrmsk = RMSK(XHI,XLO);
SHOW(xrmsk);
xlmsk = LMSK(XHI,XLO);
SHOW(xlmsk);
yrmsk = RMSK(YHI,YLO);
SHOW(yrmsk);
ylmsk = LMSK(YHI,YLO);
SHOW(ylmsk);
test(0,~0);
test(~0,0);
for (int idx = 0; idx <= 5; ++idx)
test(rand(),rand());
return 0;
}
Output:
0007FFFF 00000000000001111111111111111111 xrmsk
007FFFF0 00000000011111111111111111110000 xlmsk
0007FFFF 00000000000001111111111111111111 yrmsk
01FFFFC0 00000001111111111111111111000000 ylmsk
FFFFFFFF 11111111111111111111111111111111 xval
00000000 00000000000000000000000000000000 yval
0FFFFFFF 00001111111111111111111111111111 xshf
0007FFFF 00000000000001111111111111111111 xshf
0003FFFF 00000000000000111111111111111111 xshf
00000000 00000000000000000000000000000000 yval
0003FFFF 00000000000000111111111111111111 xshf
00FFFFC0 00000000111111111111111111000000 xshf
00FFFFC0 00000000111111111111111111000000 xshf
00FFFFC0 00000000111111111111111111000000 yval
00000000 00000000000000000000000000000000 xval
FFFFFFFF 11111111111111111111111111111111 yval
00000000 00000000000000000000000000000000 xshf
00000000 00000000000000000000000000000000 xshf
00000000 00000000000000000000000000000000 xshf
FE00003F 11111110000000000000000000111111 yval
00000000 00000000000000000000000000000000 xshf
00000000 00000000000000000000000000000000 xshf
00000000 00000000000000000000000000000000 xshf
FE00003F 11111110000000000000000000111111 yval
6B8B4567 01101011100010110100010101100111 xval
327B23C6 00110010011110110010001111000110 yval
06B8B456 00000110101110001011010001010110 xshf
0000B456 00000000000000001011010001010110 xshf
00005A2B 00000000000000000101101000101011 xshf
32000006 00110010000000000000000000000110 yval
00005A2B 00000000000000000101101000101011 xshf
00168AC0 00000000000101101000101011000000 xshf
00168AC0 00000000000101101000101011000000 xshf
32168AC6 00110010000101101000101011000110 yval
643C9869 01100100001111001001100001101001 xval
66334873 01100110001100110100100001110011 yval
0643C986 00000110010000111100100110000110 xshf
0003C986 00000000000000111100100110000110 xshf
0001E4C3 00000000000000011110010011000011 xshf
66000033 01100110000000000000000000110011 yval
0001E4C3 00000000000000011110010011000011 xshf
007930C0 00000000011110010011000011000000 xshf
007930C0 00000000011110010011000011000000 xshf
667930F3 01100110011110010011000011110011 yval
74B0DC51 01110100101100001101110001010001 xval
19495CFF 00011001010010010101110011111111 yval
074B0DC5 00000111010010110000110111000101 xshf
00030DC5 00000000000000110000110111000101 xshf
000186E2 00000000000000011000011011100010 xshf
1800003F 00011000000000000000000000111111 yval
000186E2 00000000000000011000011011100010 xshf
0061B880 00000000011000011011100010000000 xshf
0061B880 00000000011000011011100010000000 xshf
1861B8BF 00011000011000011011100010111111 yval
2AE8944A 00101010111010001001010001001010 xval
625558EC 01100010010101010101100011101100 yval
02AE8944 00000010101011101000100101000100 xshf
00068944 00000000000001101000100101000100 xshf
000344A2 00000000000000110100010010100010 xshf
6200002C 01100010000000000000000000101100 yval
000344A2 00000000000000110100010010100010 xshf
00D12880 00000000110100010010100010000000 xshf
00D12880 00000000110100010010100010000000 xshf
62D128AC 01100010110100010010100010101100 yval
238E1F29 00100011100011100001111100101001 xval
46E87CCD 01000110111010000111110011001101 yval
0238E1F2 00000010001110001110000111110010 xshf
0000E1F2 00000000000000001110000111110010 xshf
000070F9 00000000000000000111000011111001 xshf
4600000D 01000110000000000000000000001101 yval
000070F9 00000000000000000111000011111001 xshf
001C3E40 00000000000111000011111001000000 xshf
001C3E40 00000000000111000011111001000000 xshf
461C3E4D 01000110000111000011111001001101 yval
3D1B58BA 00111101000110110101100010111010 xval
507ED7AB 01010000011111101101011110101011 yval
03D1B58B 00000011110100011011010110001011 xshf
0001B58B 00000000000000011011010110001011 xshf
0000DAC5 00000000000000001101101011000101 xshf
5000002B 01010000000000000000000000101011 yval
0000DAC5 00000000000000001101101011000101 xshf
0036B140 00000000001101101011000101000000 xshf
0036B140 00000000001101101011000101000000 xshf
5036B16B 01010000001101101011000101101011 yval
MIPS program:
This is set up for the mars simulator. In particular, the syscall 34 to print a value in hex only exists in mars and not in spim. So, either get mars: http://courses.missouristate.edu/KenVollmar/mars/ or [using spim] change the 34 to 1 to print in decimal
# these work for the mars simulator
.eqv XHI 22
.eqv XLO 4
.eqv YHI 24
.eqv YLO 6
# these work for the spim simulator
###XHI = 22
###XLO = 4
###YHI = 24
###YLO = 6
.data
testdata:
.word 0xFFFFFFFF,0x00000000,0x00FFFFC0
.word 0x00000000,0xFFFFFFFF,0xFE00003F
.word 0x6B8B4567,0x327B23C6,0x32168AC6
.word 0x643C9869,0x66334873,0x667930F3
.word 0x74B0DC51,0x19495CFF,0x1861B8BF
.word 0x2AE8944A,0x625558EC,0x62D128AC
.word 0x238E1F29,0x46E87CCD,0x461C3E4D
.word 0x3D1B58BA,0x507ED7AB,0x5036B16B
edata:
msg_nl: .asciiz "\n"
msg_xrmsk: .asciiz "xrmsk "
msg_xlmsk: .asciiz "xlmsk "
msg_yrmsk: .asciiz "yrmsk "
msg_ylmsk: .asciiz "ylmsk "
msg_xval: .asciiz "xval "
msg_yval: .asciiz "yval "
msg_pass: .asciiz "pass "
msg_fail: .asciiz "FAIL "
msg_ans: .asciiz "answ "
.text
.globl main
main:
jal setup2
la $s6,testdata
la $s7,edata
main_loop:
jal test
addiu $s6,$s6,12
blt $s6,$s7,main_loop
li $v0,10
syscall
# test -- test the merge
test:
subu $sp,$sp,4
sw $ra,0($sp)
li $v0,4
la $a0,msg_nl
syscall
lw $t0,0($s6) # get source value
lw $t1,4($s6) # get destination value
lw $t2,8($s6) # get solution value
# print the X value
la $a0,msg_xval
move $a1,$t0
jal print
# print the Y value
la $a0,msg_yval
move $a1,$t1
jal print
# do the operation
jal merge
bne $t1,$t2,test_fail
la $a0,msg_pass
move $a1,$t1
jal print
j test_done
test_fail:
la $a0,msg_fail
move $a1,$t1
jal print
# print the result
la $a0,msg_ans
move $a1,$t2
jal print
test_done:
lw $ra,0($sp)
addu $sp,$sp,4
jr $ra
# print -- print number
#
# arguments:
# a0 -- string
# a1 -- value
print:
# output the string
li $v0,4
syscall
li $v0,34 # syscall print hex
move $a0,$a1
syscall
li $v0,4
la $a0,msg_nl
syscall
jr $ra
# merge -- merge the data
#
# arguments:
# t0 -- source value
# t1 -- target value
#
# registers:
# t7 -- xshf
# t6 -- ~ylmsk
merge:
srl $t7,$t0,XLO # E1: xshf = xval >> xlo
and $t7,$t7,$s0 # E2: xshf &= xrmsk
srl $t7,$t7,1 # E3: xshf >>= 1
not $t6,$s3 # M1: get ~ylmsk
and $t1,$t1,$t6 # M1: yval &= ~ylmsk
sll $t7,$t7,YLO # M2: xshf <<= ylo
and $t7,$t7,$s3 # M2: xshf &= ylmsk
or $t1,$t1,$t7 # M3: yval |= xshf
jr $ra # return
# setup2 -- set up the mask values
#
# RETURNS:
# s0 -- xrmsk
# s1 -- xlmsk
# s2 -- yrmsk
# s3 -- ylmsk
#
# registers:
# a0 -- hi bit value
# a1 -- lo bit value
setup2:
subu $sp,$sp,4
sw $ra,0($sp)
# set up the xval masks
li $a0,XHI
li $a1,XLO
jal setup1
move $s0,$v0
move $s1,$v1
la $a0,msg_xrmsk
move $a1,$s0
jal print
la $a0,msg_xlmsk
move $a1,$s1
jal print
# set up the yval masks
li $a0,YHI
li $a1,YLO
jal setup1
move $s2,$v0
move $s3,$v1
la $a0,msg_yrmsk
move $a1,$s2
jal print
la $a0,msg_ylmsk
move $a1,$s3
jal print
lw $ra,0($sp)
addu $sp,$sp,4
jr $ra # return
# setup1 -- set up the mask values
#
# RETURNS:
# v0 -- rmsk
# v1 -- lmsk
#
# arguments:
# a0 -- hi bit value
# a1 -- lo bit value
#
# registers:
# t0 -- wid
# t1 -- 32 - wid
setup1:
sub $t0,$a0,$a1 # wid = hi - lo
addi $t0,$t0,1 # wid += 1
li $v0,0xFFFFFFFF # rmsk = 0xFFFFFFFF
# get 32 - wid
li $t1,32
sub $t1,$t1,$t0
srlv $v0,$v0,$t1 # rmsk >>= (32 - wid)
sllv $v1,$v0,$a1 # lmsk = rmsk << lo
jr $ra # return
I need to build a program (hard-code) in MIPS that gets an array of 10 integers and finds the difference between two nearby numbers in the array. This is what I have build:
.data
array: .word 23,-2,45,67,89,12,-100,0,120,6
arrend:
comma: .asciiz ", "
# array = {23,-2,45,67,89,12,-100,0,120,6}
# Algorithm being implemented to find the difference between nearby elements of the array
# difference = 0 (use $t0 for difference)
# loop i = 0 to length-1 do (use $t1 for i)
# difference = array[i]-array[i+1]
# end loop (use $t3 for base addr. of array)
# registers:
# t0 -- difference
#
# t3 -- pointer to current array element (e.g. arrptr)
# t2 -- pointer to end of array
#
# t4 -- current value fetched from array (i)
# t5 -- value fetched from array (i+1)
.text
main:
li $t0,0 # difference = 0
la $t3,array # load base addr. of array
la $t2,arrend # load address of array end
j test
loop:
lw $t4,0($t3) # load array[i]
addi $t3,$t3,4 # increment array pointer
lw $t5,0($t3) # load array[i+1]
sub $t0, $t4, $t5 # the difference of two nearby elements
# print value of difference
li $v0,1
addi $a0,$t0,0
syscall
# print comma
li $v0,4
la $a0,comma
syscall
test:
blt $t3,$t2,loop # more to do? if yes, loop
the output should be :
25, -47, -22, -22, 77, 112, -100, -120, 114,
but I get the output 25, -47, -22, -22, 77, 112, -100, -120, 114, -8230,
I found out if I change la $t2,arrend to la $t2,0x10010024, it will work, but I don't know how to write it in the code.
furthermore, how can I improve my code?
Ok... So, you are iterating one more time then you need... Just sub 1 from t2 right after you assign the end pointer of the array.
It's also called bufferoverflow.
I am trying to store a integer that i am reading from the user into a array, however when i try to store it into my array my data becomes unaligned.
This first block of code is where i initialize all the data. (Under the 1. is where i am trying to store the integer )
'#Constants
P_INT = 1 #Syscall to print integer(value)
P_STRING = 4 #Syscall to print a string(addr)
P_CHAR = 11 #Syscall to print a char(char)
R_INT = 5 #Syscall to read a integer(none)
EXIT = 10 #Exit program(none)
'#Data
.data
newline:
.asciiz "\n"
'#Space for the bored.
1.
board_rep:
.space 578
'#The current node to be read in
cur_node:
.word 0
'#Size of the bored
size:
.space 4
'#Plus sign
plus:
.asciiz "+"
'#dash
dash:
.asciiz "-"
Right here is where it becomes unaligned (the sw right after 2.) . The strange thing is that i am doing the exact same thing later (in the third code block) except that i am storing it in the size array.
'#Grabs user input for the bored and stores it
get_board_rep:
li $v0,R_INT '#Read next node and store it
syscall
2.
sw $v0,0($s1)
addi $s1,$s1,4 ' #Increment next node addr
lw $a0,0($s1)
j prnt_node
At the store word (under the 3. ) it stores the read in integer fine.
la $s0, size ' #Store the variable addr's
la $s1, board_rep
li $v0,R_INT ' #Get user input(size of bored)
syscall
3.
sw $v0,0($s0) ' #Store the size of bored
jal get_board_rep
I thought maybe the array was too large but i changed it to 4 (the same size that the other array that worked). But it still was unaligned.
Thanks in advance . This is a project and i know some people don't like helping with stuff like this. But i have done my homework and i cannot find a answer anywhere.
That doesn't look aligned to me, and if i'm wrong try explicitly aligning it anyway.