Learning Objectives

  • Be able to clear integer instructions.
  • Be able to write unproblematic assembly programs.
  • Be able to load and shop from and to retentivity.
  • Be able to create labels and jump to them conditionally or unconditionally.
  • Be able to create and phone call functions using standard operating procedures.
  • Be able to use MARS's organization calls to print and read information.
  • Be able to use directives to create strings and other data.
  • Understand and use the unlike executable sections.
  • Exist able to use the stack for local storage.
  • Be able to utilise saved and temporary registers.
  • Understand what destroying registers means and what to practice almost information technology.
  • Understand how branches are implemented in the architecture.

In this lecture and in this class, nosotros will be using MARS (MIPS Assembler and Runtime Simulator), which you can download here: http://courses.missouristate.edu/kenvollmar/mars/download.htm


Associates

.text .globl main primary:     add $a0, $a0, $a1     jr  $ra

The code to a higher place shows three different pieces of the associates language. The words that start with a '.' are called directives. Those words that finish with a ':' are chosen labels. Everything else, including add and ret are called instructions.

Directives and labels are for yous (the programmer) and to change how the assembler functions. Instructions are encoded directly into machine code past the assembler. So, the important role about learning associates is to build your vocabulary--that is, learn the instructions and what they do. Recall, everything that C++ does in the end is converted into associates.


Agreement Associates

When we write assembly, nosotros become the C++, WE get the lodge of operations. Let's accept a look at a simple C++ statement and come across what we tin can exercise to catechumen it into assembly.

int i = 10; int j = xx; int thou = 30; int issue = i + j * one thousand;

When nosotros look at the code above, we tin can see that nosotros need to multiply j and 1000 together first, then add that product to i to get the event. The social club of operations was handled past C++ for u.s., but at present that we're instructing the processor ourselves, WE are at present the society of operations.

li $t0, 10 li $t1, 20 li $t2, 30  mul $t3, $t1, $t2 add $t4, $t3, $t0

This code to a higher place, we apply li (load immediate) to load the values x, 20, and thirty into three split registers, t0, t1, and t2 respectively. These registers have specific names, so we can't just name them i, j, and 1000 like we could in C++. Nosotros know that x + 20 * 30 will requite us 610, then allow's run across what nosotros get.

MARS Simulator Register Output

Our result is $t4, and the value is 0x262, which is \(two\times 16^2 + half dozen\times 16^1 + 2\times 16^0=610_{10}\). Discover that nosotros executed the mul (multiply) pedagogy commencement. In associates, the order of operations is whenever that instruction gets executed, and so nosotros must be the czar.


Registers

Registers are very small pieces of retentivity inside of the CPU. For our MIPS architecture, these are 32 bits a piece. Therefore, our MIPS is a 32-chip machine. On the Hydra and Tesla machines, each register is at least 64 bits, then our Hydra and Tesla labs machines are 64 bits.

MIPS has several registers which can be address past number, such as $0, $one, $2, or by its name, such as $a0, $t0, $s0. Here are the registers and their purpose in MIPS.

Register Proper name Usage
$zero Always the value 0. If you write to this register, the write is discarded.
$v0, $v1 The "render" registers. C++ and C only use $v0. These are Non preserved beyond role calls.
$a0 - $a3 The "argument" registers. These are Non preserved across function calls.
$t0 - $t9 The "temporary" registers. These are Not preserved beyond office calls.
$s0 - $s7 The "saved" registers. These ARE preserved across function calls. You must return them the same way you institute them.
$k0, $k1 The "kernel" registers. Do non use these.
$gp The "global pointer". Do non use this.
$sp The "stack pointer". Points to a memory address for local storage.
$fp The "frame pointer". Y'all can utilize this in conjunction with $sp to mark a stack frame.
$ra The "return address" register. Typically stores the render address for a part call. There is only ONE of these, then nested function calls must salve this!
Register file of the MIPS CPU.

The "use" of these registers are their recommended employ. You lot have full command over these registers, but if yous put a value that MIPS is not expecting, it could have unintended consequences!

What to look for

