Search This Blog

Disclosure

Everything Tech Review is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to products on Amazon.com. Amazon and the Amazon logo are trademarks of Amazon.com, Inc, or its affiliates.

Sunday, July 3, 2022

MIPS and the Little Endians - Tips and an FAQ to help ace your computer architecture class and have fun doing so!

Cool tricks I found in the MIPS architecture and the MARS Simulator! Here are some tips and tricks to learning and coding in MIPS and with the MARS Simulator, most if not all these commands and tricks will also work in other IDEs. In addition, I have added other useful computer architecture formulas and information. 

Last updated: 7/5/2022

First, make sure to read this post before proceeding... once you finish, come back here and enjoy!

Q: Is MIPS little or big endian? What does that mean?
And what about the MARS Simulator?

A: According to the Patterson and Hennessey book (Computer Organization and Design: the Hardware/Software Interface), 

On page 70 :

MIPS is in the big endian camp. Since the order matters only if you access the identical data both as a word and as four bytes, few need to be aware of the endianness.

Newer versions of the MIPS chip can support both big and little endian (bi-endian?), unlike the previous versions. Nonetheless, MIPS is classically referred to as big endian. 

As for the MARS simulator, It is considered little-endian. 

How to check: You can test this, in the data segment (`.data`)  write:

    .data

    store: .byte 0,0,0,1 #load 4 entries, each a byte long

    store2: .byte 2,0,0,0 #I loaded a 2 here to avoid confusion. 

and when you proceed to assemble the code, you can see how they are stored in the data segment. Pay attention to the Value+0 (0x01000000) and Value+4 (0x00000002) 

MIPS Data Segment


Q: What are syscalls and how can I use them? 
A: syscalls are a way to have the program interact with the user, it can print to the console, dialog box, and MARS can even play music with it (MIDI). In MARS, you can click Help -> Help -> and click on the syscall tab or you can view the web-version here

Q: How do I learn all the commands by-heart? 
A: Start with the MIPS Green Sheet which has a concise version of most if not all the commands. 

Q: The not command is a pseudo command and we cannot use it in class, how do I execute the not command without pseudocode?

A: You can use the nor command which is not pseudo... this will invert the bits! 
nor $t0, $t0, $zero
$t0 is the register you want to invert, you can also elect to save the result elsewhere by changing the left-most register name. 

Q: I want to initialize an array with all zeros or another value, what's the easiest way to do this? 
A: This works well and doesn't even require running a loop! 

arr1: .word 0:1000 #space for 1000 words/numbers 
arr2: .word 6:1000 #all initialized to 6

Now look at your data segment tab to be amazed! A 1000 sixes!!

0x00000006 

Q: How do I make use of a switch-case statement in MIPS? 
A: In assembly, we like to use what we call a JumpTable which stores the addresses of the relevant labels (AKA case names). 
I have some sample code here

Q: How do I know if the code I'm using contains pseudo-instructions?
A: On MARS, it is quite easy to detect. Click Settings->Uncheck permit extended instructions. 

On MARS, it is quite easy to detect. Click Settings->Uncheck permit extended instructions

Now, try to assemble your code.. if it assembles properly ... then you aren't using any pseudo instructions. Otherwise, it will show you which lines contain those codes... and then you can proceed to check them

In my case I was using 3 pseudo-instructions: 

la $t0, store #loads array address into memory (pointer to first element)

li $t1, 0 #count, loads immediate value
lb $t2, store($t1) #LB is a valid instruction but only in some contexts, this one swaps the label with the offset so that is why it's a pseudo variant, 

pseudo-code in mips
pseudo-code in mips

You can save time by clicking on each error in the console, and it will take you to the correct line! When you are done, try assembling again and it should work! Also you can shut off the setting we mentioned earlier whenever you want!

Alternatively, this also works... Assemble your program and then you can see what happens in the text segment on MARS.

Alternatively, this also works... Assemble your program and then you can see what happens in the text segment on MARS.

If a command takes more than one instruction to work, it is definitely a pseduo-instruction!

Q: If I want to start my data and/or text segment at a specific address (offset) how can I? 
A: MARS and SMIP allow you to do this! 

next to your .data, you can enter an address in HEX, note that it needs to be valid and in the range of the data segment... otherwise it won't assemble

.data 0x0fffa000 

You can do something similar for your .text segment, note where the data segment ends and text segment begins! Now you can fill the data segment as usual (and align if necessary), then view where the bytes and bits are loaded!

Q: Why can't I have a branch command check an immediate value as a condition such as: BEQ $t1, 5, label. Alternatively, you can ask why is the above line of code pseudo, and not actually part of the MIPS chip...

A:  Great question; Branch is an I type command, that means that it compares registers RS and RT, and the following 16 bit immediate value is the label to branch to on success. 
The two register values are each 5 bits which reference the spot in the register (2^5) with the value to compare. Frankly, we wouldn't have space in the instruction to fit in an immediate value instead of 1 of the registers. Even more so, we wouldn't have space to compare two immediate values and then jump conditionally. Recall that each instruction is 32 bits long. 

If we wanted to compare a value in a reg

The solution to your problem and how MARS translates the pseudo-instruction above is that it gets split up to 2 (if not 3 different instructions). First, the immediate value gets loaded into a register (usually a temporary one)... then the BEQ compares that temporary register to the one that was in the original command and proceeds normally. 

Q: What if you want to compare the current value to 0 in a BEQ/BNE command? 
A: This often is used as a conditional statement inside a loop, so MIPS Engineers decided to make $0 or $zero (interchangeable) into the zero-th register with the constant value of 0... you can't/shouldn't change it as it's hardcoded into the system. If you were able to change the value of the zero-th register it would screw up your code if not others'... as it is a known convention that $0 = 0... Imagine what would happen if we changed it to 1 or 2 perhaps... it would have a butterfly effect and mess up things that we wouldn't even have expected. 

