UY 2214 — E20 Manual

CS-UY 2214 — E20 Manual
Jeff Epstein
2.1 Registers…………….
2.2 Instructions…………..
2.3 Memory…………….
2.4 Comparison…………..
2.5 Subroutines …………..
2.6 E15vsE20 ………………………………………. 11
3 Instruction set 11
3.1 Instructionswiththreeregisterarguments……………………….. 12 3.1.1 add$regDst,$regSrcA,$regSrcB………………………… 12 3.1.2 sub$regDst,$regSrcA,$regSrcB ………………………… 12 3.1.3 or$regDst,$regSrcA,$regSrcB…………………………. 12 3.1.4 and$regDst,$regSrcA,$regSrcB………………………… 12 3.1.5 slt$regDst,$regSrcA,$regSrcB…………………………. 13 3.1.6 jr$reg……………………………………… 13
3.2 Instructionswithtworegisterarguments………………………… 13 3.2.1 slti$regDst,$regSrc,imm……………………………. 13 3.2.2 lw$regDst,imm($regAddr)…………………………… 13 3.2.3 sw$regSrc,imm($regAddr) …………………………… 14 3.2.4 jeq$regA,$regB,imm……………………………… 14 3.2.5 addi$regDst,$regSrc,imm …………………………… 14
3.3 Instructionswithnoregisterarguments ………………………… 15 3.3.1 jimm ……………………………………… 15 3.3.2 jalimm …………………………………….. 15
3.4 Pseudo-instructions…………………………………… 15 3.4.1 movi$reg,imm…………………………………. 15 3.4.2 nop ………………………………………. 15 3.4.3 halt ………………………………………. 16
3.5 Assemblerdirectives ………………………………….. 16 3.5.1 .fillimm…………………………………….. 16
3.6 Undefinedbitpatterns…………………………………. 16
4 Examples 16
4.1 Math………………………………………….. 16 4.2 Loops …………………………………………. 17 4.3 Subroutines………………………………………. 17 4.4 Variables ……………………………………….. 17
1 Introduction
2 Architecture
…………….. …………….. …………….. …………….. ……………..
…………… 2 …………… 2 …………… 4 …………… 8 …………… 9
Code Help, Add WeChat: cstutorcs
5 Hardware implementation 18
5.1 Single-cycleversion…………………………………… 18 5.1.1 Circuitdiagram…………………………………. 18 5.1.2 Controlsignals …………………………………. 19
5.2 Multicycleversion …………………………………… 20 5.2.1 Circuitdiagram…………………………………. 21 5.2.2 High-levelstatediagram…………………………….. 22 5.2.3 Low-levelstatediagram …………………………….. 22
5.3 Pipelinedversion……………………………………. 23 5.3.1 Circuitdiagram…………………………………. 23 5.3.2 Stages……………………………………… 25 5.3.3 Controlmodulesandwires …………………………… 25 5.3.4 Architecturaldifferences…………………………….. 26
1 Introduction
This manual covers the architecture of the E20 processor and its instruction set. The E20’s architecture is more powerful than the E15, and its assembly language is more expressive. The encoding of its machine language is also more complicated, so we will introduce a program, called an assembler, to convert its assembly language into machine language, which can be directly interpreted by the processor.
2 Architecture 2.1 Registers
The E20 processor has eight numbered 16-bit registers. By convention, in E20 assembly language, we write each register name with a dollar sign, so the registers are $0 through $7. However, register $0 is special, because its value is always zero and cannot be changed. Attempting to change the value of register $0 is valid, but will not produce any effect: the register is immutable. Therefore, we have only seven mutable registers that can actually be used as registers, $1 through $7. The initial value of all registers is zero.
In addition, the E20 processor has a 16-bit program counter register, which cannot be accessed directly through the usual instructions. The program counter stores the memory address of the currently-executing instruction. The initial value of the program counter register is zero. After each non-jump instruction, the program counter is incremented. A jump instruction may adjust the program counter.
2.2 Instructions
Syntax Each instruction in E20 assembly language consists of an opcode, as well as zero, one, two, or three arguments. Opcodes are not case-sensitive. Numeric arguments are expressed in decimal. At least one space is required between the opcode and the first argument. Arguments are separated by commas. Optional spaces may occur around each comma. Optional spaces may occur before the opcode, as well as after the last argument, or immediately after the opcode if there are no arguments. A maximum of one instruction may appear on a single line.
Any opcode may optionally be prefixed by any number of label declarations, each consisting of a label name followed by a colon. At least one space is required between a label declaration and any subsequent label declaration or opcode on the same line. A label name is a non-empty sequence of letters, digits, and underscores; the first character may not be a digit. Labels may appear either on the same line as an instruction, or on a line by themselves. A label declaration may also appear on a line after the last instruction of a program. Label names are not case-sensitive.
Comments begin with a hash mark (#) and continue to the end of the line. Blank lines are ignored. 2

There are three kinds of arguments:
• register argument — an integer 0 . . . 7 prefixed with dollar sign. For example, $4
• immediate argument — may consist of a positive decimal integer, such as 34; a negative decimal integer, such as -4; or a label name, such as loc2
• memory reference — a combination of an immediate argument and a register argument, with the latter contained in parentheses. For example, 0($2) or array($0)
Examples The add instruction takes three register arguments: a destination register and two source registers, as follows:
add $1, $2, $3 # add the value of $2 and the value of $3, store sum into $1 The addi instruction takes a destination register, a source register, and an immediate value, as follows.
Note that the third argument is an immediate value, not a register:
addi $1, $2, 3 # add the value of $2 and 3, store sum into $1
Due to the special property that register $0 always has value zero, we can use the same opcode to store an immediate value into a register. Below, we add the immediate value to the value of register $0, so the sum will always equal the immediate value:
addi $1, $0, 3 # store 3 into $1
The j instruction takes an immediate argument, and jumps to the memory address indicated. The
address may be expressed numerically or with a label:
j 8 # jump to address 8
j somelabel # jump to address given by label (defined elsewhere)
The lw instruction has one register argument and one memory reference argument. It will calculate a pointer given by the memory reference argument, and read the value stored at that memory address, storing it into the given register. Each memory reference argument has two parts: an immediate value (specified as a number or as a label) and a parenthesized register name. The memory address to be accessed is calculated by adding the immediate value and the value stored in the register:
lw $4, 0($3)
lw $4, foo($0)
# the memory reference is 0($3). Here,
# the immediate part is zero, and the
# register is $3. Therefore, the address
# to be read is equal to the value of
# register $3, plus zero. The value at that # memory location will be stored into
# register $4
# the memory reference is foo($0). Here, the
# immediate part is foo, a label. The register # part is $0, which we know has the value 0.

lw $4, foo($3)
# Therefore, the address to be read is equal # to the value of foo, plus zero. The value
# at that memory location will be stored into # register $4
# the memory reference is foo($3). Here, the
# immediate part is foo, a label. The register
# part is $3. Therefore, the address to be read
# is equal to the value of foo, plus the value
# of register $3. The value at that memory location # will be stored into register $4.
Further examples of instructions are given below, as well as in the provided example programs.
Common errors The format of the addi instruction specifies the following fields: • opcode — 3 bits
• source register — 3 bits
• destination register — 3 bits • immediate — 7 bits
This means that the immediate value must be expressed as a signed 7-bit number, in the range of −64 . . . 63. Any value outside of that range is not expressible in the allocated number of bits, and therefore the assembler must reject it. A similar restriction exists for other instructions that take an immediate field, such as jeq and slti.
A consequence of the above stipulation is that it’s impossible to directly set all bits of a register at once, with a single addi instruction. For that, we would need to use lw to read a stored value from memory.
2.3 Memory
The E20 processor has 8192 16-bit cells of memory. Initially, the program is loaded into memory, starting at address zero. The program counter is initially zero, so execution begins at the first instruction of the program. Memory cells that do not initially contain program instructions are initially set to zero.
The 8192 cells of memory are addressed using 13-bit addresses. When accessing a memory cell via a pointer (either through the program counter, or with the lw and sw opcodes), the 3 most significant bits of the pointer are ignored. Therefore, an instruction accessing memory via a pointer value 43222 (10101000110101102) refers to the same address as a pointer value 2262 (00001000110101102). Similarly, the instruction to be executed will be determined by the least significant 13 bits of the program counter.
E20 assembly language allows the use of labels. A label is a symbol that represents a known memory address. A label’s name is a sequence of characters obeying the following rules: the first character may be a letter or an underscore; subsequent characters may be a letter, an underscore, or a digit; there must be at least one character. Label names are not case-sensitive.
A label may be declared in your assembly code by giving its name followed by a colon, preceding any instruction (including normal instructions, pseudo-instruction, and directives). Multiple labels may be de- clared at a single instruction, one after another. The value of the label will be the address of the instruction that it precedes. If the label precedes no instruction, the value of the label will be the address that a subse- quent instruction would occupy. A label’s name may be used as the imm field of any instruction, assuming that the value of the label can be expressed in the number of bits allocated to that field. A label’s declaration need not precede its use.
Labels make it easier to write E20 assembly language programs. Instead of referring to addresses nu- merically, which will change as we add or remove instructions in the development of our program, we can

refer to addresses by name, which the assembly will convert to the appropriate numeric address. Labels can denote the address of an instruction (which can serve as the target of a jump instruction) or the address of a data location (which can serve as the target of load/store word instruction).
Here’s an example program, with assembly language on the left, and the corresponding machine code on the right:
first_label: movi $1, 1
j first_label
j second_label second_label:
movi $2, 2
ram[0] = 16’b0010000010000001; ram[1] = 16’b0100000000000000; ram[2] = 16’b0100000000000011;
ram[3] = 16’b0010000100000010;
In the above program, the label first_label is declared before the instruction at address 0, therefore its value is zero. The second_label is declared before the instruction at address 3, so its value is 3. The instruction j first_label refers to first_label, so the immediate field of that instruction contains the value of that label. Similarly, the instruction j second_label has an immediate field containing the value of that label. In the above listing, the color of the labels matches to the color of the corresponding bits.
Memory can be read and written using the lw and sw instructions, respectively.
The lw (load word) instruction will read a memory cell, copying its value into a register:
• The first argument of lw is the register to copy the value into. • The second argument of lw has two parts:
– an immediate field, which can be a number or a label, and – a register field.
The immediate will be summed with the value of the register, giving the memory address to read from. The sw (store word) instruction will write to a memory cell, copying a value from a register:

程序代写 CS代考 加微信: cstutorcs
• The first argument of sw is the register holding the value to be copied to be memory. • The second argument of sw has two parts:
– an immediate field, which can be a number or a label, and – a register field.
The immediate will be summed with the value of the register, giving the memory address to write to.
Here’s an example:
lw $2, myvariable($0) movi $3, 1
lw $4, myvariable($3)
myvariable: .fill 42 .fill 97
ram[0] = 16’b1000000100000011; ram[1] = 16’b0010000110000001; ram[2] = 16’b1000111000000011;
ram[3] = 16’b0000000000101010; ram[4] = 16’b0000000001100001;
In the above program, the instruction at address 0 calculates the memory address myvariable + $0, which is equal to myvariable. The value of the label myvariable is 3, because the label is declared at the instruction at memory address 3. Therefore, the first lw reads the value at that address, which is 42, and loads it into register $2. Then, in the instruction at address 2, we calculate the memory address myvariable + $3, which is myvariable + 1, which is 4. The value at memory address 4 is is 97, which is loaded into register $4.
Variables We can use labels, lw, and sw to provide variables to our program. Consider the following: beginning:
lw $1, mycounter($0) addi $1, $1, 1
sw $1, mycounter($0) j beginning
mycounter: .fill 0
ram[0] = 16’b1000000010000100; ram[1] = 16’b0010010010000001; ram[2] = 16’b1010000010000100; ram[3] = 16’b0100000000000000;
ram[4] = 16’b0000000000000000;
In the above program, mycounter is a label with the value 4, referring to a memory address initialized to the value 0. In each iteration of the loop, the value from that address is read, incremented, and stored back into memory. The register $1 is used only temporarily. This approach to storing data is convenient, because although we have relatively few registers, we have access to a large number of memory addresses.

Arrays The numeric relationship of memory addresses to each other allows us to loop through a sequence of adjacent memory addresses, effectively treating them as an array. For example:
movi $1, 0
movi $3, 0 loop:
lw $2, myarray($1) add $3, $3, $2 addi $1, $1, 1
jeq $2, $0, done
j loop done:
halt myarray:
.fill 5 .fill 3 .fill 20 .fill 4 .fill 5 .fill 0
ram[0] = 16’b0010000010000000; ram[1] = 16’b0010000110000000;
ram[2] = 16’b1000010100001000; ram[3] = 16’b0000110100110000; ram[4] = 16’b0010010010000001; ram[5] = 16’b1100100000000001; ram[6] = 16’b0100000000000010;
ram[7] = 16’b0100000000000111;
ram[8] = 16’b0000000000000101; ram[9] = 16’b0000000000000011; ram[10] = 16’b0000000000010100; ram[11] = 16’b0000000000000100; ram[12] = 16’b0000000000000101; ram[13] = 16’b0000000000000000;
In the above program, myarray identifies the address of the beginning of an array of numbers, which is really just a sequence of memory locations. The program uses $1 to store an index into the array, starting at zero, and incrementing it thereafter. A value from the array is read by the instruction at address 2. The loop will then sum each consecutive array element into a running total in $3, before continuing to the next array element. When it finds an array element whose value is zero, the loop ends. Thus, this program sums all element in the array, and the final value of $3 will be 37.
Halting As in the E15, the end of the program is expressed by entering a tight loop. We use the halt pseudo-instruction for this purpose, which is implemented as a jump to itself. That is, the halt instruction is equivalent to the following:
endofprogram: j endofprogram
Common errors Although a label may be declared before or after its use, it is an error to refer to a label that has not been declared at all in the program. For example, the following program cannot be assembled:
lw $1, mycounter($0) addi $1, $1, 1
sw $1, mycounter($0) j beginning
mycounter: .fill 0
# undeclared label!
It is an error to declare the same label more than once in a program. On the other hand, it is not an error to declare a label that is never referred to.
Jumps E20 has several jump opcodes:
• j — jump, with a 13-bit destination address
• jal — jump and link, with a 13-bit destination address
• jr — jump to register, with a register containing a 16-bit destination address

• jeq — jump if equal, with a 7-bit relative destination address
In the case of jr, the register argument provides a 16-bit address, which is loaded into the program counter.
In the case of j and jal, the instruction format provides only a 13-bit destination address. The provided 13 bits will be copied into the least-significant 13 bits of the program counter, and the remaining 3 bits of the program counter will be set to zero.
In the case of jeq, the instruction format provides only a 7-bit relative destination address, which is interpreted as a signed 2’s complement number, sign-extended1, and added to the 16-bit address of the subsequent instruction; this sum is stored into the program counter. This means that using only this instruction, it is impossible to jump to a location more than 27−1 − 1 = 01111112 = 6310 cells ahead of the current program counter, or more than −27−1 = 10000002 = −6410 behind it.
In E20 assembly language, it is an error to provide a immediate value, either numerically or by label, that exceeds the allowed number of bits for the immediate field of the given instruction. For example, j 9000 cannot be assembled, since 9000 cannot be expressed as a 13-bit unsigned integer. Similarly, jeq $0, $0, 90 cannot be assembled if it is located at address 0, since 90 − 0 − 1 = 89 cannot be expressed as a 7-bit 2’s complement integer.
2.4 Comparison
E20 supports equality comparison and less-than comparison.
Equality Equality comparison is achieved with the jeq instruction. Its arguments are two registers, and an immediate value that indicates a memory location. If the values of its two register arguments are equal, then the program will jump to the given address. Otherwise, the program will proceed to the subsequent instruction. For example, consider the following program:
jeq $1, $0, they_are_equal addi $1, $1, 1
they_are_equal: addi $1, $1, 2
# if $1 is 0, go to they_are_equal
# we execute this only when $1 is not 0 # avoid fall-through to next instruction
# we execute this only when $1 is 0
# end of program
The above E20 assembly program might be expressed roughly using the following Python code:
if Reg1 == 0: Reg1 += 2
Note that the j instruction is necessary. In contrast, consider the following program, identical except for the omission of the j instruction:
jeq $1, $0, they_are_equal
addi $1, $1, 1 they_are_equal:
addi $1, $1, 2 done:
# if $1 is 0, go to they_are_equal
# we execute this only when $1 is not 0
# we execute this regardless # end of program
1To sign-extend is to increase the number of bits of a 2’s complement number, in such a way that does not change the value it represents. The most-significant bit of the number, which represents the sign (negative or non-negative) of the value, must be reproduced into new bits positions. For example, consider a 4-bit 2’s complement number, 10112 = −510. If we sign-extend this to an 8-bit number, it will become 111110112.
In this case, we need to sign-extend the 7-bit address to 16 bits, because the result must be added to a signed 16-bit number.

This version would be expressed with the following Python code:
if Reg1 != 0: Reg1 += 1
Less-than Less-than comparison is achieved with the slt or slti instructions, in conjunction with jeq. The slt or slti instructions will set a given register to 1 if its second argument is less than its third argument, and to 0 otherwise. Then, we can use jeq to check the value of the given register. For example:
slt $1, $2, $3
jeq $1, $0, not_less addi $2, $2, 1
addi $2, $2, 2
# $1 will be set to 1 if $2 < $3 # if $1 is now 0, we know $2 >= $3
# we execute this only when $2 < $3 # avoid fall-through to next instruction # we execute this only when $2 >= $3
# end of program
The above E20 assembly program might be expressed roughly using the following Python code:
if Reg2 < Reg3: Reg2 += 1 Note that slt and slti perform unsigned comparison. That is, both comparands are assumed to be non-negative binary numbers. Less-than-or-equals We can combine the above approaches to provide less-than-or-equals comparison. First we compare for equality, then for less-than. jeq $2, $3, less_or_equal slt $1, $2, $3 jeq $1, $0, not_less_or_equal less_or_equal: addi $2, $2, 1 j done not_less_or_equal: addi $2, $2, 2 done: 2.5 Subroutines # jump if $2 and $3 are equal, otherwise fallthrough # $1 will be set to 1 if $2 < $3 # if $1 is now 0, we know $2 > $3
# we execute this only when $2 <= $3 # avoid fall-through to next instruction # we execute this only when $2 > $3 # end of program
The jal and jr instructions can be used together to achieve subroutines, a flow control mechanism that allows execution to return to an early point of code, and can be invoked from multiple places within a program. A subroutine is therefore like a function, but does not necessarily encompass the parameters and return values that functions usually entail.
Before we discuss how subroutines work in E20, consider the following C++ code:
1 intx=0; 2 inty=0; 3

4 void sub1() {
void main() { sub1();
In the above code, execution starts at line 10. The subroutine sub1 is invoked, which does stuff in lines 5 and 6, and execution then returns to line 11. At line 11, the subroutine is invoked again, lines 5 and 6 are executed again, and execution returns to line 12, whereupon the program ends.
The subtlety of such code is the mechanism by which these invocations and returns are implemented. How does sub1 know where to return to when it finishes, particularly when it returns to a different place each time?
On most architectures, this feat is accomplished by storing the address of the subsequent instruction at the time of a subroutine’s invocation. Then, when the subroutine has finished, it copies that stored address into the program counter. This approach is used by the E20 processor.
• The jal (jump and link) instruction is similar to the ordinary jump instruction (j), with the key difference that in addition to storing the immediate value into the program counter, jal will store the address of the subsequent instruction into $7.
• The jr (jump to register) instruction copies the address in the given register into the program counter. Therefore the instruction jr $7 will jump to the address in the register $7, where it was previously stored by jal.
Below is a direct E20 translation of the above C++ program. Note that we use jal sub1 to invoke the subroutine, and jr $7 to return from it.
jal sub1 halt
lw $1, x($0)
addi $1, $1, 1 sw $1, x($0)
lw $1, y($0) addi $1, $1, -1 sw $1, y($0)
# invoke subroutine
# invoke subroutine again # end program
# return from subroutine

Common errors A limitation of subroutines on E20 is that the value of $7 must be preserved for the duration of the subroutine. If the subroutine modifies $7, then the jr instruction may return to an unintended location.
A corollary of the above limitation is that a subroutine cannot call another subroutine. Since the jal instruction modifies $7, this makes recursion awkward on E20.
Both of these limitation have workarounds. For example, a subroutine could save the value of $7 into another register or into memory. It would then be free to manipulate $7, including by invoking other subroutines, as long as it restores the original value of $7 before it returns.
2.6 E15 vs E20
The E20 processor can be considered a more powerful version of the E15. Although they have many features in common and their instruction sets are similar, the E20 expands some capabilities.
registers four 4-bit registers seven 16-bit registers
16 12-bit cells of read-only in- struction memory
8192 16-bit cells of instruction/- data memory
instruction format
all instructions have 4-bit opcode field, two 2-bit register fields, and 4-bit immediate field
three formats:
• 3-bit opcode field, three 3- bit register fields, 4-bit im- mediate field
• 3-bit opcode field, two 3- bit register fields, 7-bit im- mediate field
• 3-bit opcode field, 13-bit immediate field
3 Instruction set
Here we discuss the instructions that form the E20 instruction set. We categorize the instructions by their format, which is based on the number of register arguments. The format determines how many bits are allocated to each argument.
In addition to instructions proper, we discuss pseudo-instructions, which are assembly mnemonics that are translated to another instruction. Finally, we cover assembler directives, which change the behavior of the assembler but do not correspond to any specific instruction.
In the following subsections, we give the following information about each instruction:
• the instruction name and syntax — The header of each subsection gives the assembly language syntax.
• the instruction format — Within each 16-bit instruction, we show which bits must have which values.
• the informal behavior — We give a brief prose description of the behavior of the instruction when executed.
• the formal behavior — We use a symbolic notation to express the behavior of the instruction. Here, we use the following symbols:
– <-: indicates that the location on the left will be updated with the value on the right – $reg (and variants, such as $regA, $regSrc, etc): the instruction’s register argument Programming Help
– imm: the instruction’s immediate argument
– R: the processor’s register file, indexed by the name of a register, 0 . . . 7 – Mem: the processor’s memory, indexed by a memory address
– pc: the program counter
Unless otherwise specified, immediate values can be positive, negative, or zero and are represented in 2’s complement. Unless otherwise specified, all instructions increment the program counter.
Instructions with three register arguments
add $regDst, $regSrcA, $regSrcB
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
3 bits 3 bits 3 bits 3 bits 000 regSrcA regSrcB regDst
4 bits 0000
Example: add $1, $0, $5
Adds the value of registers $regSrcA and $regSrcB, storing the sum in $regDst. Symbolically: R[regDst] <- R[regSrcA] + R[regSrcB] 3.1.2 sub $regDst, $regSrcA, $regSrcB 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 3 bits 3 bits 3 bits 3 bits 4 bits 000 regSrcA regSrcB regDst 0001 Mnemonic: Subtract Example: sub $1, $0, $5 Subtracts the value of register $regSrcB from $regSrcA, storing the difference in $regDst. Symbolically: R[regDst] <- R[regSrcA] - R[regSrcB] 3.1.3 or $regDst, $regSrcA, $regSrcB 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 3 bits 3 bits 3 bits 3 bits 4 bits 000 regSrcA regSrcB regDst 0010 Example: or $1, $0, $5 Calculates the bitwise OR of the value of registers $regSrcA and $regSrcB, storing the result in $regDst. Symbolically: R[regDst] <- R[regSrcA] | R[regSrcB] 3.1.4 and $regDst, $regSrcA, $regSrcB 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 3 bits 3 bits 3 bits 3 bits 4 bits 000 regSrcA regSrcB regDst 0011 Example: and $1, $2, $5 Calculates the bitwise AND of the value of registers $regSrcA and $regSrcB, storing the result in $regDst. Symbolically: R[regDst] <- R[regSrcA] & R[regSrcB] 3.1.5 slt $regDst, $regSrcA, $regSrcB 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 3 bits 3 bits 3 bits 3 bits 4 bits 000 regSrcA regSrcB regDst 0100 Mnemonic: Set if less than Example: slt $1, $2, $5 Compares the value of $regSrcA with $regSrcB, setting $regDst to 1 if $regSrcA is less than $regSrcB, and to 0 otherwise. The comparison performed is unsigned, meaning that the two operands are treated as unsigned 16-bit integers, not 2’s complement integers. Therefore, 0x0000 < 0xFFFF. Symbolically: R[regDst] <- (R[regSrcA] < R[regSrcB]) ? 1 : 0 3.1.6 jr $reg 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 3 bits 3 bits 3 bits 3 bits 4 bits 000 reg 000 000 1000 Mnemonic: Jump to register Example: jr $1 Jumps unconditionally to the memory address in $reg. The jump destination is expressed as an absolute address. All 16 bits of the value of $reg are stored into the program counter. Symbolically: pc <- R[reg] 3.2 Instructions with two register arguments 3.2.1 slti $regDst, $regSrc, imm 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 3 bits 3 bits 3 bits 7 bits 111 regSrc regDst imm Mnemonic: Set if less than, immediate Example: slti $1, $2, some_label Example: slti $1, $2, 30 Compares the value of $regSrc with sign-extended imm, setting $regDst to 1 if $regSrc is less than imm, and to 0 otherwise. The comparison performed