C++ handled data types (signed and unsigned, integral, and float), data sizes, and order of operations for us. Nosotros as the assembly programmer are now required to ensure that our data sizes are correct. MIPS is known as a load/store architecture. Notice that we could load pocket-size immediates, but we can merely deed upon immediates or registers. What about retentiveness? In MIPS, we take to load to become a value from retentivity into a register or store to put a value from a annals into memory.

Education Size (bytes) Description
sb $t0, 8($sp) 1 (byte) Stores the value of $t0 into ($sp + 8)
sh $t0, viii($sp) two (halfword) Stores the value of $t0 into ($sp + 8)
sw $t0, 8($a0) 4 (discussion) Stores the value of $t0 into ($a0 + viii)
lb $t0, 8($t7) 1 (byte) Loads a value from ($t7 + viii) into $t0
lh $a0, 10($t1) 2 (halfword) Loads a value from ($t1 + ten) into $a0
lw $a0, 0($s0) 4 (give-and-take) Loads a value from ($s0 + 0) into $a0
Load/store instructions in MIPS

The tabular array above has some examples of how to utilize them, nevertheless there are substantially five parts: (one) load vs. store (l vs. south), (2) data size (b, h, or westward), (iii) source (store) or destination (load) register, (three) get-go (can be 0), (4) destination (store) or source (load) register. The register for (4) must contain a valid retentiveness accost, or the pedagogy will cause the program to crash .

The lb and lh instructions volition take a 1-byte or 2-byte value, respectively from memory and put it into a 32-chip annals. Therefore, information technology needs to widen the value. These instructions volition sign-extend the value. So for lb, information technology takes scrap index 7 (the sign flake) and extends it 24 more times to make a total 32-bit value. The lh pedagogy takes bit alphabetize 15 (the sign bit) and extends it 16 more times to make a full 32-bit value.

Sometimes we want to nothing-extend a value instead. Then, instead of duplicating the sign bit, a widened value is simply padded with leading zeroes. We tin change the behavior by calculation a 'u' (for unsigned) at the end of the load instructions.

Instruction Description
lbu $t0, 0($sp) Load a byte from memory, and zero extend *($sp + 0) into $t0.
lhu $t0, 0($sp) Load a halfword (short) from memory, and zero extend *($sp + 0) into $t0.
Unsigned variants of MIPS's load instructions.

We obviously don't need an sbu or shu or fifty-fifty a lwu because each shop stores exactly 8 or 16 $.25 into memory. The lwu is not necessary considering nosotros cannot widen a 32-flake value (a word) since the registers are only 32-$.25. For a 64-bit automobile, we would take a lwu to widen a 32-bit value into a 64-bit annals.


Common Instructions

Educational activity Operation
add $t0, $t1, $t2 $t0 = $t1 + $t2
addi $t0, $t1, -100 $t0 = $t1 + -100
sub $t0, $t1, $t2 $t0 = $t1 - $t2
mul $t0, $t1, $t2 $t0 = $t1 * $t2
div $t0, $t1, $t2 $t0 = $t1 / $t2
rem $t0, $t1, $t2 $t0 = $t1 % $t2
Mutual integer instructions in MIPS

At that place are other instructions besides these, but these are your mutual integer instructions. Notice that in that location is merely addi (add immediate). MARS volition requite us a subi, but it is an addi with a negative immediate. The immediate (-100 in the example above) is encoded into the instruction itself. Each instruction consumes exactly 32 bits (4 bytes). The bulk of those $.25 are taken past the instruction and registers themselves, so that leaves footling room for the immediate. Therefore, this didactics is only useful for pocket-sized immediates.

Teaching Operation
sll $t0, $t1, 10 $t0 = $t1 << 10
sllv $t0, $t1, $t2 $t0 = $t1 << $t2
srl $t0, $t1, 10 $t0 = $t1 >> 10 (logical)
srlv $t0, $t1, $t2 $t0 = $t1 >> $t2 (logical)
sra $t0, $t1, 10 $t0 = $t1 >> 10 (arithmetic)
srav $t0, $t1, $2 $t0 = $t1 >> $t2 (arithmetic)
or $t0, $t1, $t2 $t0 = $t1 | $t2
ori $t0, $t1, x $t0 = $t1 | ten
xor $t0, $t1, $t2 $t0 = $t1 ^ $t2
xori $t0, $t1, x $t0 = $t1 ^ 10
and $t0, $t1, $t2 $t0 = $t1 & $t2
andi $t0, $t1, 10 $t0 = $t1 & ten
not $t1, $t2 $t1 = ~$t2
neg $t1, $t2 $t1 = -$t2
Logical Instructions in MIPS