So in short, you can use BEQ $t0, $0, label or BNE $zero, $t0, label,  etc. The order of registers doesn't really matter to the programmer... as long as it fits the general framework of COMMAND RS RT IMMEDIATE... 

Q: Can I refer to other registers via their "index"/number rather than their names? 
A: While in practice you can use registers like that such as $1, $2, etc... but it isn't good convention... and will annoy your professors. MIPS designated the registers with names (cannot be changed). 

NumberNameComments
$0$zeroAlways zero
$1$atReserved for assembler
$2, $3$v0, $v1First and second return values, respectively
$4, ..., $7$a0, ..., $a3First four arguments to functions
$8, ..., $15$t0, ..., $t7Temporary registers
$16, ..., $23$s0, ..., $s7Saved registers
$24, $25$t8, $t9More temporary registers
$26, $27$k0, $k1Reserved for kernel (operating system)
$28$gpGlobal pointer
$29$spStack pointer
$30$fpFrame pointer
$31$raReturn address

And then we have convention where we pass arguments to procedures via $a registers, and return values via $v registers... By not going based of their names, it will negatively impact the readability of your code. In addition to potentially overwriting registers which weren't meant to be touched in your program. 

Gotchas and code tips

1: If you notice that you've executed your program in MARS and it's going on forever (infinite loop), make sure to pause/stop the program ASAP.  If that works, then save the code somewhere safe and make the necessary edits to prevent the program from looping forever. 
If it doesn't work, on windows open task manager and end the task before it starts taking up too much memory. Unfortunately, if you wait too long, it will eventually crash and you might lose your code. 

2: I try to save my code in a folder that is being tracked via git and OneDrive. So as long as I commit and push the code to a repo... I have 2 backups besides for the local file on my computer.

3: Have an ASCII chart nearby when dealing with characters and strings! 

4: End your program properly, don't just let it run off the edge. I often set a label called exit, which can clean up any mess before ending, and then notify the chip via syscall that we are in fact done! 

·   li $v0 , 10 #exit

·   syscall

5: You can have fun with ASCII in MIPS, here is how to load and print a character for example.

li $a0, 'c' #ascii interpreter -

li $v0 , 11 #print char

syscall

6: While commas between arguments are optional, you should use them... if not then at least be consistent with your decision.

7: This one can get annoying, if you have items of varying types in your data segment, make sure to either put the things that need alignment first or utilize the .align keyword with a number following it depending on type (0 = byte, 1 = half word, 2  = word, 3 = double)

- MIPS requires everything to be word aligned (4 bytes), if something in your code isn't... it results in a nasty error. Take this for example: 

b: .space 1 #hold space for 1 byte 

a: .space 64 #allocate/hold space for 64 bytes

prompt: .asciiz "Hello World:"

The prompt is also an issue (if you have something below it), because it is 13 characters long (including the null byte). 

8. Learn how to use the various bit shifting commands as they tend to show up on exams! 

Arithmetic vs. Logic Shifts can be boiled down to the former sign extending/maintaining the signed bit vs the latter which zero-extends. Simply put, logical shifts fill the gaps after the move with zeros.. while arithmetic shifts maintain the sign (positive or negative), so they copy the signed bit to the location that needs to be filled. It is easiest to first convert the decimal value into binary and then shift the bits, and then convert the new value back to base10. 

Example: Left shift the number 5 by 1 spot. (in C++, it would be 5 << 1;)

    li $t5, 5 #load in #5 to reg $t5 

    sll $t6, $t5, 1 #left logical shift #5, by 1 spot and store in reg $t6

For simplicity, let's say we only space for 4 bits and the number is stored unsigned.

First, convert 5 to binary... it becomes 0101 

(use the powers of 2 trick 8 4 2 1, take the 4 and the 1 to get 5... the 8 becomes 0, 4 becomes 1, 2 becomes 0, and 1 is 1... leaving us with 0101). 

Now shifting left will push the number forward (essentially doubling it) and it will become 1010. The orange zero drops off the top, and the green zero is "backfilled". Using the same trick to convert, we get that the new number is 10.

Here is a simple code sample on the subject which you can run and modify in your IDE.  

When you bit shift in C++, often times the compiler makes that distinction and choses the most relevant option for you... but in MIPS each shift operation type is it's own command such as SLL - shift left Logical, SRA = shift right arithmetic, etc. 

In MIPS, you cannot shift arithmetically... (no such command exists) I'm leaving this as an exercise to the reader to determine why... feel free to leave our answers in the comment section! 

Bonus MARS Tools

They have so many useful tools such as a Floating Point Converter, Cache Simulator, X-Ray view of the single cycle, etc. I mentioned some other tools in the other MIPS blog post I wrote.

In the toolbar -> click Tools to have a go!

They have so many useful tools such as a Floating Point Converter, Cache Simulator, X-Ray view of the single cycle, etc.

Cache

As the course is computer architecture, it is important to study topics like how cache works (in general).... Here are some useful formulas which came in handy during my course:

The carrot symbol is to denote an exponent or power, and # = number. 

tag + set = logbase2(# of blocks in cache)
size of main memory/size of block = # of blocks in cache
N*2^set = # of blocks in cache
2^offset = size of block 
2^set = # of rows 
Total bits in cache = (size of block * 8 + 2 + tag) * N * 2^set //in WriteBack
Total bits in cache = (size of block * 8 + 1 + tag) * N * 2^set //in WriteThrough
Size of main address – set – offset = tag



Thank you for reading, please share the article and follow me on twitter for more resources and guides!



No comments:

Post a Comment

Thank you for posting a comment, it will be reviewed and then posted shortly.