490 likes | 520 Views
CMPS 255 Computer Architecture. Introduction to MIPS assembler, Supporting procedure calls and returns & addressing modes Reading - PH: 2.8, 2.9, 2.10. Programming Styles. Procedures ( subroutines , functions ) allow the programmer to structure programs making them
E N D
CMPS 255Computer Architecture • Introduction to MIPS assembler, • Supporting procedure calls and returns & addressing modes • Reading - PH: 2.8, 2.9, 2.10
Programming Styles • Procedures (subroutines, functions) allow the programmer to structure programs making them • easier to understand and debug and • allowing code to be reused • parameters allow the procedure to be passed values (arguments) and to return values (results)
Terminology • Caller: The program that instigates a procedure and provides the necessary parameter values • Callee: A procedure that executes a series of stored instructions based on parameters provided by the caller and then returns control to the caller. • program counter (PC): The register containing the address of the instruction in the program being executed. • stack A data structure for spilling registers organized as a last-in first-out queue. • stack pointer A value denoting the most recently allocated address in a stack that shows where registers should be spilled or where old register values can be found. In MIPS, it is register $sp.
Six Steps in Execution of a Procedure • Main routine (caller) places parameters in a place where the procedure (callee) can access them • $a0 - $a3: four argument registers • Caller transfers control to the callee • Callee acquires the storage resources needed • Callee performs the desired task • Callee places the result value in a place where the caller can access it • $v0 - $v1: two value registers for result values • Callee returns control to the caller • $ra: one return address register to return to the point of origin
jump and link (jal) Instruction • Jump and link (jal) : Single instruction to jump and savereturn address: • jalProcAddress#jump and link • Jumps to ProcAddressandsaves PC+4 in register $raas the link to the following instruction to set up the procedure return • jal should really be called lajfor “link and jump”: • Step 1 (link): Saveaddress of next instruction into $ra • Step 2 (jump): Jump to the given label • Then we can do procedure return with just jr $ra #return
Basic Procedure Flow • For a procedure sum(i,j); that computes the sum of two values i(in $t0)andj(in $t1) • Caller puts the iand j(the parameters values) in $a0and $a1and issues a jal sum#jump to routine sum • Callee computes the sum, puts result in $v0, and returns control to caller using sum: add $v0,$a0,$a1 #code to compute the sum jr $ra #return MIPS Assembly1004 add $a0,$s0,$zero # i: $s01008 add $a1,$s1,$zero # j: $s1 1012jalsum#jump to sum1016 ... 2000sum: add $v0,$a0,$a12004jr $ra
Space for saved procedure information $sp stack pointer Explicitly created space, e.g., malloc(); C pointers Variables declared once per program Code Static Heap Stack Program Spilling Registers • What if the callee needs to use more registers than allocated to argument and return values? • callee can spill registers to stack in memory (a stack is a last-in-first-out queue) • any spilled registers needed by the caller must be restored to the values that they contained before the procedure was invoked Address 0
How registers are spilled to the stack? • A stack needs a pointer to the most recently allocated address in the stack to show where the next procedure should place the registers to be spilled or where old register values are found. • Register$sp ($29),is used to address the stack (which “grows” from high address to low address) • $sp always points to the last used space in the stack • add data onto the stack – push • decrement $sp by the amount of space we need and then fill it with info • $sp = $sp – 4 data on stack at new $sp • remove data from the stack – pop • increment $sp by the amount of space we want to remove • data from stack at $sp : $sp = $sp + 4 high addr top of stack $sp low addr
Compiling a C Leaf Procedure • Leaf procedures are ones that do not call other procedures. • Give the MIPS assembler code for int leaf_ex (int g, int h, int i, int j){ int f; f = (g+h) – (i+j); return f; } where g, h, i, and jare in $a0, $a1, $a2, $a3 leaf_ex: addi $sp, $sp, –12 # adjust stack to make room for 3 items sw $t1, 8($sp) # save register $t1 for use afterwards sw $t0, 4($sp) # save register $t0 for use afterwards sw $s0, 0($sp) # save register $s0 for use afterwards add $t0,$a0,$a1 # register $t0 contains g + h add $t1,$a2,$a3 # register $t1 contains i + j sub $s0,$t0,$t1 # f = $t0 – $t1, which is (g + h)–(i + j) add $v0,$s0,$zero # returns f ($v0 = $s0 + 0) lw $s0, 0($sp) # restore register $s0 for caller lw $t0, 4($sp) # restore register $t0 for caller lw $t1, 8($sp) # restore register $t1 for caller addi $sp,$sp,12 # adjust stack to delete 3 items jr $ra # jump back to calling routine
Compiling a C Leaf Procedure • The values of the stack pointer and the stack (a) before, (b) during, and (c) after the procedure call. • SP always points to the “top” of the stack, or the last word in the stack in this drawing.
Steps and rules for Procedures Steps for Making a Procedure Call 1) Save necessary values onto stack. 2) Assign argument(s), if any. 3) jal call 4) Restore values from stack. • Rules for Procedures • Called with a jalinstruction, returns with a jr $ra • Accepts up to 4 arguments in $a0, $a1, $a2and$a3 • Return value is always in$v0(and if necessary in $v1) • Must follow register conventions(even in functions that only you will call)! So what are they?
Register Conventions • Register Conventions: A set of generally accepted rules as to which registers will changed or unchanged after a procedure call (jal). • $0:No Change. Always 0. • $s0-$s7: Restore if you change. They’re called saved registers. If the callee changes these in any way, it must restore the original values before returning. • $sp: Restore if you change. It must point to the same place before and after thejalcall, or else the caller won’t be able to restore values from the stack. • Volatile registers • $ra: Can Change. The jal call will change this register. • Caller needs to save on stack if nested call. • $v0-$v1: Can Change. These will contain the new returned values. • $a0-$a3: Can change. These are volatile argument registers. • Caller needs to save if they’ll need them after the call. • $t0-$t9: Can change. They’re called temporary: any procedure may change them at any time.
Non-Leaf Procedures (Nested Procedures) • Procedures that call other procedures • What happens to return addresses with nested procedures? • For nested call, caller needs to save on the stack: • Its return address • Any arguments and temporaries needed after the call • Restore from the stack after the call int rt_1 (int i) { if (i == 0) return 0; else return rt_2(i-1); }
Non-Leaf Procedures (Nested Procedures) • Procedures that call other procedure int rt_1 (int i) { if (i == 0) return 0; else return rt_2(i-1); } caller: jal rt_1 next: . . . rt_1: bne $a0, $zero, to_2 add $v0, $zero, $zero jr $ra to_2: addi $a0, $a0, -1 jal rt_2 jr $ra rt_2: . . . • Nested procedures (i passed in $a0, return value in $v0) • On the call to rt_1, the return address (next in the caller routine) gets stored in $ra. • What happens to the value in $ra (when i != 0) when rt_1 makes a call to rt_2?
Non-Leaf Procedures (Nested Procedures) • For nested call, caller needs to save on the stack: • Its return address • Any arguments and temporaries needed after the call • Restore from the stack after the call int rt_1 (int i) { if (i == 0) return 0; else return rt_2(i-1); } high addr caller: jal rt_1 next: . . . rt_1: bne $a0, $zero, to_2 add $v0, $zero, $zero jr $ra to_2: sw $ra, 4($sp) sw $a0, 0($sp) addi $a0, $a0, -1 jal rt_2 bk_2: lw $ra, 4($sp) addi $sp, $sp, 8 jr $ra rt_2: . . . $sp old TOS $sp caller rt addr $sp old $a0 addi $sp, $sp, -8 low addr lw $a0, 0($sp) $ra caller rt addr bk_2 caller rt addr 15
Compiling a Recursive Procedure • A procedure for calculating factorial int fact (int n) { if (n < 1) return 1; else return (n * fact (n-1)); } • A recursive procedure (one that calls itself!) fact (0) = 1 fact (1) = 1 * 1 = 1 fact (2) = 2 * 1 * 1 = 2 fact (3) = 3 * 2 * 1 * 1 = 6 fact (4) = 4 * 3 * 2 * 1 * 1 = 24 . . . • Assumenis passed in $a0; result returned in $v0
Compiling a Recursive Procedure … #caller procedure add $a0, $s1, $0 #n mapped to $s1, passed #to $a0 jal fact … #return address J Exit fact:addi $sp, $sp, -8#adjust stack pointer sw $ra, 4($sp)#save return address sw $a0, 0($sp)#save argument n slti $t0, $a0, 1 #test for n < 1 beq $t0, $zero, L1#if n >=1, go to L1 addi $v0, $zero, 1 #else return 1 in $v0 addi $sp, $sp, 8#adjust stack pointer jr $ra #return to caller (1st) L1: addi $a0, $a0, -1 #n >=1, so decrement n jal fact#call fact with (n-1) #this is where fact returns bk_f:lw $a0, 0($sp)#restore argument n lw $ra, 4($sp)#restore return address addi $sp, $sp, 8#adjust stack pointer mul $v0, $a0, $v0 #$v0 = n * fact(n-1) jr $ra #return to caller (2nd)
A Look at the Stack for $a0 = 2, Part 1 • calling fact(2) from the caller procedure (first encounter with jal and $a0=2) • saved return address to caller routine (i.e., location in the main routine where first call to fact is made) on the stack • saved original value of $a0 on the stack old TOS $sp caller rt addr $sp $a0 = 2 … add $a0, $s1, $0 jal fact …#ret address… fact: addi $sp, $sp, -8 sw $ra, 4($sp) sw $a0, 0($sp) slti $t0, $a0, 1 beq $t0, $zero, L1 addi $v0, $zero, 1 addi $sp, $sp, 8 jr $ra L1: addi $a0, $a0, -1 jal fact #this is where fact returns bk_f: lw $a0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 mul $v0, $a0, $v0 jr $ra $ra caller rt addr $a0 2 $v0
A Look at the Stack for $a0 = 1, Part 1 • Registers $ra after second call to fact (i.e., jal fact in L1) with $a0 now holding 1 old TOS caller rt addr … add $a0, $s1, $0 jal fact …#ret address… fact: addi $sp, $sp, -8 sw $ra, 4($sp) sw $a0, 0($sp) slti $t0, $a0, 1 beq $t0, $zero, L1 addi $v0, $zero, 1 addi $sp, $sp, 8 jr $ra L1: addi $a0, $a0, -1 jal fact #this is where fact returns bk_f: lw $a0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 mul $v0, $a0, $v0 jr $ra $sp $a0 = 2 $ra caller rt addr bk_f 1 $a0 2 return address to location in the main routine where first call to fact is made and original value of $a0 are already saved on the stack $v0
A Look at the Stack for $a0 = 1, Part 2 • Stack state after starting the second execution of fact (after the second encounter with jal and call to fact routine with $a0 = 1) old TOS caller rt addr $sp $a0 = 2 … add $a0, $s1, $0 jal fact …#ret address… fact: addi $sp, $sp, -8 sw $ra, 4($sp) sw $a0, 0($sp) slti $t0, $a0, 1 beq $t0, $zero, L1 addi $v0, $zero, 1 addi $sp, $sp, 8 jr $ra L1: addi $a0, $a0, -1 jal fact #this is where fact returns bk_f: lw $a0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 mul $v0, $a0, $v0 jr $ra bk_f $sp $a0 = 1 $ra bk_f $a0 1 $v0
A Look at the Stack for $a0 = 0, Part 1 • Registers $ra after third call to fact (i.e., jal fact in L1) with $a0 now holding 0 old TOS caller rt addr $a0 = 2 … add $a0, $s1, $0 jal fact …#ret address… fact: addi $sp, $sp, -8 sw $ra, 4($sp) sw $a0, 0($sp) slti $t0, $a0, 1 beq $t0, $zero, L1 addi $v0, $zero, 1 addi $sp, $sp, 8 jr $ra L1: addi $a0, $a0, -1 jal fact #this is where fact returns bk_f: lw $a0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 mul $v0, $a0, $v0 jr $ra bk_f $sp $a0 = 1 $ra bk_f bk_f $a0 1 0 $v0
A Look at the Stack for $a0 = 0, Part 2 • Stack state after starting the Third execution of fact (after the third encounter with jal and call to fact routine with $a0 = 0) old TOS caller rt addr $a0 = 2 … add $a0, $s1, $0 jal fact …#ret address… fact: addi $sp, $sp, -8 sw $ra, 4($sp) sw $a0, 0($sp) slti $t0, $a0, 1 beq $t0, $zero, L1 addi $v0, $zero, 1 addi $sp, $sp, 8 jr $ra L1: addi $a0, $a0, -1 jal fact #this is where fact returns bk_f: lw $a0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 mul $v0, $a0, $v0 jr $ra bk_f $sp $a0 = 1 bk_f $sp $a0 = 0 $ra bk_f $a0 0 $v0
A Look at the Stack when encountering jr • Stack state with the first encounter with the first jr ($v0 initialized to 1) • stack pointer updated to point to third call to fact old TOS caller rt addr $a0 = 2 … add $a0, $s1, $0 jal fact …#ret address… fact:addi $sp, $sp, -8 sw $ra, 4($sp) sw $a0, 0($sp) slti $t0, $a0, 1 beq $t0, $zero, L1 addi $v0, $zero, 1 addi $sp, $sp, 8 jr $ra L1: addi $a0, $a0, -1 jal fact #this is where fact returns bk_f: lw $a0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 mul $v0, $a0, $v0 jr $ra bk_f $sp $a0 = 1 bk_f $sp $a0 = 0 jr $ra $ra bk_f #this is where fact returns $a0 0 $v0 1
A Look at the Stack after encountering jr • Stack state after the first encounter with first jr • return address to caller routine (bk_f in fact routine) restored to $ra from the stack • previous value of $a0 restored from the stack • stack pointer updated to point to second call to fact • $v0 is updated old TOS caller rt addr $a0 = 2 $sp bk_f … add $a0, $s1, $0 jal fact …#ret address… fact:addi $sp, $sp, -8 sw $ra, 4($sp) sw $a0, 0($sp) slti $t0, $a0, 1 beq $t0, $zero, L1 addi $v0, $zero, 1 addi $sp, $sp, 8 jr $ra L1: addi $a0, $a0, -1 jal fact #this is where fact returns bk_f: lw $a0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 mul $v0, $a0, $v0 jr $ra $sp $a0 = 1 bk_f $a0 = 0 $ra bk_f $a0 1 0 $v0 1*1 1
A Look at the Stack after encountering jr • Stack state after the executing the second encounter with jr • return address to caller routine (main routine) restored to $ra from the stack • previous value of $a0 restored from the stack • stack pointer updated to point to first call to fact • $v0 is updated old TOS $sp caller rt addr $a0 = 2 $sp bk_f … add $a0, $s1, $0 jal fact …#ret address… fact:addi $sp, $sp, -8 sw $ra, 4($sp) sw $a0, 0($sp) slti $t0, $a0, 1 beq $t0, $zero, L1 addi $v0, $zero, 1 addi $sp, $sp, 8 jr $ra L1: addi $a0, $a0, -1 jal fact #this is where fact returns bk_f:lw $a0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 mul $v0, $a0, $v0 jr $ra $a0 = 1 bk_f $a0 = 0 $ra bk_f caller rt addr $a0 2 1 $v0 2*1*1 1*1
A Look at the Stack after encountering jr old TOS $sp … add $a0, $s1, $0 jal fact …#ret address … fact:addi $sp, $sp, -8 sw $ra, 4($sp) sw $a0, 0($sp) slti $t0, $a0, 1 beq $t0, $zero, L1 addi $v0, $zero, 1 addi $sp, $sp, 8 jr $ra L1: addi $a0, $a0, -1 jal fact #this is where fact returns bk_f: lw $a0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 mul $v0, $a0, $v0 jr $ra caller rt addr $a0 = 2 bk_f $a0 = 1 bk_f $a0 = 0 $ra bk_f caller rt addr $a0 2 1 $v0 2*1*1 1*1
Allocating Space on the Stack • The segment of the stack containing a procedure’s spilled/savedregisters and local variables (such as the ones that do not fit in registers, i.e., local arrays or structures) is its procedure frame (aka activation record) • Used by some compilers to manage stack storage • The frame pointer ($fp) points to the first word of the frame of a procedure – providing a stable “base” register for the procedure
Allocating Space on the Stack • frame pointer ($fp)points to the first word of the frame, often a saved argument register • stack pointer ($sp) points to the top of the stack. • stack is adjusted to make room for all saved registers and any memory-resident local variables. • Stack pointer may change during program execution, hence it’s easier for programmers to reference variables via the stable frame pointer. • When a frame pointer is used, it is initialized using the address in $sp on a call, and $sp is restored using $fp.
Allocating Space on the Heap • Text: program code • Static data: global variables • e.g., static variables in C, constant arrays and strings • $gp initialized to address to make it easy to access data in this segment • Dynamic data segment (heap) for structures that grow and shrink (e.g., linked lists) • Allocate space on the heap with malloc() in c and free it with free() (by new in Java) • Memory leak: forget to free allocated space • Stack: automatic storage MIPS: • $spis initialized to 7fff fffchexand grows down toward the data segment. • Program code (“text”) starts at 0040 0000hex. • Static data starts at 1000 0000hex. • Dynamic data grows up toward the stack. • $gp, is initialized to 1000 8000hexso that it can access from 1000 0000hex to 1000 ffffhex using the positive and negative 16-bit offsets from $gp.
Beyond Numbers • Representing a string: the first position of the string is reserved to give the length of a string (such as in Java); the last position of a string is indicated by a character used to mark the end of a string such as in C. This, the string “Cal” is represented in C by the following 4 bytes, shown as decimal numbers: 67, 97, 108, 0. • Most computers use 8-bit bytes to represent characters with the American Std Code for Info Interchange (ASCII)
Beyond Numbers • Unicode is a universal encoding of the alphabets of most human languages. there are almost as many alphabets in Unicode as there are useful symbols in ASCII. To be more inclusive, Java uses Unicode for characters. By default, it uses 16 bits to represent a character • Unicode version 4.0 has more than 160 “blocks”. Each block is a multiple of 16. For example, Greek starts at 0370hex, and Cyrillic at 0400hex.
Loading and Storing Bytes • Could use bitwise operations • MIPS byte/halfword load/store: String processing is a common case lb rt, offset(rs) lh rt, offset(rs) • Sign extend to 32 bits in rt lbu rt, offset(rs) lhu rt, offset(rs) • Zero extend to 32 bits in rt sb rt, offset(rs) sh rt, offset(rs) • Store just rightmost byte/halfword • What 8 bits/16 bits get loaded and stored? • load byte/half word places the byte/half word from memory in the rightmost 8 bits /16 bits of the destination register • what happens to the other bits in the register? • store byte/half word takes the byte/half word from the rightmost 8 bits/16 bits of a register and writes it to the byte/half word in memory • leaving the other bytes in the memory word unchanged 33
Example of Loading and Storing Bytes • Given following code sequence and memory state what is the state of the memory after executing the code? add $s3, $zero, $zero lbu $t0, 1($s3) sb $t0, 6($s3) @ Big End MSB LSB @ Little End LSB MSB Memory • What value is left in $t0? 0x 0 0 0 0 0 0 0 0 24 $t0 = 0x00000090 0x 0 0 0 0 0 0 0 0 20 • What word is changed in Memory and to what? 0x 0 0 0 0 0 0 0 0 16 0x 1 0 0 0 0 0 1 0 12 mem(4) = 0xFFFF90FF 0x 0 1 0 0 0 4 0 2 8 • What if the machine was little Endian? 0x F F 1 2 F F F F 90 0x F F F F F F F F 4 $t0 = 0x00000012 0x 0 0 9 0 1 2 A 0 0 mem(4) = 0xFF12FFFF Data Word Address (Decimal) 34 34
String Copy Example • C code (naïve): Null-terminated string void strcpy (char x[], char y[]){ int i; i = 0; while ((x[i]=y[i])!='\0') i += 1;} • Addresses of x, y in $a0, $a1, and value of i in $s0 X[] B C A X[3]=Y[3] X[2]=Y[2] X[1]=Y[1] X[0]=Y[0] \0 C B A Y[3] Y[1] Y[2] Y[0] Register Y[] ABC Memory strcpy:addi $sp,$sp,–4 # adjust stack for 1 more item sw $s0, 0($sp) # save $s0 add $s0,$zero,$zero# i = 0 + 0 L1: add $t1,$s0,$a1 # address of y[i] in $t1 lbu $t2, 0($t1) # $t2 = y[i] add $t3,$s0,$a0 # address of x[i] in $t3 sb $t2, 0($t3) # x[i] = y[i] beq $t2,$zero,L2 # if y[i] == 0, go to L2 addi $s0, $s0,1 # i = i + 1 j L1 # go to L1 L2: lw $s0, 0($sp) # y[i] == 0: end of string. Restore old $s0 addi $sp,$sp,4 # pop 1 word off stack jr $ra # return
32-bit Constants • Most constants are small: 16-bit immediate is sufficient • What if we want to load 0000 0000 1111 1111 0000 1001 0000 00002into a register? we use two instructions: • Load the upper 16 bits using "load upper immediate" instruction : copies 16-bit constant to left 16 bits of rt luirt, constant lui$t0, 255 # 255 decimal = 0000 0000 1111 1111 binary • Then must get the lower order bits right, i.e., clears right 16 bits of rt to 0 ori $t0, $t0, 2304 # 2304 decimal = 0000 1001 0000 0000 $t0 0000 0000 1111 1111 0000 0000 0000 0000 2304 0000 0000 0000 0000 0000 1001 0000 0000 $t0 0000 0000 1111 1111 0000 1001 0000 0000
5 16 17 offset 4 16 17 offset op rs rt 16 bit offset Assembling Branches • Instructions: bne $s0, $s1, Lbl#go to Lbl if $s0$s1 beq $s0, $s1, Lbl#go to Lbl if $s0=$s1 • Machine Formats: • How is the branch destination address specified? I format bne beq
Fetch PC = PC+4 op rs rt 16 bit offset Exec Decode Specifying Branch Destinations • Instruction Address Register (PC = program counter) PC bne $s0,$s1,Lbl1 add $s3,$s0,$s1 • it contains the address of the instruction in the program being executed. • its use is automatically implied by branch • PC gets updated (PC+4) during the Fetch cycle to hold the address of the next instruction Lbl1: ... • PC-relative addressing : Target address = Updated PC + offset × 4 • offset × 4 : concatenate two low-order zeros to make the offset a word address and then sign-extending those 18 bits • Updated PC (i.e., PC+4) is added to the offset × 4 • The result is written into the PC if the branch condition is true - before the next Fetch cycle
op rs rt 16 bit offset ? PC-relative addressing summary Sign bit offset × 4 16 sign-extend offset 00 14 bits branch dst address 32 32 Add PC 32 32 Add 32 4 32 32
2 ???? Assembling Jumps • Unconditional branch instruction or Jump (j and jal) targets could be anywhere in text segment • Encode full address in instruction j Lbl#go to Lbl jalLbl#jump and link J format op 26-bit address j 3 ???? Jal • Pseudo Direct jump addressing: How is the jump destination address formed? • Target address = PC31…28 : (address × 4)
Pseudo Direct jump addressing • Target address = PC31…28 : (address × 4) • Convert the low 26 bits of jump inst into a 32 bit destination address: • address × 4 : concatenating 00 as the 2 low-order bits to make it a word address • Result id an 28 bit (word) address • Concatenating with the 28 bits the upper 4 bits of the updated PC (i.e., PC+4) to create a 32 bit (word) address • Store result in PC op 26-bit address 26 00 32 PC 32 4
Example h in $s3, iin $s0, jin $s1 Assembly: beq $s0, $s1, Else add $s3, $s0, $s1 j ExitElse: sub $s3, $s0, $s1Exit: ... C: if (i!=j) h=i+j; else h=i-j; Machine language: Assume that the addr of the beqinstr is 0x00400020hex 0x00400020 4 16 17 2 + PC 0000 0000 0000 00 00 0000 0000 0000 102 002 Target = + 00400024hex = 00 00 00 08hex = 0040002chex 0x00400024 0 16 17 19 0 0x20 0x00400028 2 0000 0100 0 ... 0 0011 002 0000 0100 0 ... 0 0011 002 (002) (0000) jmp dst = = 0x00400030 0x0040002c 0 16 17 19 0 0x22 0x00400030 ...
Another example Compile the assembly code for the C code . i in $s3, k in $s5 and base of the array save is in $s6 Loop:sll $t1,$s3,2 # Temp reg $t1 = 4 * i add $t1,$t1,$s6 # $t1 = address of save[i] lw $t0,0($t1) # Temp reg $t0 = save[i] bne $t0,$s5, Exit # go to Exit if save[i] ≠ k addi $s3,$s3,1 # i = i + 1 j Loop # go to Loop Exit: while (save[i] == k) i += 1;
Branching Far Away • What if the branch destination is further away than can be captured in 16 bits? • assembler rewrites the code: it inserts an unconditional jump to the branch target and inverts the condition • Example beq $s0, $s1, L1 becomes bne $s0, $s1, L2 j L1 L2: 44
Another Instruction for Changing Flow • Most higher level languages have case or switch statements allowing the code to select one of many alternatives depending on a single value • Instruction: jr $t1 #go to address in $t1 • Machine format: R format op rs funct 0 9 0 0 0 8 = 0x08
Addressing Modes Illustrated mode 1: the operand is 16 bits of the instruction itself. mode 2: the operand is a register mode 3: The operand is in memory (load and store). mode 4: address instructions in memory, adding a 16-bit address shifted left 2 bits to the PC mode 5: address instructions in memory, concatenating a 26-bit address shifted left 2 bits with the 4 upper bits of the PC.
Review: MIPS ISA Registers • Instruction Categories • Load/Store • Computational • Jump and Branch • Floating Point • coprocessor • Memory Management • Special • 3 Instruction Formats: all 32 bits wide R0 - R31 PC HI LO 6 bits 5 bits 5 bits 5 bits 5 bits 6 bits R format OP rs rd shamt funct rt I format rt 16 bit number OP rs J format 26 bit jump target OP