All of the logical operations that we need are supported above. Some of the instructions in a higher place are called pseudoinstructions , and the assembler volition convert them to the bodily instruction. For case, not $t1, $t2, is the aforementioned as xori $t1, $t2, -1. In the reduced-instruction-set up-computer (RISC), we have a limited number of instructions, and so the assembler needs to choose the operation that might not exist exactly what yous wanted, but it's equivalent.


Jumps and Branches

We've seen how to make simple integer and logical instructions perform their magic, but a lot of times nosotros want to conditionally or repeatedly execute lawmaking. These are if statements and loops in C++. In MIPS, we accept jumps and branches. A branch can exist thought of as a condition, where as jumps are unconditional. As the name implies, information technology allows us to go somewhere else. Otherwise, the CPU will only execute the very adjacent educational activity in sequence.

This is where labels are important. A jump or branch instruction needs to know where to go to. A label is merely an like shooting fish in a barrel name we requite a memory address. When nosotros bound or co-operative, we tin can provide the label instead of hard coding the retentiveness address, and the assembler takes care of the rest!

if (t0 < t1) {     t2 = 100; } else {     t2 = -100; }

Who know what this code actually does, but let's encounter how we can convert it into associates. I used variable names t0, t1, and t2, only remember, variables are NOT registers! We are required to brand sure that each register contains the proper value of each variable.

## if (t0 < t1)    bge t0, t1, else_statement # If we get hither, t0 < t1 (t0 is NOT GE (greater-than-or-equal-to) t1)    li $t0, 100    j if_done ## else else_statement:    li $t0, -100 if_done:

Let's see what the code above is doing. Notice we accept labels (words ending with colons ':'). These marking retentiveness addresses so that when we branch or spring, we tin can provide a name rather than an accost. This is helpful considering the more than instructions nosotros write, the memory addresses change!

In the lawmaking in a higher place, I took the negative approach. The co-operative education (bge) stands for branch-if-greater-than-or-equal-to. Discover that that is the opposite of t0 < t1. And then, we're telling MIPS to go to the else statement if t0 >= t1. If the branch is taken, we jump to the label else_statement, otherwise, the co-operative instruction does zilch and we execute the didactics straight underneath it.

So, why the j if_done? A label just marks a retentiveness address. Similar a switch statement in C++, it doesn't stop code from executing. So, without the if_done, we would go right into the else argument and execute the code inside of the else statement even when t0 is indeed less than t1. That's not what we desire. And so, the jump instruction jumps over the else code and completes the if statement.

We can use the same branches and jump to execute a for loop. It is helpful for usa to know how a for loop works, when pieces of a for loop execute, and how many times.

for (t0 = 0;t0 < 100;t0++) {       t1 += ane; }
                li $t0, 0  # t0 = 0    li $t1, 0    li $t2, 100 for_loop_head:    bge $t0, $t2, for_loop_end   # t0 < 100 (we apply the negative)    addi $t1, $t1, i    # t1 += one    addi $t0, $t0, 1    # t0++    j for_loop_head  # loop after stride for_loop_end:

Branch instructions require two registers and a label. Therefore t0 < 100 cannot exist executed directly. Instead, we must use a register to concord 100.

As we can see in the for loop, we initialize the iterator ($t0) ONCE and only once. Then, just like in a for loop, we check the status before doing anything. Once again, I took the "negative" view. In a for loop the status is "if it'south truthful run the loop". Ours is "if the condition is faux, interruption the loop". We're saying the same thing except ours tells MIPS when to break the loop. Remember, when a branch is Non taken, it just executes the very next education. In our case, that's $t1 += 1. We can utilize addi since the firsthand is small. Then, as with a for loop, the pace (t0++) comes adjacent. After the step, nosotros check the condition over again. There's the loop!

