Modos de Direccionamiento+ Diseño de ISA Organización del Computador 1 Verano 2016 Repaso • Vimos que una instrucción se compone de • • OpCode • Fuente/s • Destino/s CodOp Fuente/s ¿Qué pueden ser estas Fuentes y Destinos? • Constantes • Registros • Direcciones de memoria Destino/s Repaso • ¿Qué representan? • Constantes • Referencias a variables • Referencias a arreglos (arrays) • Referencias a sub-rutinas. • Estructuras de datos (listas, colas, etc.) Modos de Direccionamiento (Parte 1) Modos de direccionamiento • Del hecho de usar distintos tipos de operandos surge la idea de tener distintos modos de direccionamiento • Es decir, distintas formas posibles de acceder a los operandos (y además, optimizar la ejecución) • Algunos modos de direccionamiento usuales: • Inmediato • Registro • Directo (o absoluto) • Indirecto con registro • Indirecto • Desplazamiento • Indexado Inmediato • El operando está en la misma instrucción (Cte). • Ejemplos (Orga1): • JMP 0x1110 • CMP 0x00FF 0x11FF OpCode • No hay acceso adicional a la memoria • Es rápido (pero poco flexible) Cte Directo • El operando está en la dirección de memoria referenciada por DIR. • • Es decir, el operando=[DIR] OpCode Ejemplo (Orga1): • NEG [0x1941] • Ideal para acceso a variables • Hay un único acceso adicional a memoria DIR Registro • El operando está en un registro del CPU • • Es decir, operando=registro n OpCode Rn Ejemplo (Orga1): • NOT R0 • Instrucción corta y rápida • No requiere acceso a memoria (ya está el operando en el CPU) • Espacio de direcciones (ie, cantidad de registros) limitado Registro Indirecto • El operando está almacenada en la dirección de memoria indicada por un registro • Es decir, operando=[Rn] OpCode Rn • Necesita un acceso a memoria menos que el direccionamiento indirecto • Cómodo para acceder a arrays Ejemplo 0xFF00 0xFF10 0xFF01 0x0000 • 0xFF20 0x0000 0xFF21 0x2222 Por ejemplo, supongamos que almacenamos una lista dinámica como <PROX_DIRECCION,VALOR> • • 0xFF10 0xFF20 0xFF11 0x1111 El último elemento tiene PROX_DIRECCION=0x0000 ¿Cómo escribimos un programa en lenguaje ORGA1 para que cuente la longitud de esta lista y lo almacene en R0? Ejemplo 0xFF00 0xFF10 0xFF01 0x0000 0xFF10 0xFF20 0xFF11 0x1111 0xFF20 0x0000 0xFF21 0x2222 R0:=0 R1 := 0xFF00 Mientras (R1!=0x0000) R0:=R0+1 R1:=[R1] Fin Mientras Pseudo-código Registro Indirecto 0xFF00 0xFF10 0xFF01 0x0000 Inicio 0xFF10 0xFF20 0xFF11 0x1111 0xFF20 0x0000 0xFF21 0x2222 MOV R0, 0x0000 MOV R1, 0xFF00 Mientras: CMP [R1], 0x0000 JE FinMientras ADD R0, 0x0001 MOV R1,[R1] FinMientras: JMP Mientras Ensamblador Orga1 Acceso a arreglos 0x0000 0x1111 0x2222 0x3333 0x4444 0xFF00 0xFF01 0xFF02 0xFF03 0xFF04 Inicio • Por ejemplo, supongamos que almacenamos un arreglo de 5 dimensiones a partir de la dirección 0xFF00 • ¿Cómo escribimos un programa en lenguaje ORGA1 para que sume las componentes del arreglo y lo almacene en R0? Acceso a arreglos 0x0000 0x1111 0x2222 0x3333 0x4444 0xFF00 0xFF01 0xFF02 0xFF03 0xFF04 Inicio R0:=0 R1 := 0xFF00 R2 := 0x0000 Mientras (R2!=0x0005) R0:=R0+[R1] R1:=R1+1 R2:=R2+1 Fin Mientras Pseudo-código Acceso a arreglos 0x0000 0x1111 0x2222 0x3333 0x4444 0xFF00 0xFF01 0xFF02 0xFF03 0xFF04 Inicio MOV R0, 0x0000 MOV R1, 0xFF00 MOV R2, 0x0000 Mientras: CMP R2,0x0005 JE FinMientras ADD R0, [R1] ADD R1, 0x0001 ADD R2, 0x0001 JMP Mientras FinMientras: … Assembler Orga1 Indirecto • • El operando está en la dirección de memoria apuntada por el contenido de la dirección • Es decir, operando=[[Dir]] • Típico para acceder a listas, arreglos u otras estructuras dinámicas OpCode Necesita 2 accesos a memoria: • 1ro: obtener el puntero P almacenado en Dir • 2do: obtener el operando almacenado en P. Dir Indirecto 0xFF00 0xFF10 0xFF01 0x0000 0xFF10 0xFF20 0xFF11 0x1111 0xFF20 0x0000 0xFF21 0x2222 R0:=0 [p_actual] := 0xFF00 Mientras ([p_actual]!=0x0000) R0:=R0+1 [actual]:=[[p_actual]] Fin Mientras Pseudo-código Indirecto 0xFF00 0xFF10 0xFF01 0x0000 0xFF10 0xFF20 0xFF11 0x1111 0xFF20 0x0000 0xFF21 0x2222 p_actual: DW 0x0000 Inicio MOV R0, 0x0000 MOV [p_actual] , 0xFF00 Mientras: CMP [p_actual], 0x0000 JE FinMientras Ensamblador Orga1 ADD R0, 0x0001 MOV [p_actual],[[p_actual]] JMP Mientras FinMientras: … Desplazamiento • El operando está almacenado en la dirección surgida de sumar el valor del registro y del desplazamiento (también llamado offset) • Es decir, operando=[Rn+D] OpCode • Ideal para acceder a campos de registros • También para arrays de registros • Rn se mueve dentro del array • D selecciona el campo Rn D Indexado • El operando está almacenado en la dirección producto de sumar una dirección con el valor de un registro • • OpCode Dir Similar al direccionamiento de desplazamiento • • Es decir, operando=[Dir+Rn] Diferencia: D puede ser bastante menor al espacio de direcciones (4 bits vs. 32 bits) Ideal para arreglos Rn Acceso a arreglos Indexado 0x0000 0x1111 0x2222 0x3333 0x4444 0xFF00 0xFF01 0xFF02 0xFF03 0xFF04 Inicio MOV R0,0x0000 MOV R1,0x0000 Mientras: CMP R1,0x0005 JE FinMientras ADD R0, [0xFF00 +R1] ADD R1, 0x0001 JMP Mientras FinMientras: … Assembler Orga1 Indexado con escala • El operando se encuentra en la posición resultado de sumar la dirección al registro multiplicado por la escala OpCode Dir Rn Escala • • Es decir, operando=[Dir+Rn*Escala] Ideal para arreglos de estructuras Indexado con escala • Supongamos que un producto de un supermercado es representado con 3 enteros <Id,Precio,Stock> • Id0 Si un arreglo con 3 productos se almacena a partir de la dirección 0xFF00 la memoria estará ocupada del siguiente modo: Precio0 Stock0 Id1 Precio1 Stock1 Id2 Precio2 Stock2 0xFF00 0xFF01 0xFF02 0xFF03 0xFF04 0xFF05 0xFF06 0xFF07 0xFF08 Inicio Indexado con escala Producto0 Id0 Precio0 Stock0 Producto1 Id1 Precio1 Stock1 Producto2 Id2 Precio2 Stock2 0xFF00 0xFF01 0xFF02 0xFF03 0xFF04 0xFF05 0xFF06 0xFF07 0xFF08 Inicio • Para sumar los stocks de todos los productos puedo utilizar el modo indexado con desplazamiento • ADD R0, [0xFF02+R1*3] Modos de direccionamiento • • Facilitan el acceso a los operandos • Arreglos • Matrices • Listas • Registros (Records) La ausencia de un modo de direccionamiento no impide el acceso al operando. Modos de direccionamiento 0x0800 0x0900 Memoria 0x0900 0x1000 Registros 0x1000 0x0500 Instrucción Máq. Orga1 MOV R0,0x0800 MOV R0,[0x0800] Indirecto MOV R0,R1 Registro MOV R0,[R1+0x0800] … R1 0x0800 Modo de Valor final de Direccionamiento fuente R0 Inmediato Directo MOV R0,[[0x0800]] MOV R0,[R1] R0 Indirecto Registro Indexado Modos de direccionamiento 0x0800 0x0900 Memoria 0x0900 0x1000 Registros 0x1000 0x0500 Instrucción Máq. Orga1 MOV R0,0x0800 MOV R0,[0x0800] Indirecto MOV R0,R1 Registro MOV R0,[R1+0x0800] … R1 0x0800 Modo de Valor final de Direccionamiento fuente R0 Inmediato 0x0800 Directo MOV R0,[[0x0800]] MOV R0,[R1] R0 Indirecto Registro Indexado Modos de direccionamiento 0x0800 0x0900 Memoria 0x0900 0x1000 Registros 0x1000 0x0500 Instrucción Máq. Orga1 MOV R0,0x0800 MOV R0,[0x0800] Indirecto MOV R0,R1 Registro MOV R0,[R1+0x0800] … R1 0x0800 Modo de Valor final de Direccionamiento fuente R0 Inmediato 0x0800 Directo 0x0900 MOV R0,[[0x0800]] MOV R0,[R1] R0 Indirecto Registro Indexado Modos de direccionamiento 0x0800 0x0900 Memoria 0x0900 0x1000 Registros 0x1000 0x0500 Instrucción Máq. Orga1 MOV R0,0x0800 MOV R0,[0x0800] Indirecto MOV R0,R1 Registro MOV R0,[R1+0x0800] … R1 0x0800 Modo de Valor final de Direccionamiento fuente R0 Inmediato 0x0800 Directo 0x0900 MOV R0,[[0x0800]] MOV R0,[R1] R0 Indirecto Registro Indexado 0x1000 Modos de direccionamiento 0x0800 0x0900 Memoria 0x0900 0x1000 Registros 0x1000 0x0500 Instrucción Máq. Orga1 MOV R0,0x0800 MOV R0,[0x0800] R0 … R1 0x0800 Modo de Valor final de Direccionamiento fuente R0 Inmediato 0x0800 Directo 0x0900 MOV R0,[[0x0800]] Indirecto 0x1000 MOV R0,R1 Registro 0x0800 MOV R0,[R1] MOV R0,[R1+0x0800] Indirecto Registro Indexado Modos de direccionamiento 0x0800 0x0900 Memoria 0x0900 0x1000 Registros 0x1000 0x0500 Instrucción Máq. Orga1 MOV R0,0x0800 MOV R0,[0x0800] R0 … R1 0x0800 Modo de Valor final de Direccionamiento fuente R0 Inmediato 0x0800 Directo 0x0900 MOV R0,[[0x0800]] Indirecto 0x1000 MOV R0,R1 Registro 0x0800 Indirecto Registro 0x0900 MOV R0,[R1] MOV R0,[R1+0x0800] Indexado Modos de direccionamiento 0x0800 0x0900 Memoria 0x0900 0x1000 Registros 0x1000 0x0500 Instrucción Máq. Orga1 MOV R0,0x0800 MOV R0,[0x0800] R0 … R1 0x0800 Modo de Valor final de Direccionamiento fuente R0 Inmediato 0x0800 Directo 0x0900 MOV R0,[[0x0800]] Indirecto 0x1000 MOV R0,R1 Registro 0x0800 Indirecto Registro 0x0900 Indexado 0x0500 MOV R0,[R1] MOV R0,[R1+0x0800] Diseño de una Arquitectura (ISA) (Parte 2) Diseño de ISA • Tenemos que considerar: • Tipos de operaciones • Números de bits por instrucción • Número de operandos por instrucción • • Operandos implícitos y explícitos • Ubicación de los campos • Tamaño y tipo de los operandos Uso de stack, registros, etc. Algunas métricas • Memoria principal ocupada por el programa • Tamaño de la instrucción (en bits) • Code density: tratar de que las instrucciones ocupen lo menos posible • Complejidad de la instrucción • Número total de instrucciones disponibles Algunas preguntas a responder • Tamaño de la instrucción: ¿corto? ¿largo? ¿variable? • ¿Cuántos bits para el OpCode? • • ¿Cuántos bits para acceder a los operandos? • • Limita la cantidad de instrucciones Limita la cantidad de memoria accesible ¿Cuántos registros? • Más registros es más cómodo para el programador, pero más costoso para la construcción Algunas preguntas a responder • Memoria: • ¿Direccionamiento por word o byte? • ¿Endianness? • ¿Cuántos/cuáles son los modos de direccionamiento? Tamaño Memoria • Tamaño de la memoria= Tamaño unidad direccionable x cant. direcciones • Ejemplo: • Tamaño unidad direccionable = 1Byte • Cant. direcciones = 2^16 =65536 direcciones • Tamaño Memoria = 65536 x 1 B = 65536 B = 64 KB Cantidad de Direcciones de Memoria • Cantidad de direcciones = Tam. de la Memoria / Tam. Unidad Direccionable • Ejemplo: • Tamaño de la Memoria = 8 MB • Tamaño Unidad Direccionable = 2 B • Cant. de Direcciones = 8 MB/2B = 4M =4x1024x1024= 4.194.304 direcciones Cantidad de bits para direcciones de Memoria • Cantidad de bits para direcciones = log2(Cantidad de direcciones) • Ejemplo: • Cant. de Direcciones = 4.194.304 • Cant. de bits para codificar direcciones = log2(4.194.304)= 22 bits Operandos • 3 operandos: RISC y Mainframes • • • 2 operandos: Intel, Motorola • A = A+B • (Al menos uno debe ser un registro) 1 operando: arquitecturas de acumulador • • AC = AC + A (+operando implícito: registro acumulador) 0 operandos: arquitecturas de pila • • A = B+C push(pop()+pop()) (+operando implícito: pila) Arquitecturas super-escalares (ejemplo: VLIW) Algunas ISAs Ortogonalidad • Máxima ortogonalidad: cualquier instrucción puede ser usada con cualquier modo de direccionamiento • Es una característica “elegante" pero muy costosa: • Implica tener muchas instrucciones • Algunas quizás poco usadas o fácilmente reemplazables Ejemplo • ¿Qué podemos deducir de este formato de instrucción? Ejemplo 32b 32b 32b • Instrucciones de longitud variable • Tamaño: 32 bits, 64bits o 96bits Ejemplo } 8 bits para Opcode =2ˆ8 instrucciones=256 Ejemplo 5 bits para identificar registros } =2ˆ5 registros=32 Ejemplo 3 bits para identificar modos de direccionamiento } =2ˆ3 modos de direc.=8 Ejemplo } 4 bits para indicar desplazamiento o escala Ejemplo 32 bits para direcciones/datos/desplazamiento • Es necesario leer una segunda palabra valores inmediatos/direcciones/etc. Formato de Instrucción • El tamaño de las instrucciones depende fuertemente del número de operandos que soporta la Arquitectura • No todas las instrucciones requieren el mismo número de operandos • Por ejemplo, la operación RET ni siquiera necesita operando, qué podemos hacer con el espacio que sobra • Rta: podríamos utilizar códigos de operación variables Ejemplo • • Supongamos una arquitectura con 16 registros, 4K direcciones de memoria. • Los registros se codifican con 4 bits (2^4=16) • Las direcciones se codifican con 12 bits (2^12=4K) Si la longitud de instrucción es fija de 16 bits, ¿cuántas instrucciones puede tener la Arquitectura? OpCode Fijo • 2^4 = 16 instrucciones: • Algunas con 1 dirección de memoria de operando • Otros con hasta 3 registros como operandos OpCode Fijo • Supongamos que se necesita únicamente 2 instrucciones con acceso a memoria 0000 0001 0010 … 1111 R1 DIR Tipo 1: 2 instrucciones de 1 dirección de memoria R2 Tipo 2: 14 instrucciones de 3 registros R3 • Si el OpCode es fijo de 4 bits, quedan únicamente 14 instrucciones de a lo sumo 3 registros. • ¿Qué pasa si el OpCode es variable? OpCode Variable 0000 0001 DIR Tipo 1: 2 instrucciones de 1 dirección de memoria R2 R3 Tipo 2: 13 instrucciones de 3 registros R2 Tipo 3: 15 instrucciones de 2 registros 0010 … 1110 R1 1111 0000 …. 1110 R1 1111 0000 … 1110 R1 Tipo 4: 15 instrucciones de 1 registro 1111 0000 … 1111 Tipo 5: 16 instrucciones de 0 operandos 1111 1111 1111 OpCode Fijo vs. OpCode Variable • El OpCode Variable nos permite un mayor aprovechamiento del espacio de codificaciones • OpCode Fijo = 16 instrucciones • OpCode Variable = 61 instrucciones Formato de Instrucción Pentium Modos de direccionamiento Pentium: 24! Formato de Instrucción Pentium REP MOVS 0xF3 # Copia “CX” bytes de DS:SI hacia ES:DI 0xA4 Resumen • Modos de direccionamiento • • Inmediato, Directo, Indirecto, Registro, etc. Diseño de ISA: • Ortogonalidad, Formato de Instrucción • OpCode Fijo vs. OpCode Variable Bibliografía • Tanenbaum - Capítulo 5 • Stalling - Capítulo 11 • Null - Capítulo 5