Chapter 3 Instructions CS 447 Jason D Bakos
Chapter 3: Instructions CS 447 Jason D. Bakos 1
Assembly Language Instructions • We’re going to use the MIPS R 2000 instruction set for the projects in this course • Review: Assembly language instructions are English words that represent binary machine language instructions 2
Arithmetic/Logical Instructions • Arithmetic instructions are composed of an operation and three registers – <op> <destreg> <operand 1> <operand 2> – There are 32 32 -bit general-purpose integer registers that we can use (R 0 is hardwired to value 0 for A/L operands) – Ex: add $1, $2, $3 • When writing assembly language programs, comments can be added after any instruction by using the ‘#’ character • Some architectures only use 2 registers – The result is stored in the first operand register – Some of our instructions will use this convention • Appendix A in the textbook lists all 3
Immediate Arithmetic/Logical Instructions • Most arithmetic/logical instructions have an “immediate” version – Immediate instructions have an ‘i’ at the end of the instruction name – Immediate instructions allow us to specify an immediate/constant/literal in lieu of a register operand – Ex: add $1, $2, 16 – We only have 16 -bits for the immediate, so we can only represent 216 unique values – Use decimal numbers for the immediate value in the assembly-language instruction 4
A/R Instructions • MIPS R 2000 A/L-instructions (complete) – – – – – add, addu, addiu and, andi div, divu (two registers) mult, multu (two registers) nor or, ori sll, sllv, srav, srlv sub, subu xor, xori 5
Pseudoinstructions • Pseudoinstructions are assembled into more than 1 machine instruction – There’s no real machine instruction for them – Ex. abs rdest, rsrc – Assembles into three instructions • move the contents of rsrc into rdest • if rdest is greater than 0, skip over the next instruction – We haven’t covered conditional branches yet • subtract rdest from 0 – Appendix A specifies which are pseudoinstructions 6
Design Considerations • Making most arithmetic instructions have 3 operands simplifies the hardware – This is a design decision – Having a variable number of operands would greatly complicate the hardware • Limiting ourselves to 32 registers is also a design decision to keep things on the processor die smaller – Influences clock cycle time – Gives us more real estate for other things on our core • Less registers, less decoding logic, etc. 7
Registers • MIPS assembly language also has symbolic names for the registers – $0 => constant 0 – $1 => $at (reserved for assembler) – $2, $3 => $v 0, $v 1 (expression evaluation and results of a function) – $4 -$7 => $a 0 -$a 3 (arguments 1 -4) – $8 -$15 => $t 0 -$t 7 (temporary values) • Used when evaluating expressions that contain more than two operands (partial solutions) • Not preserved across function calls – $16 -$23 => $s 0 ->$s 7 (for local variables, preserved across function calls) – $24, $25 => $t 8, $t 9 (more temps) – $26, $27 => $k 0, $k 1 (reserved for OS kernel) – $28 => $gp (pointer to global area) – $29 => $sp (stack pointer) – $30 => $fp (frame pointer) – $31 => $ra (return address, for branch-and-links) 8
Memory and Load/Store Instructions • As we’ve already seen, a processor can only use data stored in its registers as operands and targets for computation • Typically, before computation can be performed, data must be loaded from main memory • After the computation is complete, the results must be stored back to main memory 9
Memory • Computer memory is byte-addressed but the MIPS architecture requires alignment of loads and stores on the 32 -bit (4 byte/word) boundary – This means that all memory references must be an even multiple of 4 • When addressing 4 -byte words, you need to provide the address of the lowest-addressed byte in the word 10
Load/Store Instructions • Most commonly used: – lw, sw, lh, sh, lb, sb, la • Use: – lw <rdest>, address – address can be represented as: • symbolic address (that you declare in SPIM) • symbolic address with register index • decimal_offset($basereg) – This is the way that the instruction is translated – loads/stores from contents of $basereg+decimal_offset 11
Load/Store Instructions • SPIM treats loads and stores with symbolic addresses as pseudoinstructions – loads the address of the data segment as an immediate into $1 • lui $1, 4097 – data starts at hex address 10010000 – If an index register is provided, adds the contents of the index reg to $1 • addu $1, rindex – loads 0($1) into rdest • lw rdest, offset_of_variable($1) • This is an example of base-displacement addressing • This is why R 1 is reserved when you write your programs 12
Load/Store Instructions • When loading or storing halfwords and bytes, the address points to a aligned word – The halfword would be the LOWER (least significant) halfword of the word that the address is pointing to – The byte world be the LOWEST (least significant) byte of the word being that the address is pointing to 13
Constant-Manipulating Instructions • lui rt, imm – Load the immediate imm into the upper halfword of register rt – The lower bits are set to 0 • li rt, imm – Load the imm into the lower halfword of register rt – The upper bits are set to 0 14
Encoding Instructions • The MIPS architecture has a 32 -bit binary instruction format for each class of instruction – A/L, constant manip, comparison, branch, jump, load/store, data movement, floating-point • Even though we’ve only covered 3 of these classes, let’s look at how we encode the instructions we’ve learned… 15
Encoding/Translating A/L Instructions • First (most significant, left-most) 6 bits of ALL instructions is the opcode – The opcode defines the instruction – Doesn’t this only give us 26=64 different instructions? • Yes! But all A/L instructions, excluding the ones which have immediates, has an opcode of 0 but has a 6 -bit field at the end of the instruction that specifies the operation 16
Encoding/Translating A/L Instructions • Non-immediate A/L instructions: – – – 6 5 5 6 bits bits – – – opcode (usually 0) rs (operand 1) rt (operand 2) rd (destination) 0’s or shift amount operation code 17
Encoding/Translating A/L Instructions • Immediate A/L instructions – – 6 bits – opcode (now unique) 5 bits – rs (operand 1) 5 bits – rt (destination) 16 bits – immediate (understood to be 0 extended) 18
Encoding/Translating Load/Store Instructions • 6 bits – opcode • 5 bits – rs (base register) • 5 bits – rt (load from/store to) – Sometimes the whole register isn’t used • Half words and bytes • 16 bits – offset 19
Encoding/Translating Constant-Manip. Instructions • 6 bits – opcode • 5 bits – 0’s • 5 bits – rt dest. register – Half of this register will be assigned 0’s • 16 bits – immediate 20
Examples • Let’s compile the following C++ code segment into assembly code: – z=(a*b)+(c/d)-(e+f*g); – lw $s 0, a lw $s 1, b mult $s 0, $s 1 mflo $t 0 # new instruction lw $s 0, c lw $s 1, d div $s 0, $s 1 mflo $t 1 add $t 0, $t 1 lw $s 0, e lw $s 1, f lw $s 2, g mult $s 1, $s 2 mflo $t 1 add $t 1, $s 0, $t 1 sub $t 0, $t 1 sw $t 0, z 21
Examples • Note: There were many ways we could have compiled the C++ statement • Now let’s assemble the first three instructions to machine code – Assume the variables are all stored as words and are stored sequencially, starting with a, from the start of the data segment… 22
Examples • lw $s 0, a – We know s 0 is $16 – There a few different ways we can do this, too… – First, we need to convert this instruction to a small series of instructions… – lui $1, 4097 # 4097 is 1001 in hex lw 16, 0($1) # 0 offset because a is first var … 00111100000100000001 => 3 C 011001 1000110000000000000 => 8 C 100000 23
Examples • mult $s 0, $s 1 – 0000001000100000011000 => 02110018 24
Branch/Jump Instructions • • Branch and jump instructions are needed for program control – if-statements (conditionals) – loops – procedure calls Most common: – b <label> -- unconditional branch • label is a memory address (we can be symbolic ones, of course) – beq, bgezal, bgtz, blez, etc. • Conditional branches, where we’re comparing a register to 0 or two registers to determine if we’re going to branch or not • Also have al (and-link) variants, that link a return address (instruction following branch) into $31 so we can return • Branch targets are 16 -bit immediate offset – offset in words… it is shifted to the left 2 bits to get byte length 25
Branch/Jump Instructions – j, jal • Unconditionally branches to a 26 -bit pseudodirect address (not offset) – jalr, jr • Unconditionally branches to an address stored in a register 26
Encoding/Translating Branch/Jump Instructions • See Appendix A – These are very similar to the encoding we covered before 27
Data Movement and Comparison Instructions and Their Encoding • I’m going to leave the study of these instructions (from Appendix A) up to you as an exercise! 28
Examples • if ((a>b)&&(c=d)) e=0; else e=f; lw $s 0, a next 0: nope: yup: out: lw $s 1, b bgt $s 0, $s 1, next 0 b nope lw $s 0, c lw $s 1, d beq $s 0, $s 1, yup lw $s 0, f sw $s 0, e b out xor $s 0, $s 0 sw $s 0, e … 29
Examples • Again, there are many other ways we could have tackled this… • You will eventually come up with your own strategies for “compiling” the types of constructs you want to perform… 30
Examples • How about a for loop? • for (i=0; i<a; i++) b[i]=i; lw $s 0, a xor $s 1, $s 1 loop 0: blt $s 1, $s 0, loop 1 b out sll $s 2, S 1, 2 loop 1: sw $s 1, b($s 2) addi $s 1, 1 b loop 0 out: … 31
Examples • How about a pretest while loop? • while (a<b) { a++; } loop 0: loop 1: out: lw $s 0, a lw $s 1, b blt $s 0, $s 1, loop 1 b out addi $s 0, Ss 0, 1 sw $s 0, a b loop 0 … 32
Examples • How about a posttest while loop? • do { a++; } while (a<b); lw $s 0, a lw $s 1, b loop 0: addi $s 0, 1 sw $s 0, a blt $s 0, $s 1, loop 0 … 33
Procedure Calls • How about a procedure call? – The full-blown C/Pascal recursive procedure call convention is beyond the scope of this class, so we’ll skip it for now… – This is described in detail in Appendix A • You can arbitrarily implement your own procedure call convention… 34
Procedure Calls • Say we want to write a procedure that computes the factorial of a number, like this: int factorial (int val) { int temp=val; while (val) temp*=(--val); return temp; } 35
Procedure Calls • Let’s adopt the following simple convention: – We’ll pass the arguments through $a 0 -$a 3 • Only allows for up to 4 arguments – We’ll set our return value in $v 0 – The return address will be stored in $ra • This limits us to 1 -level of procedure calls – We’ll assume the callee (procedure) will save registers $s 0 -$s 7 starting at memory address FF 000000 when it’s called, and restore the registers before it returns • This may not be necessary for all procedures 36
Procedure Calls • So here’s our procedure… factorial: loop 0: loop 1: out: lui $t 1, 0 x. FF 00 sw $s 0, 0($t 1) sw $s 1, 4($t 1) … sw $s 7, 28($t 1) move $s 0, $a 0 move $s 1, $a 0 bgtz $s 0, loop 1 b out mult $s 0, $s 1 mflo $s 1 subi $s 0, 1 b loop 0 move $v 0, $s 1 lw $s 0, 0($t 1) … jr $31 # new instruction # load back registers 37
Procedure Calls • In order to call our procedure… – load a value into $a 0 – bal factorial – look in $v 0 for the result! 38
I/O • Doing I/O with SPIM is also described in Appendix A, but we’re going to use the system calls that are set up for us to do I/O… 39
I/O • SPIM provides some operating system services through the syscall instruction • To use the system calls: – load system call code (from pg. a 49) into $v 0 and argument into $a 0… – return values in $v 0 (or $f 0 for fp results) 40
Example I/O str: . asciiz “the answer = “. text li $v 0, 4 la $a 0, str syscall li $v 0, 1 la $a 0, 5 syscall (Refer to page A-49) 41
- Slides: 41