Co-operative Instruction Operation
beq $t0, $t1, here if (t0 == t1) goto hither;
bne $t0, $t1, hither if (t0 != t1) goto here;
blt $t0, $t1, hither if (t0 < t1) goto here;
ble $t0, $t1, here if (t0 <= t1) goto here;
bgt $t0, $t1, here if (t0 > t1) goto hither;
bge $t0, $t1, hither if (t0 >= t1) goto here;
Common Branch Weather condition in MIPS

Every bit with many other instructions, some of the instructions to a higher place are pseudo-instructions. In MIPS, we really only have beq and bne. The assembler figures out how to practice the other ones, such every bit blt and bge. blt and bge will check for negative numbers, and so the sign-flake does NOT contribute to the magnitude. This means that blt and bge volition work with signed values. However, we still have unsigned values. In these cases, we can use the 'u' variants of blt and bge equally below.

bgtu $t0, $t1, label bgeu $t0, $t1, label bleu $t0, $t1, characterization bltu $t0, $t1, characterization

There is no such thing as bequ or bneu since these volition compare bit-by-bit; yet, all inequalities (blt, ble, bgt, bge) all accept 'u' variants.

It might exist more helpful to envision a for loop as a while loop. Here's an instance of the for loop higher up every bit a while loop. See if you can match the instructions in the associates to a higher place with what'southward going on with the loop beneath.

t0 = 0; while (t0 < 100) {     t1 += 1;     t0++; }

I ALWAYS recommend get-go writing your logic in C++ then translating to associates. You are probably not comfortable with assembly and developing logic just complicates the issue. Even I volition write more complicated code in C++ starting time, compile it, test it, and so interpret into assembly. Doing all of the in a higher place in associates is complicated, even for the pros!


Integer Comparisons

A branch status can exist implemented by subtracting the two operands and seeing what comes out. These tin be summed up using the flags NZCV, which stand for negative, zero, acquit, and overflow, respectively. If we subtract two numbers and the result is negative, that means that the beginning number is smaller than the second. If we subtract two numbers and the consequence is zippo, that ways both numbers were equal, analogously, if we subtract ii numbers and the result is not naught, that means the two numbers were not equal.

In MIPS, we only have three comparisons that we can do, equals, not equals, and less than. For the branches, we only have equals and not equals (bne and beq). For less than, nosotros can utilize the SLT (set-on-less-than) educational activity. The residual of the branch instructions are pseudo-instructions that implement a combination of slt and bne/beq.

In some architectures, flags are stored after a comparing and can be referred to later. As you tin can come across with MIPS, the branch educational activity itself will brand the comparison and decision to go to the given memory characterization.

Register-style Condition Flags

NZCV tin can come with unlike names, such as SF (sign flag), ZF (naught flag), CF (carry flag), and OF (overflow flag) in the Intel/AMD architecture. The point of this is to meet that you tin utilise a mathematical operation to compare ii numbers. Since our compages deals with numbers, hopefully it is becoming clear(er) how conditions tin be implemented.

To see these weather in action, we tin see unlike ways to represent these flags to give a certain conditional issue.

Status Flags
Equals Z = 1
Not Equals Z = 0
Less Than N = 1
Conditional Flags Used For Comparison

Yous can see this in activity. Recall that the conditions are set by looking at the upshot subsequently subtraction--the difference.

\(10 - 2 = viii\)

We can encounter Z = 0 (non equals) and North = 0 (not less than). Since it is non equals and not less than, information technology therefore must be greater than.

\(ii - 10 = -8\)

Nosotros can see Z = 0 (not equals) and North = 1 (less than). This means that 2 is less than 10.

To implement this in hardware, nosotros can hook the negative flag directly to the most significant scrap of our result. Recall that this is the sign bit. Then we can test all of the digits to meet if they are zero for the zero flag.


Executable Sections

