ELO311 Estructuras de Computadores Digitales Operaciones MIPS para Control de flujo Tomás Arredondo Vidal Este material está basado en: material de apoyo del texto de David Patterson, John Hennessy, "Computer Organization & Design", (segunda y tercera edición), Morgan Kaufmann, CA. 2005 material del curso anterior ELO311 del Prof. Leopoldo Silva material del curso CSE331 de Mary Jane Irving de Penn State www.wikipedia.org
Repaso: Representación Binaria con Signo 1011 y sumar un 1 1010 complementar los bits 2 sc binary decimal -2 3 = 1000-8 -(2 3-1) = 1001-7 1010-6 1011-5 1100-4 1101-3 1110-2 1111-1 0000 0 0001 1 0010 2 0011 3 0100 4 0101 5 0110 6 2 3-1 = 0111 7
Repaso: Organización MIPS Instrucciones aritméticas hacia/desde register file Instrucciones load/store hacia/desde memoria Processor Memory 1 1100 src1 addr 5 src2 addr 5 dst addr 5 write data Register File registers ($zero - $ra) bits src1 data src2 data read/write addr read data write data ALU 7 6 5 4 3 2 1 0 byte address (little Endian) bits 0 1100 0 1000 0 0100 0 0000 2 30 words word address (binary)
Repaso: Instrucciones MIPS Hasta Ahora Category Instr Op Code Example Meaning Arithmetic add 0 and add $s1, $s2, $s3 $s1 = $s2 + $s3 (R format) subtract 0 and 34 sub $s1, $s2, $s3 $s1 = $s2 - $s3 Data load word 35 lw $s1, 100($s2) $s1 = Memory($s2+100) transfer store word 43 sw $s1, 100($s2) Memory($s2+100) = $s1 (I format) load byte lb $s1, 101($s2) $s1 = Memory($s2+101) store byte 40 sb $s1, 101($s2) Memory($s2+101) = $s1
Instrucciones para Toma de Decisiones Instrucciones para Toma de Decisiones alterar el flujo de control e.g., cambiar la próxima instrucción a ser ejecutada Bifurcaciones condicionales (conditional branch): bne $s0, $s1, Label beq $s0, $s1, Label #go to Label if $s0 $s1 #go to Label if $s0=$s1 Ejemplo: if (i==j) h = i + j; bne $s0, $s1, Lab1 add $s3, $s0, $s1 Lab1:...
Múltiples Bifurcaciones (Branches) Instrucciones: bne $s0, $s1, Label beq $s0, $s1, Label Formato del lenguaje de máquina: #go to Label if $s0 $s1 #go to Label if $s0=$s1 op rs rt 16 bit number I format 5 16 17???? 4 16 17???? Como se especifica la dirección destino de la bifurcación?
Especificando el Destino de Bifurcaciones Se podría especificar la dirección en memoria pero eso requeriria todos los bits de la instruccion Podría usar un registro y sumarlo a un valor agregado (offset) de 16 bits PC Lab1: bne $s0,$s1,lab1 add $s3,$s0,$s1... cual registro? Registro de dirección de instrucciones (PC = program counter) Su uso esta automáticamente implicado por la instrucción PC se actualiza (PC+4) durante el ciclo de lectura (fetch) asi que contiene la dirección de la próxima instrucción Limita la distancia de una bifurcación a -2 15 a +2 15-1 instrucciones desde la instrucción, pero La mayoría de las bifurcaciones son locales - principio de localidad (principle of locality)
Desensamblar Destinos de Bifurcaciones Los contenidos del PC actualizado (PC+4) se suman a los 16 bits bajos de la instrucción de branch que se convierte en un valor de bits vía Concatenar dos ceros para crear un numero de 18 bits Extender el signo de esos 18 bits El resultado se escribe en el PC si es que el resultado del condición de bifurcación es verdad antes que el ciclo de lectura de la próximo instrucción (Fetch cycle) from the low order 16 bits of the branch instruction sign-extend 16 offset 00 PC 4 Add Add branch dst address?
Ejemplo de Bifurcaciones Código assembler bne $s0, $s1, Lab1 add $s3, $s0, $s1 Lab1:... Formato de máquina de bne: op rs rt 16 bit offset I format Recordar 5 16 17 Después de que bne se lee, el PC se actualiza para apuntar a la instrucción add (PC = PC + 4). Dos ceros se concatenan al numero de offset y ese valor se suma al PC actualizado
Ejemplo de Bifurcaciones Código assembler bne $s0, $s1, Lab1 add $s3, $s0, $s1 Lab1:... Formato de máquina de bne: op rs rt 16 bit offset I format Recordar 5 16 17 1 Después de que bne se lee, el PC se actualiza para apuntar a la instrucción add (PC = PC + 4). Dos ceros se concatenan al numero de offset y ese valor se suma al PC actualizado
Repaso: Organización MIPS Instrucciones aritméticas hacia/desde register file Instrucciones load/store hacia/desde memoria Processor Memory 1 1100 src1 addr 5 src2 addr 5 dst addr 5 write data Register File registers ($zero - $ra) bits src1 data src2 data read/write addr read data write data ALU 7 6 5 4 3 2 1 0 byte address (little Endian) bits 0 1100 0 1000 0 0100 0 0000 2 30 words word address (binary)
Otra Instrucción para Cambio de Flujo MIPS tiene también una instrucción para bifurcación incondicional o salto (jump): Ejemplo: j label #go to label if (i!=j) h=i+j; else h=i-j; beq $s0, $s1, Lab1 add $s3, $s0, $s1 j Lab2 Lab1: sub $s3, $s0, $s1 Lab2:...
Código Assembler de Saltos (jumps) Instrucción: j label #go to label Formato de máquina : op 26-bit address J format 2???? Como se especifica las dirección del salto? Como una dirección absoluta formada al Concatenar los 4 bits altos del PC actual (PC+4) a la dirección de 26 bits y Concatenar 00 como los 2 bits bajos
Desensamblar Destinos de Saltos Los 26 bits de la instrucción se convierten en una instrucción de salto de bits al Concatenar dos ceros para crear una dirección de 28 bit y Concatenar los 4 bits superiores del PC actual (PC+4) Los bits se ponen en el PC antes que el próximo ciclo de lectura de instrucción (Fetch cycle) from the low order 26 bits of the jump instruction 26 00 PC
Ensamblar Bifurcaciones y Saltos Ensamblar el código de maquina MIPS de la siguiente secuencia. Asuma que la dirección de la instrucción beq es 0x00400020 beq $s0, $s1, Lab1 add $s3, $s0, $s1 j Lab2 Lab1: sub $s3, $s0, $s1 Lab2:...
Ensamblar Bifurcaciones y Saltos Ensamblar el código de maquina MIPS de la siguiente secuencia. Asuma que la dirección de la instrucción beq es 0x00400020 beq $s0, $s1, Lab1 add $s3, $s0, $s1 j Lab2 Lab1: sub $s3, $s0, $s1 Lab2:... 0x00400020 4 16 17 2 0x00400024 0 16 17 19 0 0x00400028 2 0000 0100 0... 0 0011 00 2 jmp dst = (0x0) 0x040003 00 2 (00 2 ) = 0x00400030 0x0040002c 0 16 17 19 0 34 0x00400030...
Compilando Instrucciones con While Compile el código assembly para las instrucciones en C donde i esta en $s0, j en $s1, y k en $s2 while (i!=k) i=i+j;
Compilando Instrucciones con While Compile el código assembly para las instrucciones en C donde i esta en $s0, j en $s1, y k en $s2 while (i!=k) i=i+j; Loop: beq $s0, $s2, Exit add $s0, $s0, $s1 j Loop Exit:...
Otras Instrucciones para Tomar Decisiones Tenemos beq, bne, pero falta branch si menor que Nueva instrucción: slt $t0, $s0, $s1 # if $s0 < $s1 # then # $t0 = 1 # else # $t0 = 0 Formato de máquina: op rs rt rd funct 0 16 17 8 0 42 = 0x2a 2
Otras Instrucciones para Bifurcaciones Se puede usar slt, beq, bne, y el valor fijo de 0 en el registro $zero para crear otras condiciones less than blt $s1, $s2, Label less than or equal to greater than greater than or equal to ble $s1, $s2, Label bgt $s1, $s2, Label bge $s1, $s2, Label Como seudo instrucciones son reconocidas y expandidas por el ensamblador (macros) El ensamblador usa un registro reservado ($at)
Otras Instrucciones para Bifurcaciones Se puede usar slt, beq, bne, y el valor fijo de 0 en el registro $zero para crear otras condiciones less than blt $s1, $s2, Label slt $t0, $s1, $s2 #$t0 set to 1 if bne $t0, $zero, Label # $s1 < $s2 less than or equal to greater than greater than or equal to ble $s1, $s2, Label bgt $s1, $s2, Label bge $s1, $s2, Label Como seudo instrucciones son reconocidas y expandidas por el ensamblador (macros) El ensamblador usa un registro reservado ($at)
Otra Instrucción para Cambio de Flujo Muchos lenguajes tienen un comando como case o switch que permiten al código seleccionar una de muchas alternativas dependiendo de un valor. Instrucción: jr $t1 #go to address in $t1 Machine format: op rs funct 0 9 0 0 0 8 = 0x08 2
Compilando un comando Case (Switch) switch (k) { case 0: h=i+j; break; /*k=0*/ case 1: h=i+h; break; /*k=1*/ case 2: h=i-j; break; /*k=2*/ Asumiendo que las direcciones L0, L1, L2 estan en tres palabras secuénciales en memoria comenzando por la dirección en $t4 y k esta en $s2 add $t1, $s2, $s2 #$t1 = 2*k add $t1, $t1, $t1 #$t1 = 4*k add $t1, $t1, $t4 #$t1 = addr of JT[k] lw $t0, 0($t1) #$t0 = JT[k] jr $t0 #jump based on $t0 L0: add $s3, $s0, $s1 #k=0 so h=i+j j Exit L1: add $s3, $s0, $s3 #k=1 so h=i+h j Exit L2: sub $s3, $s0, $s1 #k=2 so h=i-j Exit:... $t4 Memory L0 L1 L2
Resumen: Instrucciones MIPS hasta ahora Category Instr Op Code Example Meaning Arithmetic add 0 and add $s1, $s2, $s3 $s1 = $s2 + $s3 (R format) subtract 0 and 34 sub $s1, $s2, $s3 $s1 = $s2 - $s3 Data load word 35 lw $s1, 100($s2) $s1 = Memory($s2+100) transfer store word 43 sw $s1, 100($s2) Memory($s2+100) = $s1 (I format) load byte store byte 40 lb $s1, 101($s2) sb $s1, 101($s2) $s1 = Memory($s2+101) Memory($s2+101) = $s1 Cond. Branch br on equal br on not equal 4 5 beq $s1, $s2, L bne $s1, $s2, L if ($s1==$s2) go to L if ($s1!=$s2) go to L set on less than 0 and 42 slt $s1, $s2, $s3 if ($s2<$s3) $s1=1 else $s1=0 Uncond. Jump jump jump register 2 0 and 8 j 2500 jr $t1 go to 10000 go to $t1
Programación con Procedimientos Procedimientos (funciones) permiten al programador estructurar sus programas haciéndolos mas fácil para entender, depurar y permitiendo que el código sea reutilizado Procedimientos permiten al programador concentrarse en una porción del código a la vez parámetros le permiten a la función que se le pase valores (argumentos) y retornar valores (resultados) Procedimientos terminales (Leaf) no llaman a otros procedimientos.
Pasos en la Ejecución de un Procedimiento Rutina main llama (caller) y pone parámetros en un lugar en el cual la rutina llamada (callee) los puede obtener $a0 - $a3: cuatro registros para argumentos/parámetros Rutina que llama transfiere control a la rutina llamada Rutina llamada adquiere el almacenamiento necesario Rutina llamada ejecuta tareas Rutina llamada pone los valores de resultados en un lugar en el cual la rutina llamante los puede leer $v0 - $v1: dos registros usados para valores de resultados Rutina llamada retorna control a la rutina llamante $ra: un registro de dirección para retornar al punto de origen
Instrucción para Llamar a un Procedimiento Instrucción MIPS para llamar un procedimiento: jal ProcedureAddress #jump and link Guarda PC+4 en registro $ra para tener un enlace a la siguiente instrucción cuando se retorne del procedimiento Formato de maquina: op 26 bit address J format 3???? Para retornar del procedimiento solo hay que hacer: jr $ra #return
Registros de Desborde (Spilling Registers) Que pasa si el callee necesita usar mas registros que los que hay para argumentos ($a0 - $a3)? Usa un stack una cola LIFO high addr low addr top of stack $sp Uno de los registros generales, $sp, se usa para controlar el stack (el cual crece de direcciones altas a bajas) Sumar datos al stack push $sp = $sp 4 poner datos en stack en nuevo $sp Sacar datos del stack pop sacar datos del stack en $sp $sp = $sp + 4
De Utilidad: Suma inmediata y Multiplicación Instrucción MIPS para sumar valores inmediatos: addi $sp, $sp, 4 #$sp = $sp + 4 addi $sp, $sp, -4 #$sp = $sp - 4 Otra versión de add en el cual un operando es una constante MIPS seudo-instrucción para multiplicar: mul $v0, $a0, $v0 #$v0 = $a0 * $v0
Ejemplo: Procedimientos Enlazados Si main llama a rt_1, que pasa con la dirección de retorno a main (en $ra) si rt_1 hace una llamada a rt_2? void main(void) {... rt_1(n)... } int rt_1 (int i) { if (i == 0) return 0; else return rt_2(i-1); }
Ejemplo: Procedimientos Enlazados (cont) Procedimientos enlazados (parámetros i de rt_1 se pasa en $a0, valor de retorno en $v0, TOS es Top of Stack) old TOS high addr $sp low addr $ra rt_1: bne $a0, $zero, to_2 add $v0, $zero, $zero jr $ra to_2: addi $sp, $sp, -8 sw $ra, 4($sp) sw $a0, 0($sp) addi $a0, $a0, -1 jal rt_2 bk_2: lw $a0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 jr $ra Dirección de retorno y argumentos se almacenan en el stack
Ejemplo: Procedimientos Enlazados (cont) Procedimientos enlazados (i en $a0, returno en $v0) next old $a0 next bk_2 old TOS high addr $sp $sp low addr $ra main: next: jal rt_1 rt_1: bne $a0, $zero, to_2 add $v0, $zero, $zero jr $ra to_2: addi $sp, $sp, -8 sw $ra, 4($sp) sw $a0, 0($sp) addi $a0, $a0, -1 jal rt_2 bk_2: lw $a0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 jr $ra Dirección de retorno y argumentos se almacenan en el stack
Ejemplo: Procedimientos Enlazados (cont) Procedimientos enlazados (i en $a0, returno en $v0) next old $a0 bk_2 next old TOS high addr $sp $sp low addr $ra rt_1: bne $a0, $zero, to_2 add $v0, $zero, $zero jr $ra to_2: addi $sp, $sp, -8 sw $ra, 4($sp) sw $a0, 0($sp) addi $a0, $a0, -1 jal rt_2 bk_2: lw $a0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 jr $ra Dirección de retorno y argumentos se almacenan en el stack
Compilando un Procedimiento Recursivo Calculando un factorial: int fact (int n) { if (n < 1) return 1; else return (n * fact (n-1)); } Procedimiento Recursivo (uno que se llama a si mismo) 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... Asuma que n se pasa en $a0; resultado retornado en $v0
Compilando un Procedimiento Recursivo fact: addi $sp, $sp, -8 #adjust stack pointer sw $ra, 4($sp) #save return address sw $a0, 0($sp) #save argument n slt $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 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
Ejemplo: Una Mirada al Stack old TOS main rt addr 2 $sp $ra $a0 Ejemplo: Asuma que main( ) llamo fact(2) Estado del stack después de la ejecución de la llamada a la rutina fact con $a0 conteniendo un 2 tiene dirección de retorno (return address) a la rutina llamante (caller) (i.e., ubicación en rutina main despues del jal donde se hizo la primera llamada) en $ra tiene parametro (2) en $a0 $v0
Ejemplo: Una Mirada al Stack (cont) old TOS main rt addr $a0 = 2 main rt bk_faddr 21 $sp $sp $ra $a0 Ejemplo: Asuma que fact(2) llamo fact(1) Estado del stack después de la ejecución de la instrucción jal (segunda llamada a la rutina fact con $a0 conteniendo un 1) tiene dirección de retorno (return address) a la rutina llamante (caller) (i.e., ubicación en rutina main despues del jal donde se hizo la primera llamada) en el stack tiene valor original de $a0 en el stack $v0
Ejemplo: Una Mirada al Stack (cont) old TOS main rt addr $a0 = 2 bk_f $a0 = 1 bk_f 10 $sp $sp $ra $a0 Ejemplo: Asuma que fact(1) llamo fact(0) Estado del stack después de la ejecución de la instrucción jal (tercera llamada a la rutina fact con $a0 conteniendo un 0) tiene dirección de retorno (return address) a la rutina llamante (caller) (i.e., ubicación en rutina fact después del jal) en el stack tiene valor original de $a0 en el stack $v0
Ejemplo: Una Mirada al Stack (cont) old TOS main rt addr $a0 = 2 bk_f $a0 = 1 bk_f $a0 = 0 $sp $sp Ejemplo: Se ejecuta jr en fact(0) Estado del stack después de la ejecución de la primera instrucción jr de retorno ($v0 es 1) el puntero al stack apunta a la tercera llamada a fact bk_f $ra 0 $a0 1 $v0
Ejemplo: Una Mirada al Stack (cont) old TOS main rt addr $a0 = 2 bk_f $a0 = 1 bk_f $a0 = 0 bk_f 01 $sp $sp $ra $a0 Ejemplo: Se ejecuta jr en fact(1) Estado del stack después de ejecución de la segunda instrucción jr (retorno de rutina fact después de actualizar $v0 a 1 * 1) dirección de retorno a rutina llamante (bk_f en rutina fact) se repone en $ra del stack valor previo de $a0 se repone del stack puntero de stack apunta a la segunda llamada a fact 1 * 1 1 $v0
Ejemplo: Una Mirada al Stack (cont) old TOS main rt addr $a0 = 2 bk_f $a0 = 1 bk_f $a0 = 0 main bk_f rt addr 12 $sp $sp $ra $a0 Ejemplo: Se ejecuta jr en fact(2) Estado del stack después de ejecución de la segunda instrucción jr (retorno de rutina fact después de actualizar $v0 a 1 * 1 * 2) dirección de retorno a rutina llamante (main) se repone a $ra del stack valor original de $a0 se repone del stack puntero del stack stack apunta a posición original 1 1 * * 1 1* 2 $v0
Repaso: MIPS R3000 ISA Categorías Leer/Guardar (Load/Store) Aritméticas (Computational) Jump and Branch Punto Flotante (Floating Point) coprocessador Memory Management Special Registers R0 - R31 PC HI LO 3 Formatos: todos de bits 6 bits 5 bits 5 bits 5 bits 5 bits 6 bits OP rs rt rd shamt funct OP rs rt 16 bit number R format I format OP 26 bit jump target J format
Registros MIPS Nombre $zero $v0 - $v1 $a0 - $a3 $t0 - $t7 $s0 - $s7 $t8 - $t9 $gp $sp $fp $ra Numero Registro 0 2-3 4-7 8-15 16-23 24-25 28 29 30 31 Uso the constant 0 returned values arguments temporaries saved values temporaries global pointer stack pointer frame pointer return address Debe preservar en llamada? n.a. no no no yes no yes yes yes yes
Repaso: Instrucciones MIPS Hasta Ahora Category Instr Op Code Example Meaning Arithmetic add 0 and add $s1, $s2, $s3 $s1 = $s2 + $s3 (R format) subtract 0 and 34 sub $s1, $s2, $s3 $s1 = $s2 - $s3 Data load word 35 lw $s1, 100($s2) $s1 = Memory($s2+100) transfer store word 43 sw $s1, 100($s2) Memory($s2+100) = $s1 (I format) load byte store byte 40 lb $s1, 101($s2) sb $s1, 101($s2) $s1 = Memory($s2+101) Memory($s2+101) = $s1 Cond. Branch br on equal br on not equal 4 5 beq $s1, $s2, L bne $s1, $s2, L if ($s1==$s2) go to L if ($s1!=$s2) go to L set on less than 0 and 42 slt $s1, $s2, $s3 if ($s2<$s3) $s1=1 else $s1=0 Uncond. Jump jump jump register 2 0 and 8 j 2500 jr $t1 go to 10000 go to $t1 jump and link 3 jal 2500 go to 10000; $ra=pc+4