ECE2030 Introduction to Computer Engineering Lecture 19: Program Control Prof. Hsien-Hsin Sean Lee School of Electrical and Computer Engineering Georgia Tech
Program Execution on Processors How a program is executed on a processor? How instructions ordering are maintained? Are there times we need to change the flow of a program? How to handle change of flow of a program?
Program Counter How a sequence of instructions are fetched and executed by a computer? Program Counter (PC) A special register Provide the logical ordering of a program Point to the address of the instruction to be executed main: la $8, array lb $9, ($8) lb $10, 1($8) add $11, $9, $10 sb $11, ($8) addiu $8, $8, 4 lh $9, ($8) lhu $10, 2($8) sh $11, ($8) lw $9, ($8) lw $10, 4($8) sub $11, $9, $10 sw $11, ($8) PC
Program Counter (Little Endian) PC 0x20 0x58 0x2a 0x01 0x00 0x0b 0xa1 0x04 add $11,$9,$10 sb $11, ($8) PC+12 PC+16 PC+20 0x01 main: la $8, array lb $9, ($8) lb $10, 1($8) add $11, $9, $10 sb $11, ($8) addiu $8, $8, 4 lh $9, ($8) lhu $10, 2($8) sh $11, ($8) lw $9, ($8) lw $10, 4($8) sub $11, $9, $10 sw $11, ($8) 0x10 la $8, array 0x08 0x3c 0x00 0x09 0x81 PC+4 lb $9, ($8) 0x01 0x00 0x0a 0x81 PC+8 lb $10, 1($8) Each MIPS instruction is 4-byte wide
Program Counter Control 32 + 32-bit PC Register System clock Instruction Register 32 2kx32 INSTRUCTION MEMORY Data (i.e. instruction) 32 4
Change of Flow Scenarios Our current default mode Program executed in sequential order When a program will break the sequential property? Subroutine Call and Return Conditional Jump (with Test/Compare) Unconditional Jump MIPS R3000/4000 uses Unconditional absolute instruction addressing Conditional relative instruction addressing
Absolute Instruction Addressing The next PC address is given as an absolute value PC address = <given address> Jump class examples J LABEL JAL LABEL JALR $r JR $r
Absolute Addressing Example main: la $8, array lb $9, ($8) lb $10, 1($8) add $11, $9, $10 sb $11, ($8) j Label2 ... Label2: addiu $8, $8, 4 lh $9, ($8) lhu $10, 2($8) Assume no delay slot J Label2 Encoding: Label2=0x00400048 J opcode= (000010)2 Encoding=0x8100012 Temp = <Label2 26-bit addr> PC = PC31..28|| Temp || 02
Relative Instruction Addressing An offset relative to the current PC address is given instead of an absolute address PC address = <current PC address> + <offset> Branch class examples bne $src, $dest, LABEL beq $src, $dest, LABEL bgez $src, LABEL Bltz $src, LABEL Note that there is no blt instruction, that’s why slt is needed. To facilitate the assembly programming, there is a “blt pseudo op” that programmers can use.
Relative Addressing Example la $8, array beq $20, $22, L1 lb $10, 1($8) add $11, $9, $10 sb $11, ($8) L1: addiu $8, $8, 4 Assume no delay slot beq $20,$22,L1 Encoding=0x12960004 (next slide) Target=(offset15)14 || offset || 02 PC = PC + Target
BEQ Encoding (I-Format) rs Offset Value = (Target addr – beq addr)/4 = # of instructions in-between including beq instruction beq $20, $22, L1 rt Branch to L1 if $20==$22 Offset = 4 instructions 1 31 opcode rs rt 26 25 21 20 16 15 Offset Value 1 Encoding = 0x12960004
Relative Addressing Example The offset can be positive as well as negative L2: addiu $20, $22, 4 lw $24, ($22) lw $23, ($20) beq $24, $23, L2 Offset = -3 instructions beq $24, $23, L2 1 31 opcode rs rt 26 25 21 20 16 15 Offset Value 1 Encoding = 0x1317FFFD
MIPS Control Code Example See array.s and prime.s
Procedural Calls in MIPS MIPS uses jal or jalr to perform procedure calls (assume no branch delay slot) jal LABEL # r31 = PC + 4 jal rd, rs # rd = PC + 4 Return address is automatically saved When return from procedure jr $31 or jr $d Note that $31 is aliased to $ra Call convention Use $a0 to $a3 ($4 to $7) for the first 4 arguments Use $v0 ($2) for passing the result back to the caller
Procedural Call Example C code snippet z = pyth(x, y); z = sqrt(z); int pyth(int x, int y) { return(x2+y2); } MIPS snippet la $t0, x la $t1, y lw $a0, ($t0) lw $a1, ($t1) jal pyth add $a0, $v0, $zero jal sqrt la $t2, z sw $v0, ($t2) pyth: mult $a0, $a0 mflo $t0 mult $a1, $a1 mflo $t1 add $v0, $t0, $t1 jr $ra sqrt: …. jr $ra Note that by software convention, $t0 to $t7 are called “caller-saved” registers, i.e. the caller is responsible to back them up before procedure call if they are to be used after the procedure call again
Procedural Call: Recursion MIPS snippet la $t0, x lw $a0, ($t0) jal fact fact: addi $v0, $zero, 1 blt $a0, $v0, L1 addi $a0, $a0, -1 jal fact L1: jr $ra C code snippet z = fact(x); int fact(int n) { if (n < 1) return(1); else return(n * fact(n-1)) } ? $ra ($31) is overwritten and old value is lost
Procedural Call: Many Arguments MIPS snippet la $t0, a lw $a0, 0($t0) lw $a1, 4($t0) lw $a2, 8($t0) lw $a3, 12($t0) lw ???, 16($t0) foo: ... jr $ra C code snippet long a[5]; z = foo(a[0], a[1], a[2], a[3], a[4]); int foo(int t, int u, int v, int w, int x) { return(t+u-v*w+x); } Run out of passing argument registers !
Stack The solution to address the prior 2 problems a LIFO (Last-In First-Out) memory A scratch memory space Typically grow downward (i.e. push to lower address)
Stack Stack Frame Push Pop Base pointed by a special register $sp (=$29) Each procedure has its own stack frame (if stack space is allocated) Push Allocate a new stack frame when entering a procedure subu $sp, $sp, 32 What to store? Return address Additional passing arguments Local variables Pop Deallocate the stack frame when return from procedure addu $sp, $sp, 32
Stack Push New Stack Frame for foo() 4 bytes jal foo higher ... addr subu $sp, $sp, 32 addu $sp, $sp, 32 jr $ra higher addr $sp PUSH New Stack Frame for foo() lower addr
Stack Pop New Stack Frame for foo() 4 bytes jal foo higher ... addr subu $sp, $sp, 32 addu $sp, $sp, 32 jr $ra higher addr Current Stack Frame New Stack Frame for foo() $sp lower addr
Recursive Call MIPS snippet li $v0, 1 j fact fact: beq $a0, $v0, return return: jr $ra C code snippet z = fact(x); int fact(int n) { if (n < 1) return(1); else return(n * fact(n-1)) }
Recursive Call MIPS snippet li $v0, 1 j fact fact: beq $a0, $v0, return jal fact return: jr $ra C code snippet z = fact(x); int fact(int n) { if (n < 1) return(1); else return(n * fact(n-1)) } What to do with $a0 and $ra ?
Push onto the Stack MIPS snippet li $v0, 1 j fact fact: beq $a0, $v0, return sub $sp, $sp, 8 sw $ra, 4($sp) sw $a0, 0($sp) sub $a0, $a0, 1 jal fact return: jr $ra C code snippet z = fact(x); int fact(int n) { if (n < 1) return(1); else return(n * fact(n-1)) } What happens after returning from the procedure ??? $sp Return address $a0 (= X)
Pop from the Stack MIPS snippet li $v0, 1 j fact fact: beq $a0, $v0, return sub $sp, $sp, 8 sw $ra, 4($sp) sw $a0, 0($sp) sub $a0, $a0, 1 jal fact lw $a0, 0($sp) lw $ra, 4($sp) mult $a0, $v0 mflo $v0 add $sp, $sp, 8 return: jr $ra C code snippet z = fact(x); int fact(int n) { if (n < 1) return(1); else return(n * fact(n-1)) } Return address $a0 (= X) $sp
Recursive call for Factorial MIPS snippet li $v0, 1 j fact fact: beq $a0, $v0, return sub $sp, $sp, 8 sw $ra, 4($sp) sw $a0, 0($sp) sub $a0, $a0, 1 jal fact lw $a0, 0($sp) lw $ra, 4($sp) mult $a0, $v0 mflo $v0 add $sp, $sp, 8 return: jr $ra C code snippet z = fact(x); int fact(int n) { if (n < 1) return(1); else return(n * fact(n-1)) }