Discover that we write .text at the peak of our associates code. This is because executable programs take different sections where we store our data. The MARS simulator only supports two out of the four, but here are the sections and their use. The ones supported by MARS are in assuming.

Department Directive Description
.text CPU instructions are called the "text" of an executable.
.information Global, initialized variables are in the information section.
.rodata Global, initialized constants are in the rodata section.
.bss Global, uninitialized variables are in the bss section. The operating system sets all of these to 0 during execution, so global uninitialized variables are NOT garbage!
Four different executable sections

These sections require a characterization and a directive. Then, we tin can create information using the following directives:

.data    data_as_bytes: .byte 100, 200    data_as_halfwords: .half 100, 200, 300    data_as_words: .discussion 100, 200, 300    data_as_a_string: .asciiz "This is a cord\n"    data_as_a_sequence_of_chars: .ascii "ABCDEFG"

You can see from the example higher up that we specify the information size as .byte, .half, or .word for 1, 2, and 4 bytes, respectively. These directives require a value. Nosotros tin can create more than one piece of data by adding commas. These will be in contiguous memory. Even so, how do nosotros get these values? We tin can use the pseudo-education called 'la' for load address.

.data    output: .give-and-take 123456 .text master:     li $v0, 1  # impress integer     la $a0, output # load Accost of output     lw $a0, 0($a0) # load value FROM address of output     syscall  # impress 123456

The code above will print 123456 to the screen. Notice that we first take to load the address of the "output" label. Nosotros cannot but directly dereference the value. Instead, we load the address, so do a lw (load-give-and-take) to dereference the memory accost into the bodily value.

Recollect that these are global variables! Just like in C++, we do non want to rely on these variables. So, only utilize globals VERY sparingly!

To see how we tin use a global variable equally an assortment of data, we can create an uninitialized array of bytes and then store into them using the .space directive. This requires a parameter which is the number of bytes that you want to reserve for the given label.

.information    storage: .space sixteen .text principal:    la $t0, storage    li $t1, 100    sw $t1, 0($t0)    addi $t1, $t1, 100    sw $t1, 4($t0)

The code above demonstrates using a characterization as storage. Nosotros can grab the accost and utilize the get-go of a store education to move within it. Notice that nosotros wrote .infinite xvi. This means that we reserved 16 bytes. It DOES NOT mean that we reserved a space and put the value 16 in there. Instead, the memory allocated using .infinite must be considered garbage since it is uninitialized. MARS volition probably make it all zeroes, but practise not assume that!


Local Data Storage

Notice that all of the sections above refer to global data. This is because local storage is stored on the stack . The stack is setup for us whenever we execute a programme. How practice nosotros refer to the stack? There is a special register ($sp) called the stack pointer . This is a memory accost where we can shop and load from. The stack starts at the higher memory addresses and grows towards the lower retention addresses. Nosotros are allowed to use AT or below $sp. If we want to allocate memory, nosotros subtract the number of bytes from the $sp. However, since nosotros're responsible for the stack, we MUST put it back the aforementioned way nosotros found it past adding back to it. We don't have to clear it or restore the values, but we do have to put $sp back.

In C++, the stack is used for all variables that are not global. C++ will automatically move the stack pointer around. This is helpful (and necessary) when calling functions.

addi $sp, $sp, -viii li $t0, 100 li $t1, 200 sw $t0, 0($sp) sw $t1, 4($sp) addi $sp, $sp, eight

Higher up, we allocated viii bytes past subtracting from the stack pointer, which is two words. Since $sp points to a memory address, we tin can simply apply load and store to read or write values on the stack. This is called a stack frame. Since we allocated 8 bytes, we are immune to utilize $sp + 0, $sp + 1, ... $sp + 7 (think 0-based indices).

The stack pointer is required to be aligned by 8 bytes, which is a fancy term of saying the stack pointer must exist a multiple of 8. Therefore, even if we need 1, two, or even four bytes, we must still subtract 8. In fact, anything we subtract from $sp must be a multiple of 8. If we demand 12 bytes? We decrease the nearest multiple of 8, which is sixteen.


Functions

Functions are simply a fancy term for a label. The "difficult" part is remembering how arguments are passed to a part and how data is returned. It's not that hard and MIPS makes it much easier.

The $a0 through $a3 registers are a considering they are chosen the argument registers. So, the first argument goes into a0, the second into a1, the 3rd into a2, and the fourth into a3. What about returns? The return value goes into $v0.

Nil forces u.s. to use this policy, but it is standard operating procedure called the application binary interface or ABI. This is a fancy term for the rules we agree upon to brand functions work across programming languages.

int add_one(int value) {      render value + 1; } int main() {     int result = add_one(two);     return 0; }

A fairly elementary case. Then, we want to call add_one with an argument of 2. Take annotation of the data types!

j main add_one:     addi $v0, $a0, 1     jr $ra main:     li $a0, 100     jal  add_one     # $v0 will be 101 hither

Nosotros start by executing j main. This is considering MARS starts at the tiptop of our assembly code and works its way down. Normal executables don't exercise this. Instead, normal executables starting time at a label chosen _start, which eventually works its way to int main().

When we're in master, we take to set up the parameters before we call add_one. The pedagogy jal stands for jump-and-link. This instruction will put the retentiveness address under the jal educational activity into the $ra (return-address) register. This allows the function to find its way dorsum to int main(), otherwise, how practice nosotros know which retention address to become back to?


Destroying Registers

Per the aforementioned standard that says $a0 through $a3 get our arguments, these are as well considered scratch registers. In fact, all $t (temporary) and $a (argument) registers are considered scratch registers. This ways that when we call a function, that function is permitted to destroy whatsoever value is within any temporary or argument annals. Therefore, if we have of import data within of an a or t register, when we call a function, nosotros MUST consider it destroyed.

Saved Registers ($s0..$s7)

This is where the saved registers come into play. These registers per the standard are required to accept the same value before AND after a function call. We are all the same immune to use them, simply we must apply the stack to shop the original value of any saved register before nosotros use them. And so, earlier we render from our role, nosotros're required to load the old value back.

You will usually apply a saved register if you find yourself in a loop loading and storing over and again. Recall that each register is exactly 32 bits (4 bytes), and then we know how much stack space we need by adding all of the register we need to use together. Remember, the stack must be a multiple of eight!

Also, we simply have One $ra annals. If we demand to call some other function, nosotros will use the jal (jump-and-link) instruction. However, this instruction will destroy what'south already in $ra! Therefore, we're required to salve information technology as well only when we call another function.

my_function:    addi $sp, $sp, -16    sw $s0, 0($sp)    sw $s1, 4($sp)    sw $s2, eight($sp)    sw $ra, 12($sp)    li $s0, 100    li $s1, 200    li $s2, 300    jal some_function_label    # Nosotros tin can assume $s0, $s1, and $s2 are notwithstanding 100, 200, and 300.    lw $s0, 0($sp)    lw $s1, iv($sp)    lw $s2, 8($sp)    lw $ra, 12($sp)    addi $sp, $sp, xvi    jr $ra

Observe that we can use the offset to identify the register. We decrease xvi bytes from the stack because we're storing 4 registers and \(4\times iv = xvi\). Even if we were just storing iii register (12 bytes), we would still need xvi bytes from the stack since it is required to be a multiple of viii.

Since we don't know what's in whatsoever of the saved registers and nosotros don't know the exact size of $ra, we must always shop and load the maximum size, which is a discussion (sw and lw). That makes guessing obsolete at least!


System Calls

This is just for MARS and is not a MIPS thing. If we want to read integers or print them to the screen, we would usually apply printf or cout. These functions somewhen make a system call to the operating system to get the output. In MARS, we have to employ system calls, which can be constitute in "Help > System Calls". I will outline just the most useful beneath.

Hither are the steps to make a system call in MARS.

  1. Load organisation call number in $v0.
  2. Fix the parameters (come across tables beneath).
  3. Execute syscall instruction.
  4. Read return values (if applicable)

An example of the steps above can be seen below. Notice we execute a impress instruction for any is inside of the $t0 register. We actually make the organization call using the syscall instruction.

li $v0, i             # syscall #1 is print integer add together $a0, $t0, $zip   # This is the same as movement $a0, $t0 syscall               # syscall instruction issues the system phone call

Output

System Call Value of $v0 Parameters
Impress integer one $a0 is integer to print
Print bladder 2 $f12 is float to print
Print double 3 $f12 is double to print
Impress string iv $a0 is address of nix-terminated cord to print
Print-based organisation calls for MARS

So, following the procedures, we can print an integer past putting the organization code in $v0, which for print integer is 1, or for print string is 4.

.data    output: .asciiz "Hello World\north"  .text main:    li $v0, 4    la $a0, output    syscall

In the code above, nosotros employ li to put the system call #4 (impress cord) into $v0. And then we use la (load address) to load the address of the output string into $a0. We so make the system call by using the syscall teaching. Look at the window at the bottom of MARS, we can come across:

Hello World is printed in MARS using $v0=four organization call

Notice that I used .asciiz in the .data section to create the string. In C++, string literals go in the .rodata section, but MARS doesn't have one. Also, .asciiz means "use the ASCII table for characters and put a Z (zero) at the cease of it". C-fashion strings don't take a length. We know the length of a cord by counting until we hitting a 0--this 0 is called the null byte. This is why we have .asciiz. If nosotros don't desire a zero to automatically be put into our string, nosotros can utilize just .ascii. The null byte (0) is why we call strings null-terminated. Since we keep writing the string until we hit that null byte, which is 0.

Unfortunately, we don't take the power of printf. So, if nosotros want to impress strings and integers, we need two dissimilar system calls. The following example shows how to print an integer.

.text main:    li $v0, 1    li $a0, 100    syscall

Every bit you can see, we put the value ane into $v0 for the "impress integer" arrangement telephone call, and and then we put whatever value nosotros want to print in $a0. This produces the post-obit.

Print the integer 100 using system call #one in MARS

Input

Just like printf and cout, we have scanf and cin. Unfortunately, we don't accept that power with MARS. And then, we need to use the input organisation calls equally summarized below.

System Phone call Part Value of $v0 Returns
Read integer 5 $v0 contains integer
Read float (32-$.25) six $f0 contains float
Read double (64-bits) 7 $f0 contains double
Read cord 8 $a0 is input buffer which is filled with the string. $a1 is the maximum size of the buffer.
Read-based system calls for MARS.

An example of using the read-based system calls to a higher place is below.

.data     prompt: .asciiz "Enter an integer: "     output: .asciiz "You entered the integer: " .text main:    # Get-go, impress the "Enter an integer" prompt    li $v0, 4    la $a0, prompt    syscall    # At present look for the user to input an integer    li $v0, five    syscall    # Movement $v0 (the integer) out of the way    move $s0, $v0    # Output the "Y'all entered the integer" prompt    li $v0, 4    la $a0, output    syscall    # Finally, movement $s0 into $a0 and impress the actual integer in $a0    move $a0, $s0    li $v0, one    syscall

The code above starting time prompts the user to enter an integer. When they practice and printing ENTER, the system call puts that integer into $v0. Nosotros and then move that into $a0 so that we can print it using the print integer system call.

Reading and outputting an integer.

You lot might see the move instruction. This is yet another pseudo-teaching that resolves to using the add instruction. And so, move $t0, $s0 is the aforementioned as add $t0, $s0, $zero. This is why the syscall assistance in MARS uses add $a0, $t0, $zero instead of move $a0, $t0. They do the same affair, simply the add together instruction is existent.

Aye, there is a annals chosen $zero. This tin be used to load a value of 0 always. If we write to this register, the value is discarded. The zero annals is hardwired to 0 and cannot exist changed.


"Dropped off Bottom"

The MARS simulator volition cease your programme whenever there are no more instructions to execute. This is Non how an actual system works. Instead, when we return from int master(), C++ will make a request to the operating system to shut your plan. However, for purposes of this class, whenever y'all want to quit your program, only leap to the very terminate. I e'er brand a label called "end" that is at the bottom of each program.

In normal situations, we would utilise the get out (or exit2) arrangement calls to tell the operating system to terminate our process.