Documentos de Académico
Documentos de Profesional
Documentos de Cultura
com
debe estar en la dirección 0). Depende del microensamblador colocar cada microinstrucción
en una dirección adecuada y vincularlas en secuencias cortas utilizando el
SIGUIENTE DIRECCION campo. Cada secuencia comienza en la dirección correspondiente al valor numérico
del código de operación IJVM que interpreta (por ejemplo,MÚSICA POP comienza en 0x57), pero el resto de
la secuencia puede estar en cualquier lugar del almacén de control y no necesariamente en direcciones
consecutivas.
Ahora considere la IJVM AÑADO instrucción. La microinstrucción ramificada por el
bucle principal es la etiquetadaiadd1. Esta instrucción inicia el trabajo específico para
AÑADO:
Si el código de operación IJVC es DUP, POP, o INTERCAMBIO, la pila debe ajustarse. los
DUP instrucción simplemente replica la palabra superior de la pila. Dado que el valor de esta
palabra ya está almacenado enTOS, la operación es tan simple como incrementar SP para señalar
la nueva ubicación y almacenar TOS a esa ubicación. losMÚSICA POP la instrucción es casi tan
simple, simplemente decrementando SP para descartar la palabra superior de la pila. Sin
embargo, para mantener la palabra principal enTOS ahora es necesario leer la nueva palabra
principal de la memoria y escribirla en TOS. Finalmente, el INTERCAMBIO La instrucción implica
intercambiar los valores en dos ubicaciones de memoria: las dos palabras superiores de la pila.
Esto se hace algo más fácil por el hecho de queTOS ya contiene uno de esos valores, por lo que no
es necesario leerlo de la memoria. Esta instrucción se discutirá con más detalle más adelante.
BIPUSH
BYTE
(0×10)
(a) (B)
Figura 4-19. (a) YO CARGO con un Índice de 1 byte. (B)ILOAD ANCHO con un índice de 2 bytes.
278 EL NIVEL DE MICROARQUITECTURA CAP. 4
Sin embargo, el uso de MBR para un índice es ligeramente diferente que en BIPUSH,
donde se extendió el letrero. En el caso de un índice, el desplazamiento es siempre positivo, por lo que
el desplazamiento de bytes debe interpretarse como un entero sin signo, a diferencia de enBIPUSH,
donde se interpretó como un entero de 8 bits con signo. La interfaz deMBR al bus B está
cuidadosamente diseñado para hacer posibles ambas operaciones. En el caso deBIPUSH
(entero de 8 bits con signo), la operación adecuada es extensión de signo, es decir, el bit más a la
izquierda en el 1 byte MBR se copia en los 24 bits superiores del bus B. En el caso de
YO CARGO (entero de 8 bits sin signo), la operación adecuada es de relleno con ceros. Aquí, los 24
bits superiores del bus B simplemente se suministran con ceros. Estas dos operaciones se
distinguen por señales separadas que indican qué operación se debe realizar (ver Fig. 4-6). En el
microcódigo, esto se indica medianteMBR (firmar extendido, como en
BIPUSH 3) o MBRU (unsigned, como en iload2).
Mientras espera que la memoria suministre el operando (en iload3), SP se incrementa para
contener el valor para almacenar el resultado, la nueva parte superior de la pila. Este valor también se
copia aMAR en preparación para escribir el operando en la parte superior de la pila. ordenador personal
nuevamente debe incrementarse para obtener el siguiente código de operación (en iload4). Finalmente, MDR se
copia a TOS para reflejar la nueva parte superior de la pila (en iload5).
ISTORE es la operación inversa de YO CARGO, es decir, una palabra se quita de la parte superior
de la pila y se almacena en la ubicación especificada por la suma de LV y el índice contenido en la
instrucción. Utiliza el mismo formato queYO CARGO, se muestra en la Fig. 4-19 (a), excepto con el
código de operación 0x36 en lugar de 0x15. Esta instrucción es algo diferente de lo que cabría
esperar porque la palabra superior de la pila ya se conoce (enTOS), por lo que se puede guardar
de inmediato. Sin embargo, la nueva palabra de la parte superior de la pila debe leerse de la
memoria. Por lo tanto, se requieren tanto una lectura como una escritura, pero se pueden
realizar en cualquier orden (o incluso en paralelo, si fuera posible).
Ambos YO CARGO y ISTORE están restringidos porque solo pueden acceder a las primeras 256
variables locales. Si bien para la mayoría de los programas esto puede ser todo el espacio de variables
locales necesario, es, por supuesto, necesario poder acceder a una variable donde sea que esté ubicada
en el espacio de variables locales. Para lograr esto, IJVM usa el mismo mecanismo empleado en JVM
para lograr esto: un código de operación especialAMPLIO, conocido como byte de prefijo,
Seguido por el YO CARGO o ISTORE código de operación. Cuando ocurre esta secuencia, las definiciones de
YO CARGO y ISTORE se modifican, con un índice de 16 bits siguiendo el código de operación en lugar de un
índice de 8 bits, como se muestra en la figura 4-19 (b).
AMPLIO se decodifica de la forma habitual, lo que lleva a una rama a ancho1 que maneja el AMPLIO
código de operación. Aunque el código de operación para ampliar ya está disponible enMBR,
ancho1 obtiene el primer byte después del código de operación, porque la lógica del microprograma
siempre espera que esté allí. Luego se realiza una segunda rama de múltiples vías enancho2,
esta vez usando el byte siguiente AMPLIO para despachar. Sin embargo, desdeILOAD ANCHO
requiere un microcódigo diferente al YO CARGO, y AMPLIO ISTORE requiere un microcódigo diferente
al ISTORE, etc., la segunda rama de múltiples vías no puede simplemente usar el código de
operación como la dirección de destino, la forma Main1 lo hace.
En lugar de, ancho2 OR 0x100 con el código de operación mientras lo coloca en MPC.
Como resultado, la interpretación de ILOAD ANCHO comienza en 0x115 (en lugar de 0x15), el
SEGUNDO. 4.3 UN EJEMPLO DE IMPLEMENTACIÓN 279
Microinstrucción
orden de ejecución
AMPLIO
ILOAD ILOAD
0×115 wide_iload1 3
0×100 Main1 1 1
0×C4 ancho1 2
0×15 iload1 2
0×00
interpretación de AMPLIO ISTORE comienza en 0x136 (en lugar de 0x36), y así sucesivamente. En esto
manera, cada AMPLIO El código de operación comienza en una dirección de 256 (es decir, 0x100) palabras más
altas en el almacén de control que el código de operación regular correspondiente. La secuencia inicial de
microinstrucciones para ambosYO CARGO y ILOAD ANCHO se muestra en la Fig. 4-20.
Una vez que se alcanza el código para implementar ILOAD ANCHO (0x115), el código
difiere del normal YO CARGO solo que el índice debe construirse concatenando 2 bytes de
índice en lugar de simplemente extender el signo de un solo byte. La concatenación y la
posterior adición deben realizarse en etapas, primero copiandoÍNDICE BYTE 1 dentro H
desplazado a la izquierda en 8 bits. Dado que el índice es un entero sin signo,MBR se
extiende a cero usando MBRU. Ahora se agrega el segundo byte del índice (la operación de
suma es idéntica a la concatenación ya que el byte de orden inferior de H ahora es cero, lo
que garantiza que no habrá acarreo entre los bytes), con el resultado nuevamente
almacenado en H. A partir de aquí, la operación puede proceder exactamente como si fuera
un estándar. YO CARGO. En lugar de duplicar las instrucciones finales de ILOAD (iload3 para
iload5), simplemente nos ramificamos de ancho iload4 para iload3. Sin embargo, tenga en cuenta que
ordenador personal debe incrementarse dos veces durante la ejecución de la instrucción para dejarla
apuntando al siguiente código de operación. losYO CARGO la instrucción lo incrementa una vez; los
ILOAD ANCHO La secuencia también lo incrementa una vez.
La misma situación ocurre para AMPLIO ISTORE: después de que se ejecuten las primeras
cuatro microinstrucciones (istore1 ancho para ancho istore4), la secuencia es la misma que la
280 EL NIVEL DE MICROARQUITECTURA CAP. 4
secuencia para ISTORE después de las dos primeras instrucciones, ancho istore4 ramas a
istore3.
Nuestro siguiente ejemplo es un LDC W instrucción. Este código de operación es diferente de YO CARGO
en dos maneras. Primero, tiene un desplazamiento sin firmar de 16 bits (como la versión ancha deYO CARGO).
En segundo lugar, está indexado CPP en vez de LV, ya que su función es leer del grupo
constante en lugar del marco de la variable local. (En realidad, hay una forma corta de
LDC W (LDC), pero no lo incluimos en IJVM, ya que la forma larga incorpora todas las
variaciones posibles de la forma corta, pero toma 3 bytes en lugar de 2.)
los IINC instrucción es la única instrucción IJVM que no sea ISTORE que puede modificar una
variable local. Lo hace incluyendo dos operandos, cada uno de 1 byte de longitud, como
mostrado en la Fig. 4-21.
IINC
ÍNDICE CONST
(0x84)
Figura 4-21. los IINC la instrucción tiene dos diferentes campos de operandos.
los IINC usos de instrucción ÍNDICE para especificar el desplazamiento desde el principio del
marco de la variable local. Lee esa variable, incrementándola enCONST, un valor contenido en la
instrucción y lo almacena en la misma ubicación. Tenga en cuenta que esta instrucción puede
incrementarse en una cantidad negativa, es decir,CONST es una constante de 8 bits con signo, en
el rango -128 al +127. La JVM completa incluye una versión amplia deIINC
donde cada operando tiene 2 bytes de longitud.
Ahora llegamos a la primera instrucción de rama IJVM: IR A. La única función de esta instrucción es
cambiar el valor de ORDENADOR PERSONAL, de modo que la siguiente instrucción IJVM ejecutada es la que se
encuentra en la dirección calculada agregando el desplazamiento (con signo) de 16 bits a la dirección del
código de operación de la rama. Una complicación aquí es que el desplazamiento es relativo al valor que
ordenador personal tenía al inicio de la decodificación de la instrucción, no el valor que tiene después de que se
La microinstrucción en goto2 inicia la búsqueda del segundo byte de compensación, lo que lleva a la
figura 4-22 (d) al comienzo de goto3. Después de que el primer byte de compensación se haya desplazado 8 bits
a la izquierda y se haya copiado en H llegamos a goto4 y Fig. 4-22 (e). Ahora tenemos el primer byte de
compensación desplazado a la izquierda enH el segundo byte de compensación en MBR, y la base en OPC. Al
construir el desplazamiento completo de 16 bits en H y luego agregarlo a la base, obtenemos el
SEGUNDO. 4.3 UN EJEMPLO DE IMPLEMENTACIÓN 281
Memoria
1 byte
n+3
n+2 BYTE DE DESPLAZAMIENTO 2 OFFSET BYTE 2 OFFSET BYTE 2 OFFSET BYTE 2 OFFSET BYTE 2
n+1 BYTE DE DESPLAZAMIENTO 1 BYTE DE DESPLAZAMIENTO 1 BYTE DE DESPLAZAMIENTO 1 BYTE DE DESPLAZAMIENTO 1 BYTE DE DESPLAZAMIENTO 1
norte GOTO (0xA7) GOTO (0xA7) GOTO (0xA7) GOTO (0xA7) GOTO (0xA7)
Registros
H DESPLAZAMIENTO 1 << 8
nueva dirección para poner ORDENADOR PERSONAL, en goto5. Tenga en cuenta que usamos MBRU en goto4
en lugar de MBR porque no queremos una extensión de signo del segundo byte. El desplazamiento de
16 bits se construye, de hecho, uniendo las dos mitades en OR. Finalmente, tenemos que buscar el
siguiente código de operación antes de volver aMain1 porque el código allí espera el siguiente código de
operación en MBR. El último ciclo goto6, es necesario porque los datos de la memoria deben obtenerse a
tiempo para aparecer en MBR durante Principal1.
Las compensaciones utilizadas en el ir a Las instrucciones IJVM son valores de 16 bits con
signo, con un mínimo de -32768 y un máximo de +32767. Esto significa que no es posible bifurcar
en ambos sentidos a etiquetas más distantes que estos valores. Esta propiedad se puede
considerar como un error o una característica en IJVM (y también en JVM). El campamento de
errores diría que la definición de JVM no debería restringir su estilo de programación. El campo
de características diría que el trabajo de muchos programadores mejoraría radicalmente si
tuvieran pesadillas sobre el temido mensaje del compilador.
Desafortunadamente (en nuestra opinión) este mensaje aparece solo cuando un luego o demás La cláusula
supera los 32 KB, normalmente al menos 50 páginas de Java.
Ahora considere las tres instrucciones de rama condicional de IJVM: IFLT, IFEQ, y
SI ICMPEQ. Los dos primeros sacan la palabra superior de la pila, ramificándose si es menor
que cero o igual a cero, respectivamente. SI ICMPEQ saca las dos primeras palabras de la pila
y se ramifica si y solo si son iguales. En los tres casos, es necesario leer una nueva palabra
de la parte superior de la pila para almacenar enTOS.
El control para estas tres instrucciones es similar: el operando o los operandos se colocan primero
en los registros, luego se lee el nuevo valor de la parte superior de la pila TOS, finalmente se hacen la
prueba y la ramificación. ConsiderarIFLT primero. La palabra para probar ya está enTOS,
282 EL NIVEL DE MICROARQUITECTURA CAP. 4
pero desde IFLT saca una palabra de la pila, la nueva parte superior de la pila debe leerse para
almacenarla TOS. Esta lectura se inicia en iflt1. En iflt2, la palabra a ser probada se guarda en
OPC por el momento, por lo que el nuevo valor se puede poner en TOS en breve sin perder el
actual. Eniflt3 la nueva palabra de primer nivel está disponible en MDR, por lo que se copia a TOS.
Finalmente, en iflt4 la palabra para ser probada, ahora guardada en OPC, se ejecuta a través de la
ALU sin ser almacenado y el norte bit bloqueado y probado. Esta microinstrucción también
contiene una rama, eligiendo entreT si la prueba fue exitosa o F de lo contrario.
Si tiene éxito, el resto de la operación es esencialmente el mismo que al
comienzo de la IR A instrucción, y la secuencia simplemente continúa en medio
de la IR A secuencia, con goto2. Si no tiene éxito, una secuencia corta (F, F2,
y F3) Es necesario omitir el resto de la instrucción (el desplazamiento) antes de volver a
Main1 para continuar con la siguiente instrucción.
El código en ifeq2 y ifeq3 sigue la misma lógica, solo usando el Z poco en lugar del norte poco.
En ambos casos, corresponde al ensambladorMAL reconocer que las direcciones T y F son
especiales y para asegurarse de que sus direcciones se coloquen en direcciones de
almacenamiento de control que difieren solo en el bit más a la izquierda.
La lógica de SI ICMPEQ es aproximadamente similar a IFEQ excepto que aquí también
necesitamos leer en el segundo operando. Se almacena enH en si icmpeq3, donde se inicia la
lectura de la nueva palabra de la parte superior de la pila. Nuevamente, la palabra actual de la
parte superior de la pila se guarda enOPC y el nuevo instalado en TOS. Finalmente, la prueba en si
icmpeq6 es parecido a ifeq4.
Ahora, consideramos la implementación de INVOCAR EVIRTUAL y VUELVO, las instrucciones
para invocar una llamada a procedimiento y regresar, como se describe en la Sec. 4.2.3.
INVOCAR EVIRTUAL, una secuencia de 22 microinstrucciones, es la instrucción IJVM más compleja
implementada. Su funcionamiento se muestra en la figura 4-12. La instrucción utiliza su
desplazamiento de 16 bits para determinar la dirección del método que se invocará. En nuestra
implementación, la compensación es simplemente una compensación en el grupo constante.
Esta ubicación en el grupo constante apunta al método que se invocará. Sin embargo, recuerde
que los primeros 4 bytes de cada método sonno instrucciones. En su lugar, son dos punteros de
16 bits. El primero da el número de palabras de parámetro (incluyendoOBJREF—Ver Fig. 4-12). El
segundo da el tamaño del área de la variable local en palabras. Estos campos se obtienen a
través del puerto de 8 bits y se ensamblan como si fueran dos desplazamientos de 16 bits dentro
de una instrucción.
Luego, la información de vinculación necesaria para restaurar la máquina a su estado anterior: la
dirección de inicio del área de variable local anterior y la anterior. ordenador personal: Se almacena
inmediatamente encima del área de variable local recién creada y debajo de la nueva pila. Finalmente,
se obtiene el código de operación de la siguiente instrucción yordenador personal se incrementa antes de
volver a Main1 para comenzar la siguiente instrucción.
VUELVO es una instrucción simple que no contiene operandos. Simplemente usa la dirección
almacenada en la primera palabra del área de variables locales para recuperar la información de
enlace. Entonces restauraSP, LV, y ordenador personal a sus valores anteriores y copia el valor de
retorno de la parte superior de la pila actual a la parte superior de la pila original, como se
muestra en la figura 4-13.
SEGUNDO. 4.4 DISEÑO DEL NIVEL DE MICROARQUITECTURA 283
Como casi todo lo demás en informática, el diseño del nivel de microarquitectura está
lleno de compensaciones. Las computadoras tienen muchas características deseables, que
incluyen velocidad, costo, confiabilidad, facilidad de uso, requisitos de energía y tamaño
físico. Sin embargo, una compensación determina las decisiones más importantes que debe
tomar el diseñador de la CPU: velocidad versus costo. En esta sección, analizaremos este
tema en detalle para ver qué se puede intercambiar con qué, cómo se puede lograr un alto
rendimiento y a qué precio en hardware y complejidad.
Si bien la tecnología más rápida ha dado como resultado la mayor aceleración en cualquier
período de tiempo, eso está más allá del alcance de este texto. Las mejoras de velocidad debidas
a la organización, aunque menos sorprendentes que las debidas a los circuitos más rápidos, han
sido impresionantes. La velocidad se puede medir de diversas formas, pero dada una tecnología
de circuito y un ISA, existen tres enfoques básicos para aumentar la velocidad de ejecución:
2. Simplifique la organización para que el ciclo del reloj pueda ser más corto.
Los dos primeros son obvios, pero existe una sorprendente variedad de oportunidades de diseño
que pueden afectar drásticamente el número de ciclos del reloj, el período del reloj o, con mayor
frecuencia, ambos. En esta sección, daremos un ejemplo de cómo la codificación y decodificación
de una operación puede afectar el ciclo del reloj.
El número de ciclos de reloj necesarios para ejecutar un conjunto de operaciones se conoce como
longitud de la trayectoria. A veces, la longitud de la ruta se puede acortar agregando hardware
especializado. Por ejemplo, agregando un incrementador (conceptualmente, un sumador con un lado
conectado permanentemente para agregar 1) aORDENADOR PERSONAL, ya no tenemos que usar la ALU
para avanzar ORDENADOR PERSONAL, eliminando ciclos. El precio que se paga es más hardware. Sin
embargo, esta capacidad no ayuda tanto como cabría esperar. Para la mayoría de las instrucciones, los
ciclos consumidos incrementando la PC también son ciclos en los que se está realizando una operación
de lectura. La instrucción subsiguiente no se pudo ejecutar antes de todos modos porque depende de
los datos provenientes de la memoria.
Reducir el número de ciclos de instrucción necesarios para obtener instrucciones
requiere más que un circuito adicional para incrementar la PC. Para acelerar la
búsqueda de instrucciones en un grado significativo, se debe aprovechar la tercera
técnica, la superposición de la ejecución de las instrucciones. Separar los circuitos para
obtener las instrucciones: el puerto de memoria de 8 bits y elMBR
y ordenador personal registros: es más eficaz si la unidad se hace funcionalmente independiente de la ruta de
datos principal. De esta forma, puede obtener el siguiente código de operación u operando por sí solo,
284 EL NIVEL DE MICROARQUITECTURA CAP. 4
que debe ser realizado en serie en un solo ciclo de reloj que determina la
duración del ciclo de reloj.
Un aspecto que se puede controlar es la cantidad de decodificación que se debe realizar. Recuerde, por
ejemplo, que en la figura 4-6 vimos que, si bien cualquiera de los nueve registros podía leerse en la ALU desde
el bus B, solo necesitábamos 4 bits en la palabra de microinstrucción para especificar qué registro debía
seleccionarse. Desafortunadamente, estos ahorros tienen un precio. El circuito de decodificación agrega
retardo en la ruta crítica. Significa que cualquier registro que habilite sus datos en el bus B recibirá ese
comando un poco más tarde y obtendrá sus datos en el bus un poco más tarde. Este efecto se produce en
cascada, con la ALU recibiendo sus entradas un poco más tarde y produciendo sus resultados un poco más
tarde. Finalmente, el resultado está disponible en el bus C para ser escrito en los registros un poco más tarde.
Dado que este retraso a menudo es el factor que determina la duración del ciclo del reloj, esto puede significar
que el reloj no puede funcionar tan rápido y que todo el equipo debe funcionar un poco más lento. Por lo tanto,
existe una compensación entre velocidad y costo. Reducir el almacenamiento de control en 5 bits por palabra
tiene el costo de ralentizar el reloj. El ingeniero de diseño debe tener en cuenta los objetivos del diseño al
decidir cuál es la elección correcta. Para una implementación de alto rendimiento, probablemente no sea una
buena idea usar un decodificador; para uno de bajo costo, podría serlo. probablemente utilizar un
decodificador no sea una buena idea; para uno de bajo costo, podría serlo. probablemente utilizar un
decodificador no sea una buena idea; para uno de bajo costo, podría serlo.
El Mic-1 fue diseñado para ser moderadamente simple y moderadamente rápido, aunque
hay que reconocer que existe una enorme tensión entre estos dos objetivos. En pocas palabras,
las máquinas simples no son rápidas y las máquinas rápidas no son simples. La CPU Mic-1
también usa una cantidad mínima de hardware: 10 registros, la ALU simple de la figura 3-19
replicada 32 veces, una palanca de cambios, un decodificador, un almacén de control y un poco
de pegamento aquí y allá. Todo el sistema podría construirse con menos de 5000 transistores
más lo que requiera el almacén de control (ROM) y la memoria principal (RAM).
Habiendo visto cómo se puede implementar IJVM de una manera sencilla en
microcódigo con poco hardware, veamos ahora implementaciones alternativas más
rápidas. A continuación, veremos formas de reducir el número de microinstrucciones por
instrucción ISA (es decir, reducir la longitud de la ruta de ejecución). Después de eso,
consideraremos otros enfoques.
Este concepto de superposición del comienzo de la instrucción se puede llevar más allá
y, de hecho, el bucle principal en algunos casos se puede reducir a nada. Esto puede ocurrir
de la siguiente manera. Considere cada secuencia de microinstrucciones que termina
ramificándose enPrincipal1. En cada uno de estos lugares, la microinstrucción del bucle
principal se puede agregar al final de la secuencia (en lugar de al comienzo de la siguiente
secuencia), con la rama de múltiples vías ahora replicada en muchos lugares (pero siempre
con el mismo conjunto de objetivos) . En algunos casos elMain1 La microinstrucción se
puede fusionar con microinstrucciones anteriores, ya que esas instrucciones no siempre se
utilizan por completo.
En la figura 4-23, se muestra la secuencia dinámica de instrucciones para un MÚSICA POP
instrucción. El bucle principal ocurre antes y después de cada instrucción; en la figura mostramos
solo la ocurrencia después de laMÚSICA POP instrucción. Nótese que la ejecución de
esta instrucción toma cuatro ciclos de reloj: tres para las microinstrucciones específicas para
MÚSICA POP y uno para el bucle principal.
pop3 TOS = MDR; goto (MBR) Copia la palabra nueva en TOS; envío en código de operación
los MÚSICA POP La instrucción es particularmente adecuada para este tratamiento, porque
tiene un ciclo muerto en el medio que no usa la ALU. El bucle principal, sin embargo, usa la ALU.
Por lo tanto, para reducir la longitud de la instrucción en uno dentro de una instrucción, es
necesario encontrar un ciclo en la instrucción donde la ALU no está en uso. Tal
SEGUNDO. 4.4 DISEÑO DEL NIVEL DE MICROARQUITECTURA 287
Los ciclos muertos no son comunes, pero ocurren, por lo que la fusión Main1 al final de cada secuencia de
microinstrucciones vale la pena hacerlo. Todo lo que cuesta es una pequeña tienda de control. Por lo tanto,
tenemos nuestra primera técnica para reducir la longitud de la ruta:
¿Qué más podemos hacer para reducir la longitud de la ruta de ejecución? Otra solución fácil
es tener dos buses de entrada completos a la ALU, un bus A y un bus B, lo que da tres buses en
total. Todos (o al menos la mayoría) de los registros deben tener acceso a ambos buses de
entrada. La ventaja de tener dos buses de entrada es que luego es posible agregar cualquier
registro a cualquier otro registro en un ciclo. Para ver el valor de esta función, consulte
considerar el Implementación de Mic-1 de YO CARGO, mostrado de nuevo en la Fig. 4-25.
iload2 MAR = MBRU + H; rd MAR local para empujar los puntos SP a la nueva parte superior de la
iload4 ir a buscar; wr TOS = operación; escribir la parte superior de la pila Actualizar TOS
Vemos aquí que en iload1 LV se copia en H. La razón es que se puede agregar a MBRU en
iload2. En nuestro diseño original de dos buses, no hay forma de agregar dos registros
arbitrarios, por lo que uno de ellos primero debe copiarse a H. Con nuestro nuevo diseño de tres
buses, podemos ahorrar un ciclo, como se muestra en la Fig. 4-26. Hemos agregado el bucle de
intérprete aYO CARGO aquí, pero al hacerlo no aumenta ni disminuye la longitud de la ruta de
ejecución. Aún así, el bus adicional ha reducido el tiempo total de ejecución deYO CARGO de seis
ciclos a cinco ciclos. Ahora tenemos nuestra segunda técnica para reducir la longitud de la ruta:
iload2 MAR = SP = SP + 1 PC = nueva parte superior de la pila; preparar escribir Inc PC; obtener el
iload5 PC = PC + 1; ir a buscar; goto (MBR) MBR ya contiene código de operación; buscar byte de índice
Vale la pena usar las dos técnicas anteriores, pero para obtener una mejora dramática
necesitamos algo mucho más radical. Demos un paso atrás y observemos las partes
comunes de cada instrucción: la búsqueda y decodificación de los campos de la instrucción.
Tenga en cuenta que para cada instrucción pueden ocurrir las siguientes operaciones:
Si una instrucción tiene campos adicionales (para operandos), cada campo debe buscarse
explícitamente, 1 byte a la vez, y ensamblarse antes de que pueda usarse. Obtener y ensamblar
un campo vincula la ALU durante al menos un ciclo por byte para incrementar la PC y luego
nuevamente para ensamblar el índice o desplazamiento resultante. La ALU se usa casi en todos
los ciclos para una variedad de operaciones que tienen que ver con la obtención de la instrucción
y el ensamblaje de los campos dentro de la instrucción, además del "trabajo" real de la
instrucción.
Para superponer el bucle principal, es necesario liberar la ALU de algunas de estas tareas.
Esto se puede hacer introduciendo una segunda ALU, aunque una ALU completa no es necesaria
para gran parte de la actividad. Tenga en cuenta que, en muchos casos, la ALU se usa
simplemente como una ruta para copiar un valor de un registro a otro. Estos ciclos pueden
eliminarse mediante la introducción de rutas de datos adicionales que no pasen por la ALU. Se
puede obtener algún beneficio, por ejemplo, creando una ruta desdeTOS para
MDR, o de MDR para TOS, ya que la palabra superior de la pila se copia con frecuencia
entre esos dos registros.
En el Mic-1, gran parte de la carga se puede eliminar de la ALU creando una unidad
independiente para buscar y procesar las instrucciones. Esta unidad, llamadaSI TU
(Unidad de búsqueda de instrucciones), puede incrementar de forma independiente ordenador personal
y recuperar bytes del flujo de bytes antes de que sean necesarios. Esta unidad requiere solo un
incrementador, un circuito mucho más simple que un sumador completo. Llevando esta idea más allá,
la IFU también puede ensamblar operandos de 8 y 16 bits para que estén listos para su uso inmediato
cuando sea necesario. Hay al menos dos formas de lograr esto:
MBR2
Registro de turnos
De memoria
IMAR MBR1
+1
ordenador personal
+ 1, 2
Escribir PC
Mostramos los rudimentos del segundo esquema en la figura 4-27. En lugar de un solo 8 bitsMBR,
ahora hay dos MBRs: el de 8 bits MBR1 y el de 16 bits MBR2. La IFU realiza un seguimiento del byte o
bytes más recientes consumidos por la unidad de ejecución principal. También pone a
disposición enMBR1 el siguiente byte, al igual que en el Mic-1, excepto que detecta
automáticamente cuando el MBR1 se lee, busca previamente el siguiente byte y lo carga en MBR1
inmediatamente. Como en el Mic-1, tiene dos interfaces para el bus B:MBR1
y MBR1U. El primero tiene un signo extendido a 32 bits; el último está extendido a cero.
Similar, MBR2 proporciona la misma funcionalidad pero contiene los siguientes 2 bytes.
También tiene dos interfaces para el bus B:MBR2 y MBR2U, activar los valores de 32 bits con
signo extendido y cero, respectivamente.
La IFU es responsable de obtener un flujo de bytes. Para ello, utiliza un puerto de memoria
convencional de 4 bytes, recupera palabras completas de 4 bytes con anticipación y carga los
bytes consecutivos en un registro de desplazamiento que los proporciona uno o dos a la vez, en
el orden en que se obtienen. La función del registro de desplazamiento es mantener una cola de
bytes de la memoria, para alimentarMBR1 y MBR2.
En todo momento, MBR1 contiene el byte más antiguo en el registro de desplazamiento y MBR2
contiene los 2 bytes más antiguos (el byte más antiguo a la izquierda), formando un entero de 16 bits
[consulte la figura 4-19 (b)]. Los 2 bytes enMBR2 puede ser de diferentes palabras de memoria, porque
las instrucciones de IJVM no se alinean con los límites de palabras en la memoria.
Cuando sea MBR1 se lee, el registro de desplazamiento se desplaza 1 byte a la derecha. Cuando seaMBR2
se lee, se desplaza 2 bytes a la derecha. LuegoMBR1 y MBR2 se recargan desde el byte más antiguo
y el par de bytes, respectivamente. Si ahora queda suficiente espacio en el registro de
desplazamiento para otra palabra completa, la IFU inicia un ciclo de memoria para leerla.
290 EL NIVEL DE MICROARQUITECTURA CAP. 4
Suponemos que cuando alguno de los MBR se lee registros, se rellena al inicio del siguiente
ciclo, por lo que se puede leer en ciclos consecutivos.
El diseño de las instrucciones de uso puede ser modelado por un FSM (máquina de estado finito) como
se muestra en la Fig. 4-28. Todos los FSM constan de dos partes:estados, se muestra como círculos, y
transiciones, se muestra como arcos de un estado a otro. Cada estado representa una situación
posible en la que puede estar la FSM. Esta FSM en particular tiene siete estados, correspondientes a los
siete estados del registro de desplazamiento de la figura 4-27. Los siete estados corresponden a
cuántos bytes hay actualmente en el registro de desplazamiento, un número entre
0 y 6, inclusive.
Palabra obtenida
Palabra obtenida
Palabra obtenida
MBR2
MBR2 MBR2
MBR2 MBR2
Transiciones
MBR1: ocurre cuando se lee MBR1
MBR2: ocurre cuando se lee MBR2
Palabra recuperada: ocurre cuando se lee una palabra de memoria y se colocan 4 bytes en el registro de desplazamiento
Figura 4-28. Una máquina de estados finitos para implementar las IFU.
Cada arco representa un evento que puede ocurrir. Aquí pueden ocurrir tres eventos
diferentes. El primer evento es de 1 byte que se leeMBR1. Este evento hace que se active el
registro de desplazamiento y se desplace 1 byte del extremo derecho, reduciendo el estado
en 1. El segundo evento es de 2 bytes que se leen. MBR2, lo que reduce el estado en dos.
Ambas transiciones causanMBR1 y MBR2 para ser recargado. Cuando el FSM pasa a los
estados 0, 1 o 2, se inicia una referencia de memoria para buscar una nueva palabra
(asumiendo que la memoria no está ocupada leyendo una palabra). La llegada de la palabra
avanza el estado en 4.
Para funcionar correctamente, la IFU debe bloquear cuando se le pide que haga algo que no puede hacer,
como proporcionar el valor de MBR2 cuando solo hay 1 byte en el registro de desplazamiento y la memoria
todavía está ocupada buscando una nueva palabra. Además, solo puede hacer una cosa a la vez, por lo que los
eventos entrantes deben serializarse. Finalmente, siempre queordenador personal se cambia, las instrucciones de
uso deben actualizarse. Tales detalles lo hacen más complicado de lo que hemos mostrado. Aún así, muchos
dispositivos de hardware se construyen como FSM.
La IFU tiene su propio registro de direcciones de memoria, llamado IMAR, que se utiliza para
direccionar la memoria cuando se debe buscar una nueva palabra. Este registro tiene su propio
SEGUNDO. 4.4 DISEÑO DEL NIVEL DE MICROARQUITECTURA 291
Incrementador dedicado para que la ALU principal no sea necesaria para incrementarla para obtener la
siguiente palabra. La IFU debe monitorear el bus C para que siempreordenador personal está cargado, el nuevo
ordenador personal el valor también se copia en IMAR. Dado que el nuevo valor en ordenador personal puede no estar
en el límite de una palabra, la IFU tiene que buscar la palabra necesaria y ajustar el registro de desplazamiento
de manera apropiada.
Con las IFU, la unidad de ejecución principal escribe en ordenador personal sólo cuando se deba
cambiar la naturaleza secuencial del flujo de bytes de instrucciones. Escribe en una instrucción de
bifurcación exitosa y enINVOCAR EVIRTUAL y VUELVO.
Dado que el microprograma ya no incrementa explícitamente ordenador personal a medida que
se obtienen los códigos de operación, las IFU deben mantener ordenador personal Actual. Lo hace
detectando cuándo se ha consumido un byte del flujo de instrucciones, es decir, cuandoMBR1 o
MBR2 (o las versiones sin firmar) han sido leídas. Asociado conordenador personal es un
incrementador independiente, capaz de incrementarse en 1 o 2, dependiendo de cuántos bytes
se hayan consumido. Por tanto, el PC siempre contiene la dirección del primer byte que no se ha
consumido. Al comienzo de cada instrucción,MBR contiene la dirección del código de operación
para esa instrucción.
Tenga en cuenta que hay dos incrementadores separados y que realizan funciones diferentes.
ordenador personal cuenta bytes y se incrementa en 1 o 2. IMAR cuenta palabras y se incrementa solo en 1
(para 4 bytes nuevos). Igual queMAR, IMAR está conectado al bus de direcciones '' diagonalmente '' con
IMAR bit 0 conectado a la línea de dirección 2, y así sucesivamente, para realizar una conversión implícita
de direcciones de palabras en direcciones de bytes.
Como veremos en breve en detalle, no tener que incrementar ordenador personal en el bucle principal es
una gran ganancia, porque la microinstrucción en la que ordenador personal se incrementa a menudo hace poco
más que incrementar ORDENADOR PERSONAL. Si se puede eliminar esta microinstrucción, se puede reducir la ruta
de ejecución. La compensación aquí es más hardware para una máquina más rápida, por lo que nuestra
tercera técnica para reducir la longitud de la ruta es
Haga que una unidad funcional especializada obtenga las instrucciones de la memoria.
La IFU puede reducir en gran medida la longitud de la ruta de la instrucción promedio. Primero,
elimina el bucle principal por completo, ya que el final de cada instrucción simplemente se bifurca
directamente a la siguiente instrucción. En segundo lugar, evita inmovilizar la ALU aumentando
ORDENADOR PERSONAL. En tercer lugar, reduce la longitud de la ruta cada vez que se calcula un
índice o desplazamiento de 16 bits, porque ensambla el valor de 16 bits y lo suministra
directamente a la ALU como un valor de 32 bits, evitando la necesidad de ensamblar en H. La
Figura 4-29 muestra el Mic-2, una versión mejorada del Mic-1 donde se ha agregado el IFU de la
Figura 4-27. El microcódigo de la máquina mejorada se muestra en la figura 4-30.
Como ejemplo de cómo funciona el Mic-2, mire AÑADO. Obtiene la segunda palabra
de la pila y hace la suma como antes, solo que ahora no tiene que ir a Main1 cuando se
hace para incrementar ordenador personal y enviar a la siguiente microinstrucción.
Cuando la IFU ve esoMBR1 ha sido referenciada en iadd3, su registro de desplazamiento
interno empuja todo hacia la derecha y recarga MBR1 y MBR2. También hace un
292 EL NIVEL DE MICROARQUITECTURA CAP. 4
Memoria
MAR control
registros
Para MDR
y
de
principal
ordenador personal
memoria
Instrucción
recuperar unidad MBR
(SI TU)
MBR2
SP
LV
Señales de control
CPP
Habilitar en el bus B
OPC
Autobús C
Autobús B
H
Un autobús
6
ALU norte
control ALU
Z
Cambiador
transición a un estado uno más bajo que el actual. Si el nuevo estado es 2, la IFU comienza
a buscar una palabra de la memoria. Todo esto está en hardware. El microprograma no
tiene que hacer nada. Es por eso queAÑADO se puede reducir de cuatro microinstrucciones a
tres.
El Mic-2 mejora algunas instrucciones más que otras. LDC W pasa de nueve
microinstrucciones a solo tres, reduciendo su tiempo de ejecución en un factor de tres.
SEGUNDO. 4.4 DISEÑO DEL NIVEL DE MICROARQUITECTURA 293
Por otra parte, INTERCAMBIO va solo de ocho microinstrucciones a seis. Para el rendimiento
general, la ganancia de las instrucciones más comunes es lo que realmente cuenta. Éstos
incluyenYO CARGO (tenía 6 años, ahora 3), AÑADO (era 4, ahora 3), y SI ICMPEQ (tenía 13 años,
ahora 10 para el caso tomado; era 10, ahora 8 para el caso no tomado). Para medir la
mejora, uno tendría que elegir y ejecutar algunos puntos de referencia, pero claramente
hay una gran ganancia aquí.
El Mic-2 es claramente una mejora con respecto al Mic-1. Es más rápido y utiliza menos tienda de
control, aunque sin duda el coste de las IFU compensará con creces la propiedad inmobiliaria ganada al
tener una tienda de control más pequeña. Por tanto, es una máquina considerablemente más rápida a
un precio ligeramente superior. Veamos si podemos hacerlo aún más rápido.
¿Qué tal si intentamos reducir el tiempo del ciclo? En gran medida, el tiempo de ciclo está
determinado por la tecnología subyacente. Cuanto más pequeños sean los transistores y más
pequeñas sean las distancias físicas entre ellos, más rápido se puede ejecutar el reloj. Para una
tecnología dada, el tiempo requerido para realizar una operación de ruta de datos completa es
fijo (al menos desde nuestro punto de vista). Sin embargo, tenemos algo de libertad y la
aprovecharemos al máximo en breve.
Nuestra otra opción es introducir más paralelismo en la máquina. Por el
momento, el Mic-2 es muy secuencial. Coloca registros en sus buses, espera a que la
ALU y la palanca de cambios los procesen y luego escribe los resultados en los
registros. Excepto por las IFU, hay poco paralelismo. Agregar paralelismo es una
oportunidad real.
Como se mencionó anteriormente, el ciclo del reloj está limitado por el tiempo necesario
para que las señales se propaguen a través de la ruta de datos. La Figura 4-3 muestra un
desglose del retraso a través de los diversos componentes durante cada ciclo. Hay tres
componentes principales en el ciclo de ruta de datos real:
En la Fig. 4-31, mostramos una nueva arquitectura de tres buses, incluida la IFU, pero
con tres pestillos (registros) adicionales, uno insertado en el medio de cada bus. Los
pestillos están escritos en cada ciclo. En efecto, estos registros dividen la ruta de datos en
distintas partes que ahora pueden operar independientemente unas de otras. Nos
referiremos a esto comoMic-3, o la canalizado modelo.
¿Cómo pueden ayudar estos registros adicionales? Ahora se necesitan tres ciclos de reloj
para usar la ruta de datos: uno para cargar los pestillos A y B, uno para ejecutar la ALU y la
palanca de cambios y cargar el pestillo C, y otro para almacenar el pestillo C nuevamente en los
registros. Seguramente esto es peor de lo que ya teníamos.
294 EL NIVEL DE MICROARQUITECTURA CAP. 4
ancho iload1 MAR = LV + MBR2U; rd; ir a iload2 Idéntica a iload1 pero usando un índice de 2 bytes
istore1 ancho MAR = LV + MBR2U; ir a istore2 MAR = Idéntica a istore1 pero usando un índice de 2 bytes Igual
ldc w1 CPP + MBR2U; rd; ir a iload2 que iload1 ancho pero indexando CPP
ireturn1 MAR = SP = LV; rd Restablecer SP, MAR para leer Link ptr
ireturn2 Esperar link ptr
ireturn3 LV = MAR = MDR; rd Configure LV, MAR para vincular ptr; leer PC antiguo
ireturn4 MAR = LV + 1 Configure MAR para que apunte a LV antiguo; leer antiguo
ireturn5 PC = MDR; rd LV Restore PC
ireturn6 MAR = SP
ireturn7 LV = MDR Restaurar LV
ireturn8 MDR = TOS; wr; ir a (MBR1) Guarde el valor de retorno en la parte superior original de la pila
2. Podemos utilizar todas las partes de la ruta de datos durante cada ciclo.
Al dividir la ruta de datos en tres partes, reducimos el retraso máximo con el resultado
de que la frecuencia del reloj puede ser mayor. Supongamos que al dividir el ciclo de la ruta
de datos en tres intervalos de tiempo, cada uno es aproximadamente 1/3 del original, por
lo que podemos triplicar la velocidad del reloj. (Esto no es totalmente realista, ya que
también hemos agregado dos registros más en la ruta de datos, pero como primera
aproximación servirá).
Porque hemos asumido que todas las lecturas y escrituras de memoria pueden
satisfacerse con la caché de nivel 1, y esta caché está hecha del mismo material que el
296 EL NIVEL DE MICROARQUITECTURA CAP. 4
Memoria
MAR control
registros
Para MDR
y
de
principal
ordenador personal
memoria
Instrucción
recuperar unidad MBR1
(SI TU)
MBR2
SP
LV
Señales de control
CPP
Habilitar en el bus B
OPC
Autobús C
Autobús B
H
Un autobús
6
ALU norte
control ALU
Z
Cambiador
Veamos ahora cómo funciona la ruta de datos del Mic-3. Antes de comenzar,
necesitamos una notación para lidiar con los pestillos. La obvia es llamarlosA, B, y C
y tratar les gustan los registros, teniendo en cuenta las limitaciones de la ruta de datos. La figura
ure 4-32 muestra una secuencia de código de ejemplo, la implementación deINTERCAMBIO Para el
Mic-2.
swap5 MAR = SP - 1; wr TOS = Escriba los TOS antiguos en el segundo lugar de la pila
Detenerse para esperar un valor necesario se llama estancamiento. Después de eso, podemos
continuar iniciando microinstrucciones en cada ciclo ya que no hay más dependencias, aunque
swap6 apenas lo hace, ya que se lee H en el ciclo posterior swap3 lo escribe. Si
swap5 había intentado leer H se habría estancado durante un ciclo.
Aunque el programa Mic-3 toma más ciclos que el programa Mic-2, aún se ejecuta más
rápido. Si llamamos tiempo de ciclo Mic-3ΔT nsec, entonces el Mic-3 requiere 11ΔT
nsec para ejecutar INTERCAMBIO. Por el contrario, el Mic-2 tarda 6 ciclos a 3ΔT cada uno, para un total de 18ΔT. La
canalización ha hecho que la máquina sea más rápida, aunque tuvimos que detenernos una vez para evitar una
dependencia.
La canalización es una técnica clave en todas las CPU modernas, por lo que es importante
comprenderla bien. En la figura 4-34 vemos la ruta de datos de la figura 4-31 ilustrada gráficamente
como una tubería. La primera columna representa lo que está sucediendo durante el ciclo 1, la segunda
columna representa el ciclo 2 y así sucesivamente (asumiendo que no hay paradas). La región
sombreada en el ciclo 1 para la instrucción 1 indica que la IFU está ocupada recuperando la instrucción
1. Un tic del reloj más tarde, durante el ciclo 2, los registros requeridos por la instrucción 1 se cargan en
los pestillos A y B mientras que al mismo tiempo en la IFU está ocupado recuperando la instrucción 2,
nuevamente mostrada por los dos rectángulos sombreados en el ciclo 2.
Durante el ciclo 3, la instrucción 1 utiliza la ALU y la palanca de cambios para
realizar su operación, los pestillos A y B se cargan para la instrucción 2 y se recupera la
instrucción 3. Finalmente, durante el ciclo 4, se están trabajando cuatro instrucciones
al mismo tiempo. Se almacenan los resultados de la instrucción 1, se realiza el trabajo
de ALU para la instrucción 2, se cargan los pestillos A y B de la instrucción 3 y se
recupera la instrucción 4.
Si hubiéramos mostrado el ciclo 5 y los ciclos posteriores, el patrón habría sido el mismo que en el
ciclo 4: las cuatro partes de la ruta de datos que pueden ejecutarse de forma independiente
SEGUNDO. 4.4 DISEÑO DEL NIVEL DE MICROARQUITECTURA 299
SI TU SI TU SI TU SI TU
Reg Reg Reg Reg
C A B C A B C A B C A B
1
ALU ALU ALU ALU
Cambiador Cambiador Cambiador Cambiador
SI TU SI TU SI TU SI TU
Reg Reg Reg Reg
C A B C A B C A B C A B
2
ALU ALU ALU ALU
Cambiador Cambiador Cambiador Cambiador
SI TU SI TU SI TU SI TU
Reg Reg Reg Reg
C A B C A B C A B C A B
3
ALU ALU ALU ALU
Instrucción
SI TU SI TU SI TU SI TU
Reg Reg Reg Reg
C A B C A B C A B C A B
4
ALU ALU ALU ALU
Cambiador Cambiador Cambiador Cambiador
Tiempo
sería haciéndolo. Este diseño representa una tubería de cuatro etapas, con etapas para
obtención de estructuras, acceso a operandos, operaciones ALU y escritura en los registros.
Es similar a la tubería de la figura 2-4 (a), excepto sin la etapa de decodificación. El punto
importante a retomar aquí es que, aunque una sola instrucción requiere cuatro ciclos de
reloj para ejecutarse, en cada ciclo de reloj se inicia una nueva instrucción y se completa
una instrucción anterior.
Otra forma de ver la figura 4-34 es seguir cada instrucción horizontalmente a lo largo de la
página. Para la instrucción 1, en el ciclo 1, las IFU están trabajando en ello. En el ciclo 2, sus
registros se colocan en los buses A y B. En el ciclo 3, la ALU y la palanca de cambios están
trabajando para ello. Finalmente, en el ciclo 4, sus resultados se almacenan nuevamente en el
300 EL NIVEL DE MICROARQUITECTURA CAP. 4
registros. Lo que hay que tener en cuenta aquí es que hay cuatro secciones del hardware
disponibles y, durante cada ciclo, una instrucción dada usa solo una de ellas, liberando las otras
secciones para diferentes instrucciones.
Una analogía útil de nuestro diseño de tuberías es una línea de montaje en una fábrica que
ensambla automóviles. Para abstraer lo esencial de este modelo, imagine que suena un gran
gong cada minuto, momento en el que todos los automóviles se mueven una estación más
adelante en la línea. En cada estación, los trabajadores realizan alguna operación en el automóvil
que se encuentra frente a ellos, como agregar el volante o instalar los frenos. A cada latido del
gong (1 ciclo), se inyecta un nuevo automóvil al inicio de la línea de montaje y un automóvil
terminado arranca al final. Por lo tanto, aunque puede llevar cientos de ciclos completar un
automóvil, en cada ciclo se completa un automóvil completo. La fábrica puede producir un
automóvil por minuto, independientemente del tiempo que lleve realmente ensamblar un
automóvil. Este es el poder de la canalización, y se aplica tanto a las CPU como a las fábricas de
automóviles.
Un punto que hemos pasado por alto es que cada microinstrucción selecciona su propio sucesor.
La mayoría de ellos simplemente selecciona el siguiente en la secuencia actual, pero el último, como
swap6, a menudo hace una bifurcación de múltiples vías, lo que atasca la tubería, ya que es imposible
continuar con la búsqueda previa después de que sea posible. Necesitamos una mejor forma de
abordar este punto.
Nuestra última microarquitectura es el Mic-4. Sus partes principales se muestran en la figura 4-35,
pero se ha suprimido una cantidad sustancial de detalles para mayor claridad. Al igual que el Mic-3,
tiene un IFU que recupera palabras de la memoria y mantiene las distintasMBRs. La IFU también
alimenta el flujo de bytes entrante a un nuevo componente, elunidad de decodificación. Esta
unidad tiene una ROM interna indexada por código de operación IJVM. Cada entrada (fila) contiene dos
partes: la longitud de esa instrucción IJVM y un índice en otra ROM, la ROM de microoperación. La
longitud de la instrucción IJVM se utiliza para permitir que la unidad de decodificación analice el flujo de
bytes entrante en instrucciones, por lo que siempre sabe qué bytes son códigos de operación y cuáles
son operandos. Si la longitud de la instrucción actual es de 1 byte (p. Ej.,MÚSICA POP), entonces la unidad
de decodificación sabe que el siguiente byte es un código de operación. Sin embargo, si la longitud de la
instrucción actual es de 2 bytes, la unidad de decodificación sabe que el siguiente byte es un operando,
seguido inmediatamente por otro código de operación. Cuando elAMPLIO se ve el prefijo, el siguiente
byte se transforma en un código de operación ancho especial, por ejemplo, AMPLIO + ILOAD se convierte
en AMPLIA ILOAD.
La unidad de decodificación envía el índice a la ROM de microoperación que encontró
en su tabla al siguiente componente, el unidad de cola. Esta unidad contiene algo de lógica
más dos tablas internas, una en ROM y otra en RAM. La ROM contiene el microprograma, y
cada instrucción IJVM tiene un número de entradas consecutivas, llamadas
microoperaciones. Las entradas deben estar en orden, así que trucos como
ancho iload2 ramificándose a iload2 en Mic-2 no están permitidos. Cada secuencia de IJVM
debe estar completa, duplicando secuencias en algunos casos.
SEGUNDO. 4.4 DISEÑO DEL NIVEL DE MICROARQUITECTURA 301
Final
Microoperación
IJVM Ir a
ROM
largo
índice Unidad de cola
1 3
2
De ROM de microoperación
memoria AÑADO
Instrucción ISUB
recuperar unidad YO CARGO
Unidad de decodificación
IFLT
Cola
de pendiente
microoperaciones
Hacia / desde
memoria
Conduce la etapa 4 ALU C METRO AB MIR1
4
7 Registros
Conduce la etapa 5 ALU C MAB MIR2
6
Conduce la etapa 7 ALU C METRO AB MIR4
C A B
ALU 5
Cambiador
con el bit Goto activado y todavía queda mucho espacio en la cola, la unidad de cola envía
una señal de confirmación de regreso a la unidad de decodificación. Cuando la unidad de
decodificación ve el acuse de recibo, envía el índice de la siguiente instrucción IJVM a la
unidad de cola.
De esta manera, la secuencia de instrucciones IJVM en la memoria se convierte
finalmente en una secuencia de microoperaciones en una cola. Estas microoperaciones
alimentanMIRs, que envían las señales para controlar la ruta de datos. Sin embargo, otro
factor que debemos considerar ahora es que los campos de cada microoperación no están
activos al mismo tiempo. losA y B Los campos estn activos durante el primer ciclo, el ALU
El campo está activo durante el segundo ciclo, el C El campo está activo durante el tercer ciclo y
cualquier operación de memoria tiene lugar en el cuarto ciclo.
Para que esto funcione correctamente, hemos introducido cuatro MIRs en la Fig. 4-35.
Al comienzo de cada ciclo de reloj (elΔw tiempo en la figura 4-3), MIR3 se copia a MIR4, MIR2 se
copia a MIR3, MIR1 se copia a MIR2, y MIR1 se carga con una nueva microoperación de la cola
de microoperaciones. Entonces cadaMIR emite sus señales de control, pero solo se utilizan
algunas de ellas. losA y B campos de MIR1 se utilizan para seleccionar los registros que
controlan los pestillos A y B, pero los ALU campo en MIR1
no se utiliza y no está conectado a nada más en la ruta de datos.
Un ciclo de reloj más tarde, esta microoperación ha pasado a MIR2 y los registros que
seleccionó ahora están sentados de forma segura en los pestillos A y B esperando que
lleguen las aventuras. SuALU El campo ahora se usa para impulsar la ALU. En el siguiente
ciclo, esC campo volverá a escribir los resultados en los registros. Después de eso, pasará a
MIR4 e iniciar cualquier operación de memoria necesaria utilizando el ahora cargado MAR
(y MDR, para escribir).
Un último aspecto del Mic-4 necesita un poco de discusión ahora: las micro-ramas. Algunas
instrucciones de IJVM, comoIFLT, necesidad de bifurcar condicionalmente en función de, digamos,
el norte poco. Cuando ocurre una micro-sucursal, la tubería no puede continuar. Para lidiar con
eso, hemos agregado el bit Goto a la microoperación. Cuando la unidad de cola activa una
microoperación con este bit establecido mientras lo copia a la cola, se da cuenta de que hay un
problema por delante y se abstiene de enviar un acuse de recibo a la unidad de decodificación.
Como resultado, la máquina se detendrá en este punto hasta que se haya resuelto la microrama.
componentes en la figura 4-35. El Mic-4 obtiene automáticamente un flujo de bytes de la memoria, los
decodifica en instrucciones IJVM, los convierte en una secuencia de microoperaciones usando una ROM
y los pone en cola para usarlos según sea necesario. Las primeras tres etapas de la canalización se
pueden vincular al reloj de la ruta de datos si se desea, pero no siempre habrá trabajo por hacer. Por
ejemplo, la IFU ciertamente no puede alimentar un nuevo código de operación IJVM a la unidad de
decodificación en cada ciclo de reloj porque las instrucciones IJVM
tardaría varios ciclos en ejecutarse y la cola desbordamiento rápido.
1 2 3 4 5 6 7
Escribir
SI TU Descifrador Cola Operandos Ejecutiva emory
METRO
espalda
Todos los fabricantes de computadoras quieren que sus sistemas funcionen lo más rápido posible.
En esta sección, veremos una serie de técnicas avanzadas que se están investigando actualmente para
mejorar el rendimiento del sistema (principalmente CPU y memoria). Debido a la naturaleza altamente
competitiva de la industria informática, el desfase entre las nuevas ideas de investigación que pueden
hacer que una computadora sea más rápida y su incorporación a los productos es sorprendentemente
corto. En consecuencia, la mayoría de las ideas que discutiremos ya están en uso en una amplia
variedad de productos existentes.
Las ideas que se discutirán se dividen aproximadamente en dos categorías: mejoras de
implementación y mejoras arquitectónicas. Las mejoras de implementación son formas de
construir una nueva CPU o memoria para que el sistema funcione más rápido sin cambiar
la arquitectura. Modificar la implementación sin cambiar la arquitectura significa que los
programas antiguos se ejecutarán en la nueva máquina, un importante punto de venta.
Una forma de mejorar la implementación es utilizar un reloj más rápido, pero esto es
304 EL NIVEL DE MICROARQUITECTURA CAP. 4
Uno de los aspectos más desafiantes del diseño de computadoras a lo largo de la historia ha
sido proporcionar un sistema de memoria capaz de proporcionar operandos al procesador a la
velocidad con la que puede procesarlos. La reciente alta tasa de crecimiento en la velocidad del
procesador no ha ido acompañada de una aceleración correspondiente en las memorias. En
relación con las CPU, los recuerdos se han vuelto más lentos durante décadas. Dada la enorme
importancia de la memoria primaria, esta situación ha limitado en gran medida el desarrollo de
sistemas de alto rendimiento y ha estimulado la investigación sobre formas de sortear el
problema de las velocidades de la memoria que son mucho más lentas que las velocidades de la
CPU y, en términos relativos, empeoran cada año. .
Los procesadores modernos imponen demandas abrumadoras a un sistema de memoria, en
términos de latencia (el retraso en el suministro de un operando) y ancho de banda (la cantidad de
datos suministrados por unidad de tiempo). Desafortunadamente, estos dos aspectos de un sistema de
memoria están en gran parte reñidos. Muchas técnicas para aumentar el ancho de banda lo hacen solo
aumentando la latencia. Por ejemplo, las técnicas de canalización utilizadas en el Mic-3 se pueden
aplicar a un sistema de memoria, con múltiples solicitudes de memoria superpuestas manejadas de
manera eficiente. Desafortunadamente, al igual que con el Mic-3, esto da como resultado una mayor
latencia para las operaciones de memoria individuales. A medida que las velocidades de reloj del
procesador se vuelven más rápidas, se vuelve cada vez más difícil proporcionar un sistema de memoria
capaz de suministrar operandos en uno o dos ciclos de reloj.
Una forma de atacar este problema es proporcionando cachés. Como vimos en la Sec.
2.2.5, un caché contiene las palabras de memoria utilizadas más recientemente en una memoria pequeña y
rápida, lo que acelera el acceso a ellas. Si hay un porcentaje suficientemente grande de las palabras de
memoria necesarias en la memoria caché, la latencia de memoria efectiva se puede reducir enormemente.
SEGUNDO. 4.5 MEJORANDO EL DESEMPEÑO 305
Una de las formas más efectivas de mejorar tanto el ancho de banda como la latencia es usar
múltiples cachés. Una técnica básica que funciona de manera muy eficaz es introducir una caché
separada para instrucciones y datos. Hay varios beneficios de tener cachés separados para
instrucciones y datos, a menudo llamadoscaché dividido. Primero, las operaciones de memoria se
pueden iniciar de forma independiente en cada caché, duplicando efectivamente el ancho de banda del
sistema de memoria. Es por eso que tiene sentido proporcionar dos puertos de memoria separados,
como hicimos en el Mic-1: cada puerto tiene su propia caché. Tenga en cuenta que cada caché tiene
acceso independiente a la memoria principal.
Hoy en día, muchos sistemas de memoria son más complicados que esto, y una caché
adicional, llamada caché de nivel 2, puede residir entre las cachés de instrucciones y datos y la
memoria principal. De hecho, como se requieren sistemas de memoria más sofisticados, puede
haber tres o más niveles de caché. En la figura 4-37 vemos un sistema con tres niveles de caché.
El chip de la CPU en sí contiene una pequeña caché de instrucciones y una pequeña caché de
datos, normalmente de 16 KB a 64 KB. Luego está el caché de nivel 2, que no está en el chip de la
CPU pero puede estar incluido en el paquete de la CPU, junto al chip de la CPU y conectado a él
mediante una ruta de alta velocidad. Esta caché generalmente está unificada y contiene una
combinación de datos e instrucciones. Un tamaño típico para la caché L2 es de 512 KB a 1 MB. La
caché de tercer nivel está en la placa del procesador y consta de unos pocos megabytes de SRAM,
que es mucho más rápida que la memoria DRAM principal.
Los cachés son generalmente inclusivos, con el contenido de la caché de nivel 1 está en
la caché de caché de y el completo completo del nivel la caché 2 está en el nivel 3
nivel 2.
UPC
paquete
Chip de la CPU
Unificado
L2 Unificado
cache Caché L3
L1-I L1-D
Principal
memoria
(DRACMA)
Procesador
tablero
Teclado Gráficos Disco
controlador controlador controlador
Para lograr su objetivo, las cachés dependen de dos tipos de localidad de dirección. Localidad
espacial es la observación de que es probable que se acceda a ubicaciones de memoria con direcciones
numéricamente similares a una ubicación de memoria a la que se ha accedido recientemente
306 EL NIVEL DE MICROARQUITECTURA CAP. 4
futuro. Los cachés intentan explotar esta propiedad al traer más datos de los que se han solicitado, con
la expectativa de que se puedan anticipar solicitudes futuras.Localidad temporal se produce cuando se
vuelve a acceder a ubicaciones de memoria a las que se ha accedido recientemente. Esto puede ocurrir,
por ejemplo, en ubicaciones de memoria cerca de la parte superior de la pila o instrucciones dentro de
un bucle. La localidad temporal se explota en los diseños de caché principalmente mediante la elección
de qué descartar en una falla de caché. Muchos algoritmos de reemplazo de caché explotan la localidad
temporal descartando aquellas entradas a las que no se ha accedido recientemente.
Todas las cachés utilizan el siguiente modelo. La memoria principal se divide en bloques de
tamaño fijo llamadoslíneas de caché. Una línea de caché generalmente consta de 4 a 64 bytes
consecutivos. Las líneas se numeran consecutivamente comenzando en 0, por lo que con un tamaño de
línea de 32 bytes, la línea 0 es de 0 a 31 bytes, la línea 1 es de 32 a 63, y así sucesivamente. En cualquier
momento, algunas líneas están en la caché. Cuando se hace referencia a la memoria, el circuito del
controlador de caché comprueba si la palabra a la que se hace referencia se encuentra actualmente en
la caché. Si es así, se puede usar el valor allí, guardando un viaje en la memoria principal. Si la palabra
no está allí, se elimina alguna entrada de línea del caché y la línea necesaria se recupera de la memoria
o del caché más distante para reemplazarla. Existen muchas variaciones de este esquema, pero en
todas ellas la idea es mantener las líneas más utilizadas en la caché tanto como sea posible, para
maximizar el número de referencias de memoria satisfechas fuera de la caché.
La caché más simple se conoce como caché de asignación directa. En la figura 4-38 (a) se
muestra un ejemplo de caché de asignación directa de un solo nivel. Este ejemplo de caché contiene
2048 entradas. Cada entrada (fila) en la caché puede contener exactamente una línea de caché de la
memoria principal. Con un tamaño de línea de caché de 32 bytes (para este ejemplo), el caché puede
contener 2048 entradas de 32 bytes o 64 KB en total. Cada entrada de caché consta de tres partes:
1. El Válido bit indica si hay datos válidos en esta entrada o no. Cuando se
inicia el sistema (se inicia), todas las entradas se marcan como
inválidas.
2. El Etiqueta El campo consta de un valor único de 16 bits que identifica la línea de
memoria correspondiente de la que proceden los datos.
3. El Datos El campo contiene una copia de los datos en la memoria. Este campo
contiene una línea de caché de 32 bytes.
Válido
Direcciones que usan esta entrada
Etiqueta Datos
Entrada
7
6
5
4
3 96-127, 65632-65663, 131168-131199
2 64-95, 65600-65631, 131136-131167,…
1 32-63, 65568-65599, 131104-131135,… 0-31,
0 65536-65567, 131072-131103,…
(a)
Bits dieciséis 11 3 2
(B)
Figura 4-38. (a) Una caché mapeada directamente. (b) Una dirección virtual de 32 bits.
3. El PALABRA campo indica a qué palabra dentro de una línea se hace referencia.
4. El BYTE Por lo general, el campo no se usa, pero si solo se solicita un solo byte,
indica qué byte dentro de la palabra se necesita. Para una caché que solo
proporciona palabras de 32 bits, este campo siempre será 0.
Cuando la CPU produce una dirección de memoria, el hardware extrae los 11 LÍNEA
bits de la dirección y los usa para indexar en la caché para encontrar una de las 2048 entradas. Si
esa entrada es válida, elETIQUETA campo de la dirección de memoria y el Etiqueta se comparan los
campos en la entrada de la caché. Si están de acuerdo, la entrada de la caché contiene la palabra
solicitada, una situación llamadagolpe de caché. Con un acierto, una palabra que se lee se puede
sacar de la caché, eliminando la necesidad de ir a la memoria. Solo la palabra realmente
necesaria se extrae de la entrada de la caché. El resto de la entrada no se utiliza. Si la entrada de
la caché no es válida o las etiquetas no coinciden, la entrada necesaria no está presente en la
caché, una situación llamadafalta de caché. En este caso, la línea de caché de 32 bytes se obtiene
de la memoria y se almacena en la entrada de caché, reemplazando lo que estaba allí. Sin
embargo, si la entrada de caché existente se ha modificado desde que se cargó, se debe volver a
escribir en la memoria principal antes de sobrescribirla.
308 EL NIVEL DE MICROARQUITECTURA CAP. 4
Como se mencionó anteriormente, muchas líneas diferentes en la memoria compiten por las
mismas ranuras de caché. Si un programa que usa la memoria caché de la figura 4-38 (a) usa mucho
palabras en las direcciones 0 y 65.536, habrá conflictos constantes, con cada referencia potencialmente
expulsando a la otra de la memoria caché. Una solución es permitir dos o más líneas en cada entrada de
caché. Un caché connorte posibles entradas para cada dirección se llama un caché asociativo de
conjuntos de n vías. En la figura 4-39 se ilustra una caché asociativa de conjuntos de cuatro vías.
7
6
5
4
3
2
1
0
Llevado al extremo, también es posible una caché de 2048 vías que contenga un solo conjunto de
entradas de 2048 líneas. Aquí, todas las direcciones de memoria se asignan a un solo conjunto, por lo
que la búsqueda requiere comparar la dirección con las 2048 etiquetas de la caché. Tenga en cuenta
que ahora cada entrada debe tener una lógica de coincidencia de etiquetas. Desde elLÍNEA El campo es
de longitud 0, el ETIQUETA El campo es la dirección completa excepto por el PALABRA y BYTE los campos.
Además, cuando se reemplaza una línea de caché, todas las 2048 ubicaciones son posibles candidatos
para el reemplazo. Mantener una lista ordenada de 2048 entradas requiere una gran cantidad de
contabilidad, lo que hace que el reemplazo de LRU no sea factible. (Recuerde que esta lista debe
actualizarse en cada operación de memoria, no solo en un error). Sorprendentemente, los cachés de
alta asociatividad no mejoran mucho el rendimiento sobre los cachés de baja asociatividad en la
mayoría de las circunstancias y, en algunos casos, funcionan peor. Por estas razones, la asociatividad de
conjuntos más allá de cuatro vías es relativamente inusual.
Por último, las escrituras plantean un problema especial para las cachés. Cuando un procesador
escribe una palabra y la palabra está en la caché, obviamente debe actualizar la palabra o descartar la
entrada de la caché. Casi todos los diseños actualizan la caché. Pero, ¿qué pasa con la actualización de la
copia en la memoria principal? Esta operación se puede aplazar hasta más tarde, cuando la línea de
caché esté lista para ser reemplazada por el algoritmo LRU. Esta elección es difícil,
310 EL NIVEL DE MICROARQUITECTURA CAP. 4
Las computadoras modernas están altamente canalizadas. La tubería de la figura 4-36 tiene siete
etapas; Las computadoras de gama alta a veces tienen tuberías de 10 etapas o incluso más. La
canalización funciona mejor en código lineal, por lo que la unidad de búsqueda puede leer palabras
consecutivas de la memoria y enviarlas a la unidad de decodificación antes de que se necesiten.
El único problema menor con este maravilloso modelo es que no es el más mínimo
realista. Los programas no son secuencias de códigos lineales. Están llenas de instrucciones
de bifurcación. Considere los enunciados simples de la figura 4-40 (a). Una variable,I, se
compara con 0 (probablemente la prueba más común en la práctica). Dependiendo del
resultado, otra variable,k, se le asigna uno de los dos valores posibles.
(a) (B)
Por molestas que sean las ramas incondicionales, las ramas condicionales son peores. No
solo tienen ranuras de retardo, sino que ahora la unidad de búsqueda no sabe desde dónde leer
hasta mucho más tarde en la canalización. Las primeras máquinas canalizadas soloestancado
hasta que se supo si la rama sería tomada o no. Detener tres o cuatro ciclos en
cada rama condicional, especialmente si el 20% de las instrucciones son ramas
condicionales, causa estragos en el rendimiento.
En consecuencia, lo que hacen la mayoría de las máquinas cuando llegan a una rama
condicional es predecir si se tomará o no. Sería bueno si pudiéramos conectar una bola de
cristal en una ranura PCIe libre (o mejor aún, en la IFU) para ayudar con la predicción, pero
hasta ahora este enfoque no ha dado frutos.
A falta de un periférico tan agradable, se han ideado varias formas de hacer la predicción.
Una forma muy simple es la siguiente: suponga que todos los condicionales hacia atrás
312 EL NIVEL DE MICROARQUITECTURA CAP. 4
Hay dos formas de hacerlo. La primera forma es permitir que las instrucciones obtenidas
después de una rama condicional predicha se ejecuten hasta que intenten cambiar el estado de
la máquina (por ejemplo, almacenar en un registro). En lugar de sobrescribir el registro, el valor
calculado se coloca en un registro temporal (secreto) y solo se copia en el registro real después
de que se sabe que la predicción fue correcta. La segunda forma es registrar el valor de cualquier
registro que esté a punto de sobrescribirse (por ejemplo, en un registro cero secreto), para que la
máquina pueda volver al estado que tenía en el momento de la bifurcación mal pronosticada.
Ambas soluciones son complejas y requieren una contabilidad de nivel industrial para hacerlas
bien. Y si se golpea una segunda rama condicional antes de que se sepa si la primera se predijo
correctamente, las cosas pueden complicarse mucho.
Hay varias formas de organizar la tabla de historial. De hecho, estas son precisamente las mismas formas
que se utilizan para organizar un caché. Considere una máquina con instrucciones de 32 bits que están
alineadas con palabras de modo que los 2 bits de orden inferior de cada dirección de memoria sean
SEGUNDO. 4.5 MEJORANDO EL DESEMPEÑO 313
Rama/ Predicción
Válido sin rama Válido
Predicción
Válido bits
Rama Rama Rama Objetivo
bits
Espacio dirección / etiqueta Espacio dirección / etiqueta Espacio dirección / etiqueta Dirección
6 6 6
5 5 5
4 4 4
3 3 3
2 2 2
1 1 1
0 0 0
Figura 4-41. (a) Un bit de 1 historia de la sucursal. (b) Un historial de bifurcaciones de 2 bits. (c) Un mapa-
ping entre la dirección de instrucción de bifurcación y la dirección de destino.
00. Con una tabla de historial mapeada directamente que contiene 2norte entradas, el orden bajo n + Se
pueden extraer 2 bits de una dirección de destino de instrucción de bifurcación y desplazarlos 2 bits a la
derecha. Estanorte-El número de bit se puede usar como un índice en la tabla de historial donde se
realiza una verificación para ver si la dirección almacenada allí coincide con la dirección de la sucursal. Al
igual que con un caché, no es necesario almacenar losn + 2 bits, por lo que se pueden omitir (es decir,
solo se almacenan los bits de la dirección superior, la etiqueta). Si hay un acierto, el bit de predicción se
usa para predecir la rama. Si la etiqueta incorrecta está presente o la entrada no es válida, se produce
un error, al igual que con un caché. En este caso, se puede utilizar la regla de bifurcación hacia
adelante / hacia atrás.
Si la tabla del historial de sucursales tiene, digamos, 4096 entradas, entonces se ramifica en las direcciones 0,
16384, 32768, ... entrará en conflicto, de forma análoga al mismo problema con un caché. La
misma solución es posible: bidireccional, cuádruple onorte-forma de entrada asociativa. Al igual
que con un caché, el caso límite es un solonorte-forma de entrada asociativa, que requiere
asociatividad total de búsqueda.
Dado un tamaño de tabla suficientemente grande y suficiente asociatividad, este esquema
funciona bien en la mayoría de las situaciones. Sin embargo, siempre ocurre un problema sistemático.
Cuando finalmente se sale de un bucle, la rama al final se predecirá mal y, lo que es peor, la predicción
errónea cambiará el bit en la tabla de historial para indicar una predicción futura de "sin rama". La
próxima vez que se ingrese al bucle , la rama al final de la primera iteración se predecirá
incorrectamente. Si el bucle está dentro de un bucle externo, o en un procedimiento llamado con
frecuencia, este error puede ocurrir con frecuencia.
Para eliminar este error de predicción, podemos darle una segunda oportunidad a la entrada de la
tabla. Con este método, la predicción se cambia solo después de dos predicciones incorrectas
consecutivas. Este enfoque requiere tener dos bits de predicción en la tabla de historial, uno para lo que
"se supone" que debe hacer la rama y otro para lo que hizo la última vez, como se muestra en la figura
4-41 (b).
Una forma ligeramente diferente de ver este algoritmo es verlo como una máquina de
estados finitos con cuatro estados, como se muestra en la figura 4-42. Después de una serie de
predicciones consecutivas exitosas de '' sin bifurcación '', el FSM estará en el estado 00 y predecirá
314 EL NIVEL DE MICROARQUITECTURA CAP. 4
"sin rama" la próxima vez. Si esa predicción es incorrecta, pasará al estado 01, pero también
predecirá "sin rama" la próxima vez. Solo si esta predicción es incorrecta, ahora pasará al estado
11 y predecirá las ramas todo el tiempo. En efecto, el bit más a la izquierda del estado es la
predicción y el bit más a la derecha es lo que hizo la rama la última vez. Si bien este diseño usa
solo 2 bits de historia, un diseño que realiza un seguimiento de 4 u 8 bits de historia
La historia también es posible.
Sin sucursal
Rama Rama
01 10 No
00 Rama rama 11
Predecir Predecir
Predecir sin rama rama Predecir
sin rama No uno mas uno mas Rama rama
rama tiempo tiempo
Sin sucursal
Figura 4-42. Una máquina de estados finitos de 2 bits para la predicción de ramas.
Este no es nuestro primer FSM. La figura 4-28 también era un FSM. De hecho, todos nuestros
microprogramas pueden considerarse FSM, ya que cada línea representa un estado específico en el que
puede estar la máquina, con transiciones bien definidas a un conjunto finito de otros estados. Los FSM
se utilizan ampliamente en todos los aspectos del diseño de hardware.
Hasta ahora, hemos asumido que el objetivo de cada rama condicional se conocía,
normalmente como una dirección explícita a la que se bifurca (contenida dentro de la
propia instrucción), o como un desplazamiento relativo de la instrucción actual (es
decir, un número con signo para agregar al contador de programas). A menudo, esta
suposición es válida, pero algunas instrucciones de rama condicional calculan la
dirección de destino haciendo aritmética en los registros y luego yendo allí. Incluso si
el FSM de la figura 4-42 predice con precisión que se tomará la rama, tal predicción no
sirve de nada si se desconoce la dirección de destino. Una forma de lidiar con esta
situación es almacenar la dirección real bifurcada hasta la última vez en la tabla de
historial, como se muestra en la figura 4-41 (c). De esta forma, si la tabla dice que la
última vez que se tomó la sucursal en la dirección 516 fue a la dirección 4000,
Todas las técnicas de predicción de ramas discutidas hasta ahora son dinámicas, es decir, se
llevan a cabo en tiempo de ejecución mientras el programa se está ejecutando. También se
adaptan al comportamiento actual del programa, lo cual es bueno. La desventaja es que
requieren un hardware costoso y especializado y una gran complejidad de chip.
Una forma diferente de hacerlo es contar con la ayuda del compilador. Cuando el compilador ve una
declaración como
sabe muy bien que la rama al final del ciclo se tomará casi todo el tiempo. Si tan solo tuviera
una forma de avisarle al hardware, se podría ahorrar mucho esfuerzo.
Aunque se trata de un cambio de arquitectura (y no solo un problema de implementación),
algunas máquinas, como UltraSPARC III, tienen un segundo conjunto de instrucciones de
bifurcación condicionales, además de las normales (que son necesarias para la compatibilidad
con versiones anteriores). Los nuevos contienen un bit en el que el compilador puede especificar
que cree que la rama se tomará (o no). Cuando se encuentra uno de estos, la unidad de
búsqueda simplemente hace lo que se le ha dicho. Además, no es necesario desperdiciar un
espacio precioso en la tabla del historial de la sucursal para estas instrucciones, lo que reduce los
conflictos allí.
Finalmente, nuestra última técnica de predicción de ramas se basa en la elaboración de
perfiles (Fisher y Freudenberger, 1992). Esto también es una técnica estática, pero en lugar de
que el compilador intente averiguar qué ramas se tomarán y cuáles no, el programa se ejecuta
realmente (generalmente en un simulador) y se captura el comportamiento de la rama. Esta
información se alimenta al compilador, que luego usa las instrucciones especiales de bifurcación
condicional para decirle al hardware qué hacer.
La mayoría de las CPU modernas son tanto canalizadas como superescalares, como se muestra en la
figura 2-6. Lo que esto generalmente significa es que una unidad de búsqueda extrae palabras de instrucción
de la memoria antes de que se necesiten para alimentar una unidad de decodificación. La unidad de
decodificación emite las instrucciones decodificadas a las unidades funcionales adecuadas para su ejecución.
En algunos casos, puede dividir instrucciones individuales en microoperaciones antes de emitirlas,
dependiendo de lo que puedan hacer las unidades funcionales.
Claramente, el diseño de la máquina es más simple si todas las instrucciones se ejecutan en
el orden en que se obtienen (asumiendo por el momento que el algoritmo de predicción de rama
nunca adivina mal). Sin embargo, la ejecución en orden no siempre ofrece un rendimiento
óptimo debido a las dependencias entre instrucciones. Si una instrucción necesita un valor
calculado por la instrucción anterior, la segunda no puede comenzar a ejecutarse hasta que la
primera haya producido el valor necesario. En esta situación (una dependencia de RAW), la
segunda instrucción tiene que esperar. También existen otros tipos de dependencias, como
veremos pronto.
316 EL NIVEL DE MICROARQUITECTURA CAP. 4
En un intento por solucionar estos problemas y producir un mejor rendimiento, algunas CPU
permiten que se omitan las instrucciones dependientes para acceder a instrucciones futuras que
no son dependientes. No hace falta decir que el algoritmo interno de programación de
instrucciones utilizado debe producir el mismo efecto que si el programa se ejecutara en el orden
en que se escribió. Ahora demostraremos cómo funciona el reordenamiento de instrucciones
usando un ejemplo detallado.
Para ilustrar la naturaleza del problema, comenzaremos con una máquina que siempre
emite instrucciones en el orden del programa y también requiere que completen la ejecución en
el orden del programa. El significado de este último se aclarará más adelante.
Nuestra máquina de ejemplo tiene ocho registros visibles para el programador, R0
mediante R7. Todas las instrucciones aritméticas usan tres registros: dos para los operandos
y uno para el resultado, lo mismo que el Mic-4. Supondremos que si una instrucción se
decodifica en ciclonorte, la ejecución comienza en ciclo n + 1. Para una instrucción simple,
como una suma o resta, la escritura en el registro de destino ocurre al final del ciclo. n + 2.
Para una instrucción más complicada, como una multiplicación, la escritura diferida ocurre
al final del ciclo. n + 3. Para que el ejemplo sea realista, permitiremos que la unidad de
decodificación emita hasta dos instrucciones por ciclo de reloj. Las CPU superescalares
comerciales a menudo pueden emitir cuatro o incluso seis instrucciones por ciclo de reloj.
Figura 4-43. Una CPU superescalar con problemas en orden y finalización en orden.
En máquinas reales, el marcador también realiza un seguimiento del uso de la unidad funcional,
para evitar emitir una instrucción para la que no hay una unidad funcional disponible. Para simplificar,
asumiremos que siempre hay una unidad funcional adecuada disponible, por lo que no mostraremos
las unidades funcionales en el marcador.
La primera línea de la figura 4-43 muestra I1 (instrucción 1), que multiplica R0 por R1
y pone el resultado en R3. Dado que ninguno de estos registros está todavía en uso, se emite la
instrucción y el marcador se actualiza para reflejar que R0 y R1 están siendo leídos y R3 se está
escribiendo. Ninguna instrucción posterior puede escribir en ninguno de estos o puede leerR3
hasta que I1 se haya retirado. Dado que esta instrucción es una multiplicación, se terminará al
final del ciclo 4. Los valores del marcador que se muestran en cada línea reflejan su estado
después de que se haya emitido la instrucción en esa línea. Los espacios en blanco son ceros.
318 EL NIVEL DE MICROARQUITECTURA CAP. 4
Dado que nuestro ejemplo es una máquina superescalar que puede emitir dos instrucciones
por ciclo, se emite una segunda instrucción (I2) durante el ciclo 1. Agrega R0 y R2, almacenar el
resultado en R4. Para ver si se puede emitir esta instrucción, se aplican estas reglas:
Ya hemos visto dependencias RAW, que ocurren cuando una instrucción necesita usar como
fuente un resultado que una instrucción anterior aún no ha producido. Las otras dos
dependencias son menos graves. Son esencialmente conflictos de recursos. en unDependencia
de WAR (Write After Read), una instrucción está tratando de sobrescribir un registro que una
instrucción anterior aún no ha terminado de leer. ADependencia WAW (Write After Write) es
similar. A menudo, estos pueden evitarse haciendo que la segunda instrucción coloque sus
resultados en otro lugar (quizás temporalmente). Si no existe ninguna de las tres dependencias
anteriores y la unidad funcional que necesita está disponible, se emite la instrucción. En este
caso, I2 usa un registro (R0) que está siendo leído por una instrucción pendiente, pero esta
superposición está permitida, por lo que se emite I2. Del mismo modo, I3 se emite durante el
ciclo 2.
Ahora llegamos a I4, que necesita usar R4. Desafortunadamente, vemos en la línea 3 que R4 se está
escribiendo. Aquí tenemos una dependencia RAW, por lo que la unidad de decodificación se detiene hastaR4 se
vuelve disponible. Mientras está detenido, deja de extraer instrucciones de la unidad de recuperación. Cuando
los búferes internos de la unidad de búsqueda se llenan, se detiene la búsqueda previa.
Vale la pena señalar que la siguiente instrucción en el orden del programa, I5, no tiene
conflictos con ninguna de las instrucciones pendientes. Podría haber sido decodificado y emitido
si no fuera por el hecho de que este diseño requiere emitir instrucciones en orden.
Ahora veamos lo que sucede durante el ciclo 3. I2, siendo una suma (dos ciclos),
termina al final del ciclo 3. Desafortunadamente, no se puede retirar (liberando así R4
para I4). ¿Por qué no? La razón es que este diseño también requiere un retiro en
orden. ¿Por qué? ¿Qué daño podría provenir de hacer la tienda en
R4 ahora y marcarlo como disponible?
La respuesta es sutil, pero importante. Suponga que las instrucciones pudieran completarse
fuera de orden. Entonces, si ocurriera una interrupción, sería difícil guardar el estado de la
máquina para poder restaurarla más tarde. En particular, no sería posible decir que se han
ejecutado todas las instrucciones hasta alguna dirección y que no todas las instrucciones
posteriores. A esto se le llamainterrupción precisa y es una característica deseable en una CPU
(Moudgill y Vassiliadis, 1996). La retirada fuera de servicio hace que las interrupciones sean
imprecisas, por lo que algunas máquinas completan las instrucciones en orden.
Volviendo a nuestro ejemplo, al final del ciclo 4, las tres instrucciones pendientes se pueden
retirar, por lo que en el ciclo 5 finalmente se puede emitir I4, junto con el I5 recién decodificado.
Siempre que se retira una instrucción, la unidad de decodificación debe verificar si hay una
instrucción detenida que ahora se puede emitir.
SEGUNDO. 4.5 MEJORANDO EL DESEMPEÑO 319
Figura 4-44. Operación de una CPU superescalar con problema de avería y finalización
fuera de orden.
evensum = 0; evensum = 0;
oddsum = 0;
oddsum = 0;
i = 0;
i = 0;
i> = límite
while (i <límite) { mientras (i <límite)
k = yo * yo * yo;
k = yo * yo * yo;
si (((i / 2) * 2) == i) si ((i / 2) * 2) = = i)
evensum = evensum + k; T F
i = i + 1;
i = i + 1;
}
(a) (B)
Figura 4-45. (a) Un fragmento de programa. (b) El gráfico de bloques básico correspondiente.
El problema es que la mayoría de los bloques básicos son cortos y no hay suficiente paralelismo en ellos
para explotarlos de manera efectiva. En consecuencia, el siguiente paso es permitir que el reordenamiento
cruce los límites de los bloques básicos en un intento de llenar todos los espacios de emisión. Las mayores
ganancias se obtienen cuando una operación potencialmente lenta se puede mover hacia arriba en el gráfico
para comenzar temprano. Esto podría ser unCARGA instrucción, una operación de punto flotante, o incluso el
comienzo de una larga cadena de dependencia. Mover el código hacia arriba sobre una rama se llamaizar.
Imagine que en la figura 4-45 todas las variables se mantuvieron en registros excepto
evensum y oddsumpor falta de registros). Entonces podría tener sentido mover su
CARGA instrucciones en la parte superior del bucle, antes de calcular k, para que comiencen desde
el principio, por lo que los valores estarán disponibles cuando sea necesario. Por supuesto, solo
uno de ellos será necesario en cada iteración, por lo que el otroCARGA se desperdiciará, pero si la
memoria caché y la memoria están canalizadas y hay espacios disponibles para problemas,
puede que valga la pena hacerlo. Ejecutar código antes de que se sepa si va a ser necesario se
llamaejecución especulativa. El uso de esta técnica requiere el soporte del compilador y el
hardware, así como algunas extensiones arquitectónicas. Normalmente, reordenar las
instrucciones sobre los límites de los bloques básicos está más allá de la capacidad del hardware,
por lo que el compilador debe mover las instrucciones explícitamente.
322 EL NIVEL DE MICROARQUITECTURA CAP. 4
si (x> 0) z = y / x;
dónde x, y, y z son variables de coma flotante. Suponga que todas las variables se
recuperan en registros de antemano y que la división (lenta) de punto flotante se eleva por
encima de lasi prueba. Desafortunadamente,X es 0 y la trampa resultante de dividir por
cero termina el programa. El resultado neto es que la especulación ha provocado que un
programa correcto falle. Peor aún, el programador puso un código explícito para evitar esta
situación y sucedió de todos modos. No es probable que esta situación lleve a un
programador feliz.
Una posible solución es tener versiones especiales de instrucciones que puedan causar
excepciones. Además, un poco, llamadoun poco de veneno se agrega a cada registro. Cuando
una instrucción especulativa especial falla, en lugar de causar una trampa, establece la
SEGUNDO. 4.5 MEJORANDO EL DESEMPEÑO 323
bit de veneno en el registro de resultados. Si ese registro es tocado más tarde por una instrucción
regular, la trampa ocurre entonces (como debería). Sin embargo, si el resultado nunca se usa, el bit de
veneno finalmente se borra y no se produce ningún daño.
En el exterior, el Core i7 parece ser una máquina CISC tradicional, con procesadores
que admiten un conjunto de instrucciones enorme y difícil de manejar que admite
operaciones de enteros de 8, 16 y 32 bits, así como funciones flotantes de 32 y 64 bits.
operaciones puntuales. Tiene solo ocho registros visibles por procesador y no hay dos
iguales. Las longitudes de las instrucciones varían de 1 a 17 bytes. En resumen, es una
arquitectura heredada que parece hacer todo mal.
Sin embargo, en el interior, el Core i7 contiene un núcleo RISC moderno, delgado y medio,
profundamente canalizado que se ejecuta a una frecuencia de reloj extremadamente rápida que
probablemente aumentará en los próximos años. Es bastante sorprendente cómo los ingenieros de
Intel lograron construir un procesador de última generación para implementar una arquitectura
antigua. En esta sección veremos la microarquitectura Core i7 para ver cómo funciona.
Al subsistema de memoria
Nivel 1
Interfaz del sistema
caché de datos
Nivel 1 Rama
caché inst vaticinador
Figura 4-46. El diagrama de bloques de la microarquitectura Sandy Bridge del Core i7.
caché asociativo con líneas de caché de 64 bytes. La caché L3 compartida varía en tamaño
de 1 MB a 20 MB. Si paga más efectivo a Intel, obtiene más caché a cambio.
Independientemente de su tamaño, el L3 está organizado como un caché asociativo de 12
vías con líneas de caché de 64 bytes. En el caso de que se pierda un acceso a la caché L3, se
envía a la RAM externa a través del bus RAM DDR3.
Asociadas con la caché L1 hay dos unidades de captación previa (no se muestran en la
figura) que intentan captar datos de niveles inferiores del sistema de memoria en la L1 antes de
que sean necesarios. Una unidad de captación previa capta previamente el siguiente bloque de
memoria cuando detecta que se está captando un "flujo" secuencial de memoria en el
procesador. Un segundo prefetcher, más sofisticado, rastrea la secuencia de direcciones de
cargas y almacenes de programas específicos. Si progresan con paso regular (p. Ej., 0x1000 ...
0x1020 ... 0x1040 ...) precargará el siguiente elemento al que probablemente se accederá antes
del programa. Esta captación previa orientada a zancadas hace maravillas para los programas
que marchan a través de matrices de variables estructuradas.
El subsistema de memoria de la figura 4-46 está conectado tanto al front-end como al caché de
datos L1. El front-end es responsable de obtener instrucciones del subsistema de memoria,
decodificarlas en microoperaciones similares a RISC y almacenarlas en dos cachés de almacenamiento
de instrucciones. Todas las instrucciones obtenidas se colocan en la caché de instrucciones L1 (nivel 1).
La caché L1 tiene un tamaño de 32 KB, organizada como una caché asociativa de 8 vías con bloques de
64 bytes. A medida que las instrucciones se obtienen de la caché L1, ingresan a los decodificadores que
determinan la secuencia de microoperaciones utilizadas para
SEGUNDO. 4.6 EJEMPLOS DEL NIVEL DE MICROARQUITECTURA 325
La figura 4-47 es una versión simplificada de la microarquitectura de Sandy Bridge que muestra la tubería.
En la parte superior está la interfaz, cuyo trabajo es recuperar instrucciones de la memoria y prepararlas para
su ejecución. El front-end recibe nuevas instrucciones x86 desde la caché de instrucciones L1. Los decodifica en
microoperaciones para su almacenamiento en la caché de microoperaciones, que contiene aproximadamente
1.5K microoperaciones. Una caché de microoperaciones de este tamaño funciona de manera comparable a una
caché L0 convencional de 6 KB. El caché de microoperaciones contiene grupos de seis microoperaciones en una
sola línea de seguimiento. Por más tiempo
sucesivas de microoperaciones, se pueden enlazar varias líneas de seguimiento.
Nivel 1
caché inst
Rama
vaticinador/
Parte delantera
Unidad de decodificación Rama
fin objetivo
buffer
Compartir
Microoperación
Caché L3
cache Nivel 2
unificado
cache
Fuera- Asignar / cambiar el nombre de la unidad
de-
pedido
control No- Memoria
programador de memoria planificador
Nivel 1
datos
Unidad de retiro cache
Figura 4-47. Una vista simplificada de la ruta de datos del Core i7.
Para una rama tomada el BTB (búfer de destino de rama) se consulta para determinar la
dirección de destino. El BTB contiene la dirección de destino de la sucursal la última vez que se
tomó. La mayoría de las veces esta dirección es correcta (de hecho, siempre es correcta para
ramas con un desplazamiento constante). Ramas indirectas, como las que utilizan las llamadas a
funciones virtuales y C ++cambiar declaraciones, van a muchas direcciones, y la BTB puede
predecirlas erróneamente.
La segunda parte de la canalización, la lógica de control fuera de orden, se alimenta desde la memoria caché de
microoperaciones. A medida que cada micro-operación ingresa desde el extremo frontal, hasta cuatro por ciclo, el
unidad de asignación / cambio de nombre lo registra en una tabla de 168 entradas llamada ROBAR
(Búfer de reorden). Esta entrada realiza un seguimiento del estado de la microoperación hasta que se
retira. La unidad de asignación / cambio de nombre luego verifica si los recursos que necesita el
microop están disponibles. Si es así, la microoperación se pone en cola para su ejecución en uno de los
planificador colas. Se mantienen colas separadas para microoperaciones de memoria y no memoria. Si
una microoperación no se puede ejecutar, se retrasa, pero las microoperaciones posteriores se
procesan, lo que lleva a una ejecución desordenada de las microoperaciones. Esta estrategia fue
diseñada para mantener todas las unidades funcionales lo más ocupadas posible. Hasta 154
instrucciones pueden estar en vuelo en cualquier instante, y hasta 64 de estas pueden cargarse desde la
memoria y hasta 36 pueden almacenarse en la memoria.
A veces, una micro-operación se detiene porque necesita escribir en un registro que está
siendo leído o escrito por una micro-operación anterior. Estos conflictos se denominan
dependencias WAR y WAW, respectivamente, como vimos anteriormente. Al cambiar el nombre
del destino de la nueva microoperación para permitirle escribir su resultado en uno de los 160
registros temporales en lugar de en el destino previsto, pero aún ocupado, es posible programar
la microoperación para que se ejecute de inmediato. . Si no hay ningún registro de scratch
disponible, o el micro-op tiene una dependencia RAW (que nunca se puede tapar), el asignador
anota la naturaleza del problema en la entrada ROB. Cuando todos los recursos necesarios estén
disponibles más tarde, la microoperación se coloca en una de las colas del planificador.
Las colas del programador envían microoperaciones a las seis unidades funcionales cuando están
listas para ejecutarse. Las unidades funcionales son las siguientes:
Dado que los programadores y las ALU pueden procesar una operación por ciclo, un Core i7 de 3 GHz
tiene el rendimiento del programador para emitir 18 mil millones de operaciones por segundo; sin
embargo, en realidad, el procesador nunca alcanzará este nivel de rendimiento. Dado que el front-end
suministra como máximo cuatro microoperaciones por ciclo, seis microoperaciones solo pueden
328 EL NIVEL DE MICROARQUITECTURA CAP. 4
emitido en ráfagas cortas ya que pronto las colas del planificador se vaciarán. Además, las
unidades de memoria necesitan cuatro ciclos para procesar sus operaciones, por lo que podrían
contribuir al rendimiento máximo de ejecución solo en pequeñas ráfagas. A pesar de no poder
saturar por completo los recursos de ejecución, las unidades funcionales sí brindan una
capacidad de ejecución significativa, y es por eso que el control de desorden se toma tantas
molestias para encontrar trabajo que hacer.
Las tres ALU enteras no son idénticas. ALU 1 puede realizar todas las operaciones
aritméticas y lógicas y multiplica y divide. ALU 2 solo puede realizar operaciones aritméticas
y lógicas. ALU 3 puede realizar operaciones aritméticas y lógicas y resolver ramas. Del
mismo modo, las dos unidades de coma flotante tampoco son idénticas. El primero puede
realizar operaciones aritméticas de punto flotante, incluidas multiplicaciones, mientras que
el segundo solo puede realizar sumas, restas y movimientos de punto flotante.
Las unidades ALU y de coma flotante son alimentadas por un par de archivos de registro de 128
entradas, uno para números enteros y otro para números de coma flotante. Estos proporcionan todos
los operandos para que se ejecuten las instrucciones y proporcionan un repositorio de resultados.
Debido al cambio de nombre de los registros, ocho de ellos contienen los registros visibles a nivel ISA (
EAX, EBX, ECX, EDX, etc.), pero cuáles ocho contienen los valores '' reales '' varían con el tiempo a medida
que cambia el mapeo durante la ejecución.
La arquitectura Sandy Bridge introdujo Advanced Vector Extensions (AVX), que admite
operaciones vectoriales paralelas de datos de 128 bits. Las operaciones vectoriales incluyen
vectores de punto flotante y enteros, y esta nueva extensión ISA representa un aumento de dos
veces en el tamaño de los vectores ahora admitidos en comparación con las extensiones ISA SSE
y SSE2 anteriores. ¿Cómo implementa la arquitectura operaciones de 256 bits con solo rutas de
datos y unidades funcionales de 128 bits? Coordina inteligentemente dos puertos del
programador de 128 bits para producir una sola unidad funcional de 256 bits.
La caché de datos L1 está estrechamente acoplada al extremo posterior de la tubería Sandy
Bridge. Es una caché de 32 KB y contiene enteros, números de punto flotante y otros tipos de
datos. A diferencia del caché de microoperaciones, no se decodifica de ninguna manera. Solo
tiene una copia de los bytes en la memoria. La caché de datos L1 es una caché asociativa de 8 vías
con 64 bytes por línea de caché. Es un caché de escritura diferida, lo que significa que cuando se
modifica una línea de caché, el bit sucio de esa línea se establece y los datos se copian de nuevo
al caché L2 cuando se expulsan del caché de datos L1. La caché puede manejar dos operaciones
de lectura y una de escritura por ciclo de reloj. Estos accesos múltiples se implementan usando
bancario, que divide el caché en subcachés separados (8 en el caso de Sandy Bridge). Siempre
que los tres accesos sean a bancos separados, pueden proceder en conjunto; de lo contrario,
todos los accesos bancarios en conflicto, excepto uno, tendrán que pararse. Cuando una palabra
necesaria no está presente en la caché L1, se envía una solicitud a la caché L2, que responde
inmediatamente o recupera la línea de la caché de la caché L3 compartida y luego responde.
Hasta diez solicitudes de la caché L1 a la caché L2 pueden estar en curso en cualquier momento.
Debido a que las microoperaciones se ejecutan fuera de orden, las tiendas en la caché L1 no están
permitidas hasta que se hayan retirado todas las instrucciones que preceden a una tienda en particular. los
unidad de jubilación tiene el trabajo de retirar las instrucciones, en orden, y realizar un seguimiento
SEGUNDO. 4.6 EJEMPLOS DEL NIVEL DE MICROARQUITECTURA 329
de donde está. Si ocurre una interrupción, las instrucciones que aún no se han retirado se abortan, por lo que
el Core i7 tiene "interrupciones precisas", de modo que tras una interrupción, todas las instrucciones hasta
cierto punto se han completado y ninguna instrucción más allá de eso tiene ningún efecto.
Si se ha retirado una instrucción de almacenamiento, pero las instrucciones anteriores aún
están en curso, la caché L1 no se puede actualizar, por lo que los resultados se colocan en un
búfer especial de almacenamiento pendiente. Este búfer tiene 36 entradas, correspondientes a
las 36 tiendas que podrían estar en ejecución a la vez. Si una carga posterior intenta leer los
datos almacenados, se puede pasar del búfer de almacenamiento pendiente a la instrucción,
aunque aún no esté en la caché de datos L1. Este proceso se llamatienda a carga reenvío. Si bien
este mecanismo de reenvío puede parecer sencillo, en la práctica es bastante complicado de
implementar porque es posible que las tiendas intermedias aún no hayan calculado sus
direcciones. En este caso, la microarquitectura no puede saber definitivamente qué almacén en el
búfer de almacenamiento producirá el valor necesario. El proceso de determinar qué tienda
proporciona el valor para una carga se llamadesambiguación.
Debería estar claro a estas alturas que el Core i7 tiene una microarquitectura altamente
compleja cuyo diseño fue impulsado por la necesidad de ejecutar el antiguo conjunto de
instrucciones Pentium en un núcleo RISC moderno y altamente canalizado. Logra este objetivo al
dividir las instrucciones de Pentium en microoperaciones, almacenarlas en caché y enviarlas a la
tubería cuatro a la vez para su ejecución en un conjunto de ALU capaces de ejecutar hasta seis
microoperaciones por ciclo en condiciones óptimas. Las microoperaciones se ejecutan fuera de
servicio pero se retiran en orden, y los resultados se almacenan en las cachés L1 y L2 en orden.
los componentes clave son similares a los que se utilizan en el Core i7. Las similitudes se deben
principalmente a la tecnología, las limitaciones de energía y la economía. Por ejemplo, ambos
diseños emplean una jerarquía de caché multinivel para cumplir con las estrictas restricciones de
costos de las aplicaciones integradas típicas; sin embargo, el último nivel del sistema de memoria
caché de Cortex A9 (L2) tiene un tamaño de solo 1 MB, significativamente más pequeño que el
Core i7 que admite cachés de último nivel (L3) de hasta 20 MB. Las diferencias, por el contrario,
se deben principalmente a la diferencia entre tener que cerrar la brecha entre un conjunto de
instrucciones CISC antiguo y un núcleo RISC moderno y no tener que hacerlo.
A LPDDR2
memoria
Nivel 2
Instrucción Nivel 1 unificado
cola caché de datos cache
ALU FPU
Unidad de almacenamiento de carga /
almacenar búfer
Jubilación
En la parte superior de la figura 4-48 se encuentra la caché de instrucciones asociativas de 4 vías de 32 KB,
que utiliza líneas de caché de 32 bytes. Dado que la mayoría de las instrucciones ARM son de 4 bytes, hay
espacio para aproximadamente 8K instrucciones aquí en este caché, bastante más grande que el caché micro-
op del Core i7.
los unidad de emisión de instrucciones prepara hasta cuatro instrucciones para su
ejecución por ciclo de reloj. Si hay una falta en la caché L1, se emitirán menos instrucciones.
Cuando se encuentra una rama condicional, se consulta un predictor de rama con entradas de 4K
para predecir si se tomará o no la rama. Si se predice, se consulta la caché de dirección de
destino de rama de entrada de 1K para la dirección de destino pronosticada. Además, si la
interfaz detecta que el programa está ejecutando un bucle cerrado (es decir, un bucle pequeño
no anidado), lo cargará en la caché de búsqueda lateral de bucle rápido. Esta optimización
acelera la búsqueda de instrucciones y reduce la energía, ya que las cachés y los predictores de
rama pueden estar en un modo de suspensión de baja energía mientras se ejecuta el ciclo
cerrado.
La salida de la unidad de emisión de instrucciones fluye hacia los decodificadores, que
determinan qué recursos y entradas necesitan las instrucciones. Como el Core i7,
SEGUNDO. 4.6 EJEMPLOS DEL NIVEL DE MICROARQUITECTURA 331
las instrucciones se renombran después de la decodificación para eliminar los peligros de WAR que
pueden ralentizar la ejecución fuera de orden. Después de cambiar el nombre, las instrucciones se
colocan en la cola de envío de instrucciones, que las emitirá cuando sus entradas estén listas para las
unidades funcionales, potencialmente fuera de servicio.
La cola de envío de instrucciones envía instrucciones a las unidades funcionales, como se
muestra en la figura 4-48. La unidad de ejecución de enteros contiene dos ALU, así como una
canalización corta para instrucciones de bifurcación. Allí también se incluye el archivo de registro
físico, que contiene registros ISA y algunos registros temporales. La canalización Cortex A9 puede
contener opcionalmente también uno más motores de cómputo, que actúan como unidades
funcionales adicionales. ARM admite un motor de cálculo para el cálculo de punto flotante
llamadoVFP y cálculo vectorial de SIMD entero llamado NEÓN.
La unidad de carga / almacenamiento maneja varias instrucciones de carga y almacenamiento.
Tiene rutas a la caché de datos y al búfer de almacenamiento. loscaché de datos es una caché de datos
L1 asociativa de 4 vías tradicional de 32 KB que utiliza un tamaño de línea de 32 bytes. losalmacenar
búfer contiene las tiendas que aún no han escrito su valor en la caché de datos (en el momento de la
jubilación). Una carga que se ejecuta primero intentará recuperar su valor del búfer de
almacenamiento, utilizando el reenvío de almacenamiento a carga como el del Core i7. Si el valor no
está disponible en el búfer de la tienda, lo obtendrá de la caché de datos. Un posible resultado de la
ejecución de una carga es una indicación del búfer de la tienda de que debe esperar, porque una tienda
anterior con una dirección desconocida está bloqueando su ejecución. En caso de que se pierda el
acceso a la caché de datos L1, el bloque de memoria se obtendrá de la caché L2 unificada. En
determinadas circunstancias, el Cortex A9 también realiza una captación previa de hardware de la caché
L2 a la caché de datos L1, con el fin de mejorar el rendimiento de las cargas y las tiendas.
El chip OMAP 4430 también contiene lógica para controlar el acceso a la memoria. Esta
lógica se divide en dos partes: la interfaz del sistema y el controlador de memoria. La interfaz del
sistema interactúa con la memoria a través de un bus LPDDR2 de 32 bits de ancho. Todas las
solicitudes de memoria al mundo exterior pasan a través de esta interfaz. El bus LPDDR2 admite
una dirección de 26 bits (palabra, no byte) a 8 bancos que devuelven una palabra de datos de 32
bits. En teoría, la memoria principal puede ser de hasta 2 GB por canal LPDDR2. El OMAP4430
tiene dos de ellos, por lo que puede direccionar hasta 4 GB de RAM externa.
El controlador de memoria asigna direcciones virtuales de 32 bits a direcciones físicas de 32
bits. El Cortex A9 admite memoria virtual (que se describe en el capítulo 6), con un tamaño de
página de 4 KB. Para acelerar el mapeo, tablas especiales, llamadasTLB (Buffers Lookaside de
traducción), se proporcionan para comparar la dirección virtual actual a la que se hace
referencia con aquellas a las que se hace referencia en el pasado reciente. Se proporcionan dos
de estas tablas para mapear direcciones de instrucciones y datos.
El Cortex A9 tiene una tubería de 11 etapas, ilustrada de forma simplificada en la figura 4-49.
Las 11 etapas están designadas por nombres de etapas cortos que se muestran en el lado
izquierdo de la figura. Examinemos ahora brevemente cada etapa. losFe1 (Obtener
332 EL NIVEL DE MICROARQUITECTURA CAP. 4
1. Entero ALU 1.
2. Entero ALU 2.
3. Multiplica la unidad.
Escenario
Rama
Fe2 vaticinador Instrucción unidad de emisión
Instrucción
Fe3
cola
Id1
Instrucción
descodificación
Id2
FPU / Nivel 1
Ex2 Mult
NEÓN caché de datos
Nivel 2
Ex3 unificado
cache
...
WB Jubilación
Esta descripción del Cortex A9 está lejos de ser completa, pero debería dar una idea
razonable de cómo funciona y en qué se diferencia de la microarquitectura Core i7.
32 × 8 unidad
general
Instrucción
objetivo SPI
Registrarse
registros unidad
Perro guardián
Instrucción Temporizador
Direccionamiento indirecto
Direccionamiento directo
descifrador
ALU
Cosa análoga
comparador
Líneas de control
Módulo de E / S 1
Datos
SRAM Módulo de E / S 2
Módulo de E / S 3
EEPROM
El corazón del ATmega168 es el bus principal de 8 bits. Se adjuntan a él los registros y bits de
estado, ALU, memoria y dispositivos de E / S. Vamos a describirlos ahora brevemente. El archivo
de registro contiene 32 registros de 8 bits, que se utilizan para almacenar valores de programa
temporales. losestado y control El registro contiene los códigos de condición de la última
operación de ALU (es decir, signo, desbordamiento, negativo, cero y acarreo), más un bit
SEGUNDO. 4.6 EJEMPLOS DEL NIVEL DE MICROARQUITECTURA 335
que indica si hay una interrupción pendiente. loscontador de programa contiene la dirección de
la instrucción que se está ejecutando actualmente. Para realizar una operación ALU, primero se
leen los operandos del registro y se envían a la ALU. La salida ALU se puede escribir en cualquiera
de los registros grabables a través del bus principal.
El ATmega168 tiene varias memorias para datos e instrucciones. La SRAM de datos es de 1
KB, demasiado grande para direccionarse completamente con una dirección de 8 bits en el bus
principal. Por lo tanto, la arquitectura AVR permite construir direcciones con un par secuencial de
registros de 8 bits, produciendo así una dirección de 16 bits que admite hasta 64 KB de memoria
de datos. La EEPROM proporciona hasta 1 KB de almacenamiento no volátil donde los programas
pueden escribir variables que necesitan sobrevivir a un corte de energía.
Existe un mecanismo similar para abordar la memoria del programa, pero 64 KB de código es
demasiado pequeño, incluso para sistemas integrados de bajo costo. Para permitir que se direccione
más memoria de instrucciones, la arquitectura AVR define tres registros de página RAM (RAMPX, RAMPY
y RAMPZ), cada uno de 8 bits de ancho. El registro de la página RAM se concatena con un par de
registros de 16 bits para producir una dirección de programa de 24 bits, lo que permite 16 MB de
espacio de direcciones de instrucciones.
Deténgase a pensar en eso por un minuto. 64 KB de código es demasiado pequeño para un
microcontrolador que podría alimentar un juguete o un pequeño electrodoméstico. En 1964, IBM lanzó
el System 360 Model 30, que tenía 64 KB de memoria total (sin trucos para actualizarlo). Se vendió por
250.000 dólares, lo que equivale aproximadamente a 2 millones de dólares en dólares de hoy. El
ATmega168 cuesta alrededor de $ 1, menos si compra muchos a la vez. Si consulta, digamos, la lista de
precios de Boeing, descubrirá que los precios de los aviones no se han reducido en un factor de 250.000
en los últimos 50 años aproximadamente. Tampoco tienen los precios de los coches ni de los televisores
ni de nada más que de los ordenadores.
Además, el ATmega168 tiene un controlador de interrupciones en chip, una interfaz de
puerto serie (SPI) y temporizadores, que son esenciales para las aplicaciones en tiempo
real. También hay tres puertos de E / S digitales de 8 bits, que permiten que el ATmega168
controle hasta 24 botones externos, luces, sensores, actuadores, etc. Es la presencia de los
temporizadores y los puertos de E / S más que cualquier otra cosa lo que hace posible usar
el ATmega168 para aplicaciones integradas sin ningún chip adicional.
El ATmega168 es un procesador síncrono, y la mayoría de las instrucciones toman un ciclo
de reloj, aunque algunas toman más. El procesador está en canalización, de modo que mientras
se recupera una instrucción, se ejecuta la instrucción anterior. La canalización consta de solo dos
etapas, sin embargo, recuperar y ejecutar. Para ejecutar instrucciones en un ciclo, el ciclo de reloj
debe acomodar la lectura del registro del archivo de registro, seguido de la ejecución de la
instrucción en la ALU, seguido de la escritura del registro de nuevo en el archivo de registro.
Debido a que todas estas operaciones ocurren en un ciclo de reloj, no hay necesidad de lógica de
derivación o detección de bloqueo. Las instrucciones del programa se ejecutan en orden, en un
ciclo y sin superponerse con otras instrucciones.
Si bien podríamos entrar en más detalles sobre el ATmega168, la descripción anterior y la
Fig. 4-50 dan la idea básica. El ATmega168 tiene un solo bus principal (para reducir el área del
chip), un conjunto heterogéneo de registros y una variedad de memorias y dispositivos de E / S
que cuelgan del bus principal. En cada ciclo de ruta de datos, dos operandos son
336 EL NIVEL DE MICROARQUITECTURA CAP. 4
leer desde el archivo de registro y ejecutar a través de la ALU y los resultados se almacenan de nuevo en un
registro, al igual que en las computadoras más modernas.
Nuestros tres ejemplos son muy diferentes, sin embargo, incluso ellos exhiben una cierta
cantidad de puntos en común. El Core i7 tiene un antiguo conjunto de instrucciones CISC que a
los ingenieros de Intel les encantaría lanzar a la Bahía de San Francisco, excepto que al hacerlo
violaría las leyes de contaminación del agua de California. El OMAP4430 es un diseño RISC puro,
con un conjunto de instrucciones delgado y medio. El ATmega168 es un procesador simple de 8
bits para aplicaciones integradas. Sin embargo, el corazón de cada uno de ellos es un conjunto de
registros y una o más ALU que realizan operaciones aritméticas y booleanas simples en
operandos de registro.
A pesar de sus obvias diferencias externas, el Core i7 y el OMAP4430 tienen unidades
de ejecución bastante similares. Ambas unidades de ejecución aceptan microoperaciones
que contienen un código de operación, dos registros de origen y un registro de destino.
Ambos pueden ejecutar una microoperación en un ciclo. Ambos tienen pipelines profundos,
predicción de ramificaciones y cachés I y D divididos.
Esta similitud interna no es un accidente o incluso se debe a la interminable búsqueda de
trabajo de los ingenieros de Silicon Valley. Como vimos con nuestros ejemplos Mic-3 y Mic-4, es
fácil y natural construir una ruta de datos canalizada que toma dos registros fuente, los ejecuta a
través de una ALU y almacena los resultados en un registro. La Figura 4-34 muestra esta
canalización gráficamente. Con la tecnología actual, este es el diseño más efectivo.
La principal diferencia entre el Core i7 y el OMAP4430 es cómo pasan de su conjunto de
instrucciones ISA a la unidad de ejecución. El Core i7 tiene que dividir sus instrucciones CISC para
ponerlas en el formato de tres registros que necesita la unidad de ejecución. De eso se trata la
interfaz de la figura 4-47: piratear grandes instrucciones para convertirlas en microoperaciones
agradables y ordenadas. El OMAP4430 no tiene que hacer nada porque sus instrucciones ARM
nativas ya son microoperaciones agradables y ordenadas. Ésta es la razón por la que la mayoría
de las ISA nuevas son del tipo RISC, para proporcionar una mejor coincidencia entre el conjunto
de instrucciones ISA y el motor de ejecución interno.
Es instructivo comparar nuestro diseño final, el Mic-4, con estos dos ejemplos del mundo
real. El Mic-4 se parece más al Core i7. Ambos tienen la función de interpretar un conjunto de
instrucciones ISA no RISC. Ambos hacen esto dividiendo las instrucciones ISA en
microoperaciones con un código de operación, dos registros de origen y un registro de destino.
En ambos casos, las microoperaciones se depositan en una cola para su posterior ejecución. El
Mic-4 tiene un estricto problema en orden, ejecución en orden, diseño de retiro en orden,
mientras que el Core i7 tiene una política de emisión en orden, ejecución fuera de orden, retiro
en orden.
El Mic-4 y el OMAP4430 no son realmente comparables en absoluto porque el OMAP4430
tiene instrucciones RISC (es decir, microoperaciones de tres registros) como su ISA
SEGUNDO. 4,7 COMPARACIÓN DEL I7, OMAP4430 Y ATMEGA168 337
conjunto de instrucciones. No es necesario romperlos. Se pueden ejecutar tal cual, cada uno en
un único ciclo de ruta de datos.
A diferencia del Core i7 y el OMAP4430, el ATmega168 es una máquina sencilla. Es
más parecido a RISC que a CISC porque la mayoría de sus sencillas instrucciones se
pueden ejecutar en un ciclo de reloj y no es necesario descomponerlas. No tiene
canalización ni almacenamiento en caché, y tiene problemas en orden, ejecución en
orden y retiro en orden. En su simplicidad, se parece mucho al Mic-1.
4.8 RESUMEN
la última caída posible de velocidad del hardware. El OMAP4430 tiene una tubería
profunda, pero además es relativamente simple, con problemas en orden, ejecución
en orden y retiro en orden. El ATmega168 es muy simple, con un bus principal sencillo
y sencillo al que se adjuntan un puñado de registros y una ALU.
PROBLEMAS
1. ¿Cuáles son los cuatro pasos que utilizan las CPU para ejecutar instrucciones?
2. En la figura 4-6, el registro del bus B está codificado en un campo de 4 bits, pero el bus C se representa como un
mapa de bits. ¿Por qué?
3. En la Fig. 4-6 hay un cuadro etiquetado como "Bit alto". Proporcione un diagrama de circuito para ello.
4. Cuando el JMPC campo en una microinstrucción está habilitado, MBR está ORed con SIGUIENTE
DIRECCION para formar la dirección de la siguiente microinstrucción. ¿Hay alguna
circunstancia en la que tenga sentido tenerSIGUIENTE DIRECCION ser 0x1FF y utilizar JMPC?
k = 5;
se agrega después de la si declaración. ¿Cuál sería el nuevo código de ensamblaje? Suponga que el
compilador es un compilador optimizador.
i = k + n + 5;
ILOAD j
ILOAD n
ISUB
BIPUSH 7
ISUB
DUP
AÑADO
ISTORE i
a binario, L2 tiene que estar en las 256 palabras inferiores del almacén de control. ¿No sería
igualmente posible tenerL1 en, digamos, 0x40 y L2 en 0x140? Explica tu respuesta.
9. En el microprograma para Mic-1, en si icmpeq3, MDR se copia a H. Unas pocas líneas más tarde se
resta de TOS para comprobar la igualdad. Seguramente es mejor tener una declaración:
CAP. 4 PROBLEMAS 339
si cmpeq3 Z = TOS - MDR; rd
10. ¿Cuánto tiempo tarda un Mic-1 de 2,5 GHz en ejecutar la siguiente declaración de Java?
i = j + k;
Da tu respuesta en nanosegundos.
11. Repita la pregunta anterior, solo ahora para un Mic-2 de 2.5 GHz. Según este cálculo, ¿cuánto
tiempo tomaría un programa que se ejecuta durante 100 segundos en el Mic-1 en el Mic-2?
12. Escriba un microcódigo para el Mic-1 para implementar la JVM POPTWO instrucción. Esta instrucción
elimina dos palabras de la parte superior de la pila.
13. En la máquina JVM completa, hay códigos de operación especiales de 1 byte para cargar locales de 0
a 3 en la pila en lugar de usar el código general YO CARGO instrucción. ¿Cómo debería modificarse la
IJVM para aprovechar al máximo estas instrucciones?
14. La instrucción ISHR (entero de desplazamiento aritmético a la derecha) existe en JVM pero no en IJVM. Utiliza
los dos valores superiores de la pila, reemplazándolos con un valor único, el resultado. La segunda
palabra desde arriba de la pila es el operando que se va a desplazar. Su contenido se desplaza hacia la
derecha en un valor entre 0 y 31, inclusive, dependiendo del valor de los 5 bits menos significativos de la
palabra superior en la pila (los otros 27 bits de la palabra superior se ignoran). El bit de signo se replica a
la derecha para tantos bits como el recuento de cambios. El código de operación paraISHR es 122 (0x7A).
una. ¿Cuál es la operación aritmética equivalente al desplazamiento a la izquierda con una cuenta de 2?
B. Amplíe el microcódigo para incluir esta instrucción como parte de IJVM.
15. La instrucción ISHL (shift left integer) existe en JVM pero no en IJVM. Utiliza los dos valores superiores
de la pila, reemplazando los dos con un solo valor, el resultado. La segunda palabra desde arriba
de la pila es el operando que se va a desplazar. Su contenido se desplaza hacia la izquierda en un
valor entre 0 y 31, inclusive, dependiendo del valor de los 5 bits menos significativos de la palabra
superior en la pila (los otros 27 bits de la palabra superior se ignoran). Los ceros se desplazan
desde la derecha para tantos bits como el recuento de cambios. El código de operación para
ISHL es 120 (0x78).
una. ¿Cuál es la operación aritmética equivalente a desplazarse a la izquierda con una cuenta de 2?
B. Amplíe el microcódigo para incluir esta instrucción como parte de IJVM.
dieciséis. La JVM INVOCAR EVIRTUAL La instrucción necesita saber cuántos parámetros tiene. ¿Por
qué?
17. Implementar la JVM DESCARGAR instrucción para el Mic-2. Tiene un índice de 1 byte y empuja la
variable local en esta posición a la pila. Luego también empuja la siguiente palabra más alta
a la pila.
18. Dibuja una máquina de estados finitos para anotar tenis. Las reglas del tenis son las siguientes. Para
ganar, necesitas al menos cuatro puntos y debes tener al menos dos puntos más que tu oponente.
Empiece con un estado (0, 0) que indique que nadie ha puntuado todavía. Luego agregue un
estado (1, 0) lo que significa queA ha anotado. Rotule el arco de (0, 0) a (1, 0) con unUNA.
Ahora agregue un estado (0, 1) que indique que B ha anotado, y etiquete el arco de (0, 0) con un
B. Continúe agregando estados y arcos hasta que se hayan incluido todos los estados posibles.
340 EL NIVEL DE MICROARQUITECTURA CAP. 4
19. Reconsidere el problema anterior. ¿Hay estados que podrían colapsar sin cambiar el
resultado de ningún juego? Si es así, ¿cuáles son equivalentes?
20. Dibuje una máquina de estados finitos para la predicción de ramas que sea más tenaz que la figura 4-42. Debería
cambiar solo las predicciones después de tres predicciones erróneas consecutivas.
21. El registro de desplazamiento de la figura 4-27 tiene una capacidad máxima de 6 bytes. ¿Podría construirse una
versión más económica de la IFU con un registro de desplazamiento de 5 bytes? ¿Qué tal uno de 4 bytes?
22. Habiendo examinado las IFU más baratas en la pregunta anterior, ahora examinemos las más
caras. ¿Sería útil tener un registro de desplazamiento mucho más grande en la IU, digamos,
12 bytes? ¿Por qué o por qué no?
24. En el Mic-4, la unidad de decodificación mapea el código de operación IJVM en el índice ROM donde se
almacenan las microoperaciones correspondientes. Parecería más sencillo simplemente omitir la etapa de
decodificación y alimentar el código de operación IJVM directamente en la cola. Podría usar el código de
operación IJVM como un índice en la ROM, de la misma manera que funciona el Mic-1. ¿Qué hay de malo
en este plan?
25. ¿Por qué las computadoras están equipadas con múltiples capas de caché? ¿No sería mejor
simplemente tener uno grande?
26. Una computadora tiene una caché de dos niveles. Suponga que el 60% de las referencias de memoria se encuentran
en la caché de primer nivel, el 35% en el segundo nivel y el 5% fallan. Los tiempos de acceso son 5 nseg, 15 nsec y
60 nsec, respectivamente, donde los tiempos para la memoria caché y la memoria de nivel 2 comienzan a contar
en el momento en que se sabe que son necesarios (por ejemplo, un acceso a la memoria caché de nivel 2 ni
siquiera comienza hasta que ocurra la falta de caché de nivel 1). ¿Cuál es el tiempo medio de acceso?
27. Al final de la Sec. 4.5.1, dijimos que la asignación de escritura gana solo si es probable que haya
varias escrituras en la misma línea de caché seguidas. ¿Qué pasa con el caso de una escritura
seguida de varias lecturas? ¿No sería eso también una gran victoria?
28. En el primer borrador de este libro, la figura 4-39 mostraba una caché asociativa de tres vías en
lugar de una caché asociativa de cuatro vías. Uno de los revisores hizo un berrinche, alegando que
los estudiantes estarían terriblemente confundidos por esto porque 3 no es una potencia de 2 y las
computadoras hacen todo en binario. Dado que el cliente siempre tiene la razón, la figura se
cambió a una caché asociativa de cuatro vías. ¿Tenía razón el revisor? Analice su respuesta.
29. Muchos arquitectos informáticos dedican mucho tiempo a profundizar sus procesos. ¿Por qué?
30. Una computadora con una tubería de cinco etapas se ocupa de las ramas condicionales deteniéndose durante los
siguientes tres ciclos después de llegar a uno. ¿En qué medida el estancamiento perjudica el rendimiento si el 20%
de todas las instrucciones son ramas condicionales? Ignore todas las fuentes de estancamiento excepto las ramas
condicionales.
31. Una computadora obtiene hasta 20 instrucciones por adelantado. Sin embargo, en promedio, cuatro de
estas son ramas condicionales, cada una con una probabilidad del 90% de ser predichas correctamente.
¿Cuál es la probabilidad de que la captación previa esté en el camino correcto?
CAP. 4 PROBLEMAS 341
32. Suponga que cambiamos el diseño de la máquina utilizada en la figura 4-43 para que tenga 16
registros en lugar de 8. Luego cambiamos I6 para usar R8 como su destino. ¿Qué sucede en los
ciclos que comienzan en el ciclo 6?
33. Normalmente, las dependencias causan problemas con las CPU canalizadas. ¿Hay alguna
optimización que se pueda hacer con las dependencias de WAW que realmente puedan mejorar las
cosas? ¿Qué?
34. Vuelva a escribir el intérprete Mic-1 pero teniendo LV ahora apunte a la primera variable local en lugar de al
puntero de enlace.
35. Escriba un simulador para un caché mapeado directo unidireccional. Realice el número de entradas y los
parámetros de tamaño de línea de la simulación. Experimente con él e informe sobre sus hallazgos.
Esta página se dejó en blanco intencionalmente
5
EL CONJUNTO DE INSTRUCCIONES
NIVEL DE ARQUITECTURA
343
344 EL NIVEL DE ARQUITECTURA DEL CONJUNTO DE INSTRUCCIONES CAP. 5
FORTRAN
Programa C
programa
FORTRAN Programa C
programa compilado compilado
al programa ISA al programa ISA
Software
Nivel ISA
Hardware
Programa ISA ejecutado
por microprograma o hardware
Hardware
Los ingenieros no pueden implementar de una manera rentable (por ejemplo, una instrucción de
sucursal y hacer nómina), no entra. De manera similar, si la gente del hardware tiene alguna
característica nueva ingeniosa que quieren poner (por ejemplo, una memoria en el que las palabras
cuyas direcciones son números primos son superrápidas), pero la gente del software no puede
averiguar cómo generar código para usarlo, morirá en el tablero de dibujo. Después de mucha
negociación y simulación, surgirá y se implementará un ISA perfectamente optimizado para los
lenguajes de programación previstos.
Esa es la teoría. Ahora la cruda realidad. Cuando aparece una nueva máquina, la primera
pregunta que hacen todos los clientes potenciales es: '' ¿Es compatible con su predecesora? '' La
segunda es: '' ¿Puedo ejecutar mi antiguo sistema operativo en ella? '' La tercera es: '' ¿Ejecutará
todos mis programas de aplicación existentes sin modificaciones? '' Si alguna de las respuestas es
'' no '', los diseñadores tendrán mucho que explicar. Los clientes rara vez están interesados en
deshacerse de todo su software antiguo y empezar de nuevo.
Esta actitud ejerce una gran presión sobre los arquitectos informáticos para
mantener el ISA igual entre modelos, o al menos hacerlo compatible con versiones
anteriores. Con esto queremos decir que la nueva máquina debe poder ejecutar
programas antiguos sin cambios. Sin embargo, es completamente aceptable que la
nueva máquina tenga nuevas instrucciones y otras características que solo puedan ser
explotadas por un nuevo software. En términos de la figura 5-1, siempre que los
diseñadores hagan que el ISA sea compatible con versiones anteriores de los modelos
anteriores, son prácticamente libres de hacer lo que quieran con el hardware, ya que
casi nadie se preocupa por el hardware real (o incluso sabe Que hace). Pueden
cambiar de un diseño microprogramado a ejecución directa, o agregar tuberías o
instalaciones superescalares o cualquier otra cosa que deseen, siempre que
mantengan la compatibilidad con versiones anteriores de ISA. El objetivo es
asegurarse de que los programas antiguos se ejecuten en la nueva máquina.
SEGUNDO. 5.1 DESCRIPCIÓN GENERAL DEL NIVEL ISA 345
Lo anterior no pretende implicar que el diseño de ISA no importe. Un buen ISA tiene
ventajas significativas sobre uno deficiente, particularmente en cuanto a potencia
informática bruta frente al costo. Para diseños equivalentes, diferentes NIA pueden
representar una diferencia de hasta un 25% en el rendimiento. Nuestro punto es
simplemente que las fuerzas del mercado hacen que sea difícil (pero no imposible)
desechar una ISA antigua e introducir una nueva. Sin embargo, de vez en cuando surge un
nuevo ISA de propósito general, y en mercados especializados (por ejemplo, sistemas
embebidos o procesadores multimedia) esto ocurre con mucha más frecuencia. En
consecuencia, es importante comprender el diseño de ISA.
¿Qué hace un buen ISA? Hay dos factores principales. Primero, una buena ISA debe definir
un conjunto de instrucciones que se puedan implementar de manera eficiente en las tecnologías
actuales y futuras, lo que resultará en diseños rentables a lo largo de varias generaciones. Un
diseño deficiente es más difícil de implementar y puede requerir muchas más puertas para
implementar un procesador y más memoria para ejecutar programas. También puede funcionar
más lento porque ISA oculta las oportunidades de superponer operaciones, lo que requiere
diseños mucho más sofisticados para lograr un rendimiento equivalente. Un diseño que
aproveche las peculiaridades de una tecnología en particular puede ser un flash en la sartén,
proporcionando una sola generación de implementaciones rentables, solo para ser superado por
ISA más progresistas.
En segundo lugar, una buena ISA debería proporcionar un objetivo limpio para el código
compilado. La regularidad y la integridad de una variedad de opciones son rasgos importantes
que no siempre están presentes en una ISA. Estas son propiedades importantes para un
compilador, que puede tener problemas para elegir la mejor opción entre alternativas limitadas,
particularmente cuando algunas alternativas aparentemente obvias no están permitidas por la
ISA. En resumen, dado que ISA es la interfaz entre el hardware y el software, debería hacer felices
a los diseñadores de hardware (ser fácil de implementar de manera eficiente) y hacer felices a los
diseñadores de software (ser fácil generar un buen código).
Comencemos nuestro estudio del nivel ISA preguntándonos qué es. Esto puede parecer una
pregunta simple, pero tiene más complicaciones de las que uno podría imaginar en un principio.
En la siguiente sección plantearemos algunos de estos problemas. Luego, veremos modelos de
memoria, registros e instrucciones.
para saber cuál es el modelo de memoria, qué registros hay, qué tipos de datos e
instrucciones están disponibles, etc. La recopilación de toda esta información es lo que
define el nivel ISA.
Según esta definición, cuestiones como si la microarquitectura está
microprogramada o no, si está canalizada o no, si es superescalar o no, etc., no
forman parte del nivel ISA porque no son visibles para el redactor del compilador. Sin
embargo, esta observación no es del todo cierta porque algunas de estas propiedades
afectan el rendimiento y eso es visible para el escritor del compilador. Considere, por
ejemplo, un diseño superescalar que puede emitir instrucciones consecutivas en el
mismo ciclo, siempre que una sea una instrucción entera y la otra sea una instrucción
de punto flotante. Si el compilador alterna instrucciones enteras y de punto flotante,
obtendrá un rendimiento notablemente mejor que si no lo hiciera. Así, los detalles de
la operación superescalarestán visible a nivel ISA, por lo que la separación entre las
capas no es tan limpia como podría parecer al principio.
Para algunas arquitecturas, el nivel ISA se especifica mediante un documento de definición
formal, a menudo producido por un consorcio de la industria. Para otros no lo es. Por ejemplo,
ARM v7 (versión 7 ARM ISA) tiene una definición oficial publicada por ARM Ltd. El propósito de un
documento de definición es hacer posible que diferentes implementadores construyan las
máquinas y que todas ejecuten exactamente el mismo software y obtengan exactamente los
mismos resultados.
En el caso de ARM ISA, la idea es permitir que varios proveedores de chips fabriquen
chips ARM que sean funcionalmente idénticos, que solo difieran en rendimiento y precio.
Para que esta idea funcione, los proveedores de chips deben saber qué se supone que debe
hacer un chip ARM (a nivel ISA). Por lo tanto, el documento de definición dice qué es el
modelo de memoria, qué registros están presentes, qué hacen las instrucciones, etc., pero
no cómo es la microarquitectura.
Dichos documentos definitorios contienen normativo secciones, que imponen requisitos, y
informativo secciones, que están destinadas a ayudar al lector pero no forman parte de la
definición formal. Las secciones normativas utilizan constantemente palabras como
debe, no puede, y deberían exigir, prohibir y sugerir aspectos de la arquitectura,
respectivamente. Por ejemplo, una oración como
dice que si un programa ejecuta un código de operación que no está definido, debe causar una
trampa y no ser simplemente ignorado. Un enfoque alternativo podría ser dejar esto abierto, en
cuyo caso la oración podría leer
Esto significa que el escritor del compilador no puede contar con ningún comportamiento en particular,
lo que le da a los diferentes implementadores la libertad de tomar diferentes decisiones. La mayoría de
las especificaciones arquitectónicas van acompañadas de conjuntos de pruebas que comprueban si una
implementación que dice ajustarse a la especificación realmente lo hace.
SEGUNDO. 5.1 DESCRIPCIÓN GENERAL DEL NIVEL ISA 347
Está claro por qué ARM v7 tiene un documento que define su nivel ISA: para que todos
los chips ARM ejecuten el mismo software. Durante muchos años, no hubo un documento
de definición formal para el IA-32 ISA (a veces llamado elx86 ISA) porque Intel no quería
facilitar a otros proveedores la fabricación de chips compatibles con Intel. De hecho, Intel
acudió a los tribunales para intentar evitar que otros proveedores clonaran sus chips,
aunque perdió el caso. Sin embargo, a fines de la década de 1990, Intel finalmente lanzó
una especificación completa del conjunto de instrucciones IA-32. Quizás esto se debió a que
sintieron el error de sus métodos y querían ayudar a sus colegas arquitectos y
programadores, o quizás fue porque Estados Unidos, Japón y Europa estaban investigando
a Intel por posiblemente violar las leyes antimonopolio. Esta referencia de ISA bien
redactada todavía se actualiza hoy en el sitio web para desarrolladores de Intel (http://
developer.intel.com). La versión lanzada con el Core i7 de Intel pesa 4161 páginas,
recordándonos una vez más que el Core i7 es uncomplejo equipo de instrucciones.
Otra propiedad importante del nivel ISA es que en la mayoría de las máquinas hay al menos
dos modos. Modo kernel está diseñado para ejecutar el sistema operativo y permite que se
ejecuten todas las instrucciones. Modo de usuario está destinado a ejecutar programas de
aplicación y no permite que se ejecuten determinadas instrucciones sensibles (como las que
manipulan la caché directamente). En este capítulo nos centraremos principalmente en las
instrucciones y propiedades del modo de usuario.
Todas las computadoras dividen la memoria en celdas que tienen direcciones consecutivas. El
tamaño de celda más común en este momento es de 8 bits, pero en el pasado se han utilizado tamaños
de celda de 1 a 60 bits (consulte la figura 2-10). Una celda de 8 bits se llamabyteo octeto).
La razón para usar bytes de 8 bits es que los caracteres ASCII son de 7 bits, por lo que un carácter ASCII
(más un bit de paridad que se usa con poca frecuencia) cabe en un byte. Otros códigos, como Unicode y
UTF-8, utilizan múltiplos de 8 bits para representar caracteres.
Los bytes generalmente se agrupan en palabras de 4 bytes (32 bits) u 8 bytes (64 bits) con
instrucciones disponibles para manipular palabras completas. Muchas arquitecturas requieren que las
palabras estén alineadas con sus límites naturales. Por ejemplo, una palabra de 4 bytes puede
comenzar en la dirección 0, 4, 8, etc., pero no en la dirección 1 o 2. De manera similar, una palabra de 8
bytes puede comenzar en la dirección 0, 8 o 16, pero no en dirección 4 o 6. La alineación de palabras de
8 bytes se ilustra en la Fig. 5-2.
A menudo se requiere alineación porque las memorias funcionan de manera más eficiente
de esa manera. El Core i7, por ejemplo, obtiene 8 bytes a la vez de la memoria utilizando una
interfaz DDR3 que solo admite accesos alineados de 64 bits. Por lo tanto, el Core i7 ni siquiera
podría hacer una referencia de memoria no alineada si quisiera porque la interfaz de memoria
requiere direcciones. que son múltiplos de 8.
Sin embargo, este requisito de alineación a veces causa problemas. En el Core i7, los
programas pueden hacer referencia a palabras que comienzan en cualquier dirección, una
propiedad que se remonta al 8088, que tenía un bus de datos de 1 byte de ancho (y, por lo tanto,
no se requiere alinear referencias de memoria en límites de 8 bytes). . Si un Core i7
348 EL NIVEL DE ARQUITECTURA DEL CONJUNTO DE INSTRUCCIONES CAP. 5
Dirección Dirección
8 bytes 8 bytes
24 24
dieciséis 19 18 17 16 dieciséis
15 14 13 12 11 10 9 8 8 15 14 13 12 8
0 0
(a) (B)
Figura 5-2. Un 8 bytes palabra en una memoria little-endian. (a) Alineado. (b) No
alineado. Algunas máquinas requieren que las palabras de la memoria estén alineadas.
El programa lee una palabra de 4 bytes en la dirección 7, el hardware tiene que hacer una
referencia de memoria para obtener los bytes 0 a 7 y una segunda para obtener los bytes 8 a 15.
Luego, la CPU tiene que extraer los 4 bytes requeridos de los 16 bytes leídos. de la memoria y
ensamblarlos en el orden correcto para formar una palabra de 4 bytes. Hacer esto de forma
regular no conduce a una velocidad deslumbrante.
Tener la capacidad de leer palabras en direcciones arbitrarias requiere una lógica adicional en el
chip, lo que lo hace más grande y más caro. A los ingenieros de diseño les encantaría deshacerse de él y
simplemente requerirían que todos los programas hicieran referencias a la memoria alineadas con
palabras. El problema es que, cada vez que los ingenieros dicen: "¿A quién le importa ejecutar
programas viejos y mohosos 8088 que hacen referencia a la memoria incorrectamente?", La gente de
marketing tiene una respuesta sucinta: "Nuestros clientes".
La mayoría de las máquinas tienen un solo espacio de direcciones lineal en el nivel ISA, que se
extiende desde la dirección 0 hasta un máximo, a menudo 232 - 1 bytes o 264 - 1 bytes. Sin embargo,
algunas máquinas tienen espacios de direcciones separados para instrucciones y datos, por lo que una
búsqueda de instrucciones en la dirección 8 va a un espacio de direcciones diferente al de una
búsqueda de datos en la dirección 8. Este esquema es más complejo que tener un solo espacio de
direcciones, pero tiene dos ventajas. Primero, es posible tener 232 bytes de programa y 232 bytes de
datos utilizando solo direcciones de 32 bits. En segundo lugar, debido a que todas las escrituras van
automáticamente al espacio de datos, es imposible que un programa se sobrescriba accidentalmente a
sí mismo, eliminando así una fuente de errores del programa. La separación de los espacios de
instrucción y de datos también hace que los ataques de malware sean mucho más difíciles de realizar
porque el malware no puede cambiar el programa, ni siquiera puede abordarlo.
Tenga en cuenta que tener espacios de direcciones separados para instrucciones y datos no es lo mismo
que tener un caché de nivel 1 dividido. En el primer caso, la cantidad total de espacio de direcciones se duplica
y las lecturas en cualquier dirección dada producen resultados diferentes, dependiendo de si se está leyendo
una instrucción o una palabra de datos. Con un caché dividido, todavía hay un solo espacio de direcciones, solo
diferentes cachés almacenan diferentes partes del mismo.
Otro aspecto más del modelo de memoria de nivel ISA es la semántica de la memoria. Es
perfectamente natural esperar que unCARGA instrucción que ocurre después de una TIENDA
instrucción y que hace referencia a la misma dirección devolverá el valor recién almacenado.
SEGUNDO. 5.1 DESCRIPCIÓN GENERAL DEL NIVEL ISA 349
Sin embargo, en muchos diseños, como vimos en el Cap. 4, se reordenan las microinstrucciones. Por
tanto, existe un peligro real de que la memoria no tenga el comportamiento esperado. El problema
empeora aún más en un multiprocesador, ya que cada una de las múltiples CPU envía un flujo de
solicitudes de lectura y escritura (posiblemente reordenadas) a la memoria compartida.
Los diseñadores de sistemas pueden abordar este problema con cualquiera de los varios enfoques. En un
extremo, todas las solicitudes de memoria se pueden serializar, de modo que cada una se complete antes de
que se emita la siguiente. Esta estrategia perjudica el rendimiento pero proporciona la semántica de memoria
más simple (todas las operaciones se ejecutan en un orden estricto del programa).
En el otro extremo, no se dan garantías de ningún tipo. Para forzar una orden en la
memoria, el programa debe ejecutar unSINCRONIZAR instrucción, que bloquea la emisión de todas
las nuevas operaciones de memoria hasta que se hayan completado todas las anteriores. Este
diseño supone una gran carga para los compiladores porque tienen que comprender en detalle
cómo funciona la microarquitectura subyacente, pero les da a los diseñadores de hardware la
máxima libertad para optimizar el uso de la memoria.
También son posibles modelos de memoria intermedia, en los que el hardware bloquea
automáticamente la emisión de determinadas referencias de memoria (por ejemplo, aquellas que
implican una dependencia RAW o WAR) pero no otras. Si bien tener todas estas peculiaridades
causadas por la microarquitectura expuestas al nivel ISA es molesto (al menos para los escritores
de compiladores y programadores de lenguaje ensamblador), es en gran medida la tendencia.
Esta tendencia se debe a las implementaciones subyacentes, como el reordenamiento de las
microinstrucciones, las canalizaciones profundas, los niveles de caché múltiples, etc. Veremos
más ejemplos de tales efectos antinaturales más adelante en este capítulo.
5.1.3 Registros
Todas las computadoras tienen algunos registros visibles a nivel ISA. Están ahí para
controlar la ejecución del programa, mantener resultados temporales y servir para otros
propósitos. En general, los registros visibles a nivel de microarquitectura, comoTOS y MAR
en la Fig. 4-1, no son visibles a nivel ISA. Sin embargo, algunos de ellos, como el
contador de programa y el puntero de pila, son visibles en ambos niveles. Por otro
lado, los registros visibles a nivel ISA siempre son visibles a nivel de microarquitectura
ya que es allí donde se implementan.
Los registros de nivel ISA se pueden dividir aproximadamente en dos categorías: registros
de propósito especial y registros de propósito general Los registros de propósito especial
incluyen cosas como el contador de programa y el puntero de pila, así como otros registros con
una función específica. En contraste, los registros de propósito general están ahí para contener
variables locales clave y resultados intermedios de cálculos. Su función principal es proporcionar
un acceso rápido a datos muy utilizados (básicamente, evitando accesos a la memoria). Las
máquinas RISC, con sus CPU rápidas y memorias (relativamente) lentas, generalmente tienen al
menos 32 registros de propósito general, y la tendencia en los nuevos diseños de CPU es tener
aún más.
En algunas máquinas, los registros de propósito general son completamente simétricos e
intercambiables. Cada uno puede hacer cualquier cosa que los demás puedan hacer. Si los registros
350 EL NIVEL DE ARQUITECTURA DEL CONJUNTO DE INSTRUCCIONES CAP. 5
son todos equivalentes, un compilador puede usar R1 para mantener un resultado temporal, pero
también se puede utilizar R25. La elección del registro no importa.
En otras máquinas, sin embargo, algunos de los registros de propósito general pueden ser
algo especiales. Por ejemplo, en el Core i7, hay un registro llamadoEDX que puede usarse como
un registro general, pero que también recibe la mitad del producto en una multiplicación y
retiene la mitad del dividendo en una división.
Incluso cuando los registros de propósito general son completamente intercambiables, es común
que el sistema operativo o los compiladores adopten convenciones sobre cómo se usan. Por ejemplo,
algunos registros pueden contener parámetros para procedimientos llamados y otros pueden usarse
como registros temporales. Si un compilador pone una variable local importante enR1 y luego llama a
un procedimiento de biblioteca que piensa R1 es un registro temporal disponible para él, cuando el
procedimiento de biblioteca regresa, R1 puede contener basura. Si existen convenciones en todo el
sistema sobre cómo se utilizarán los registros, se recomienda a los compiladores y programadores en
lenguaje ensamblador que se adhieran a ellas para evitar problemas.
Además de los registros de nivel ISA visibles para los programas de usuario, siempre
hay una cantidad sustancial de registros de propósito especial disponibles solo en modo
kernel. Estos registros controlan los distintos cachés, memoria, dispositivos de E / S y otras
características de hardware de la máquina. Solo los usa el sistema operativo, por lo que los
compiladores y los usuarios no tienen que conocerlos.
Un registro de control que es una especie de híbrido kernel / usuario es el registro de
banderas o PSW (Palabra de estado del programa). Este registro contiene varios bits
misceláneos que necesita la CPU. Los bits más importantes son loscódigos de condición.
Estos bits se establecen en cada ciclo de ALU y reflejan el estado del resultado de la operación
más reciente. Los bits de código de condición típicos incluyen
C— Se establece cuando el resultado provocó una ejecución del bit más a la izquierda.
A - Se establece cuando hubo un acarreo del bit 3 (acarreo auxiliar, ver más abajo). P -
Los códigos de condición son importantes porque la comparación y las instrucciones de bifurcación
condicional (también llamadas instrucciones de salto condicional) los utilizan. Por ejemplo, el
CMP La instrucción típicamente resta dos operandos y establece los códigos de condición
basados en la diferencia. Si los operandos son iguales, entonces la diferencia será cero y el
Z bit de código de condición en el PSW Se establecerá el registro. Una subsecuenteBEQ
(Branch EQual) prueba la Z bit y ramas si está configurado.
los PSW contiene más que solo los códigos de condición, pero el contenido completo
varía de una máquina a otra. Los campos adicionales típicos son el modo de máquina
SEGUNDO. 5.1 DESCRIPCIÓN GENERAL DEL NIVEL ISA 351
(por ejemplo, usuario o kernel), bit de seguimiento (utilizado para depurar), nivel de prioridad de la CPU y estado de
habilitación de interrupciones. A menudo elPSW es legible en modo de usuario, pero algunos de los campos sólo se
pueden escribir en modo kernel (por ejemplo, el bit de modo usuario / kernel).
5.1.4 Instrucciones
En este capítulo analizaremos tres ISA muy diferentes: el IA-32 de Intel, como se
incorpora en el Core i7, la arquitectura ARM v7, implementada en el sistema en un
chip OMAP4430, y la arquitectura AVR de 8 bits, utilizada por el microcontrolador
ATmega168. La intención no es proporcionar una descripción exhaustiva de ninguna
de las NIA, sino más bien demostrar aspectos importantes de una NIA y mostrar cómo
estos aspectos pueden variar de una NIA a otra. Comencemos con el Core i7.
(a menudo llamado x86-64), que aumentó los cálculos de números enteros y el tamaño de la dirección
virtual a 64 bits. Si bien la mayoría de las extensiones fueron introducidas por Intel y luego
implementadas por los competidores, este fue un caso en el que AMD introdujo una extensión que Intel
tuvo que adoptar.
El Core i7 tiene tres modos de funcionamiento, dos de los cuales lo hacen actuar como un
8088. En modo real, todas las funciones que se han agregado desde el 8088 están desactivadas y
el Core i7 se comporta como un simple 8088. Si algún programa hace algo mal, toda la máquina
simplemente falla. Si Intel hubiera diseñado seres humanos, habría puesto un poco que los
hubiera hecho volver al modo chimpancé (la mayoría de los cerebrales discapacitados, no habla,
duerme en los árboles, come principalmente plátanos, etc.)
Un paso hacia arriba es modo virtual 8086, lo que hace posible ejecutar programas
antiguos del 8088 de forma protegida. En este modo, un sistema operativo real tiene el control
de toda la máquina. Para ejecutar un programa 8088 antiguo, el sistema operativo crea un
entorno aislado especial que actúa como un 8088, excepto que si su programa falla, se notifica al
sistema operativo en lugar de que la máquina se bloquee. Cuando un usuario de Windows inicia
una ventana de MS-DOS, el programa que se ejecuta allí se inicia en el modo virtual 8086 para
proteger al propio Windows de los programas de MS-DOS que se comportan mal.
El modo final es el modo protegido, en el que el Core i7 actúa como un Core i7 en lugar
de un 8088 muy caro. Hay cuatro niveles de privilegios disponibles y controlados por bits en
el PSW. El nivel 0 corresponde al modo kernel en otras computadoras y tiene acceso
completo a la máquina. Es utilizado por el sistema operativo. El nivel 3 es para programas
de usuario. Bloquea el acceso a ciertas instrucciones críticas y registros de control para
evitar que un programa de usuario fraudulento apague toda la máquina. Los niveles 1 y 2
rara vez se utilizan.
El Core i7 tiene un gran espacio de direcciones, con memoria dividida en 16,384 segmentos, cada
uno de los cuales va de la dirección 0 a la dirección 2.32 - 1. Sin embargo, la mayoría de los sistemas
operativos (incluidos UNIX y todas las versiones de Windows) admiten solo un segmento, por lo que la
mayoría de los programas de aplicación ven efectivamente un espacio de direcciones lineal de 232 bytes
y, a veces, parte de esto está ocupado por el sistema operativo. Cada byte en el espacio de direcciones
tiene su propia dirección, con palabras de 32 bits de longitud. Las palabras se almacenan en formato
little-endian (el byte de orden inferior tiene la dirección más baja).
Los registros del Core i7 se muestran en la figura 5-3. Los primeros cuatro registros,
EAX, EBX, ECX, y EDX, son
registros de 32 bits, más o menos de propósito general, aunque cada
uno tiene sus propias peculiaridades. EAX es el registro aritmético principal; EBX es bueno
para guardar punteros (direcciones de memoria); ECX juega un papel en el bucle; EDX es
necesario para la multiplicación y la división, donde, junto con EAX, contiene dividendos y
productos de 64 bits. Cada uno de estos registros contiene un registro de 16 bits en los 16
bits de orden inferior y un registro de 8 bits en los 8 bits de orden inferior. Estos registros
facilitan la manipulación de cantidades de 16 y 8 bits, respectivamente. El 8088 y el 80286
solo tenían registros de 8 y 16 bits. Los registros de 32 bits se agregaron con el 80386, junto
con elmi prefijo, que significa Extendido.
Los cuatro siguientes también son de propósito algo general, pero con más peculiaridades. losESI y
EDI Los registros están destinados a mantener punteros en la memoria, especialmente para
SEGUNDO. 5.1 DESCRIPCIÓN GENERAL DEL NIVEL ISA 353
Bits dieciséis 8 8
HACHA
AH Alabama EAX
BX
BH licenciado en Derecho EBX
CX
CH CL ECX
DX
DH DL EDX
ESI
EDI
EBP
ESP
CS
SS
DS
ES
FS
GS
EIP
EFLAGS
La arquitectura ARM fue introducida por primera vez en 1985 por Acorn Computer. La
arquitectura se inspiró en la investigación realizada en Berkeley en la década de 1980 (Patterson,
1985 y Patterson y Séquin, 1982). La arquitectura ARM original (llamada ARM2) era una
arquitectura de 32 bits que admitía un espacio de direcciones de 26 bits. El OMAP4430
utiliza la microarquitectura ARM Cortex A9, que implementa la versión 7 de la
arquitectura ARM, y esa es la ISA que describiremos en este capítulo. Para mantener la
coherencia con el resto del libro, aquí nos referiremos al OMAP4430, pero a nivel ISA,
todos los diseños basados en el núcleo ARM Cortex A9 implementan el mismo ISA.
El ARM ISA tiene dos grupos de registros. Estos son los registros de propósito
general de 16 32 bits y los registros de coma flotante de 32 bits (si se admite el
coprocesador VFP). Los registros de propósito general se denominanR0 mediante R15,
SEGUNDO. 5.1 DESCRIPCIÓN GENERAL DEL NIVEL ISA 355
aunque se utilizan otros nombres en determinados contextos. Los nombres y funciones alternativos de
los registros se muestran en la figura 5-4.
R13 SP de pila
Todos los registros generales tienen 32 bits de ancho y se pueden leer y escribir
mediante una variedad de instrucciones de carga y almacenamiento. Los usos dados en la
figura 5-4 se basan en parte en la convención, pero también en parte en cómo los trata el
hardware. En general, no es aconsejable desviarse de los usos enumerados en la figura a
menos que tenga un cinturón negro en piratería ARM y realmente sepa lo que está
haciendo. Es responsabilidad del compilador o programador asegurarse de que el
programa acceda a los registros correctamente y realice el tipo correcto de aritmética en
ellos. Por ejemplo, es muy fácil cargar números de punto flotante en los registros generales
y luego realizar la suma de enteros en ellos, una operación que producirá un sinsentido
total, pero que la CPU realizará alegremente cuando se le indique.
los Vx Los registros se utilizan para contener constantes, variables y punteros que son necesarios
para los procedimientos, y deben almacenarse y volver a cargarse en las entradas y salidas de los
procedimientos si es necesario. losHacha Los registros se utilizan para pasar parámetros a los
procedimientos para evitar referencias a la memoria. Explicaremos cómo funciona esto a continuación.
Se utilizan cuatro registros dedicados para fines especiales. losIP El registro funciona
alrededor de las limitaciones de la instrucción de llamada funcional ARM (BL) que no puede
abordar completamente todos sus 232 bytes de espacio de direcciones. Si el objetivo de una
llamada está demasiado lejos para que la instrucción se exprese, la instrucción llamará a un
fragmento de código '' barniz '' que usa la dirección en elIP registrarse como destino de la
llamada a la función. losSP register indica la parte superior actual de la pila y fluctúa a medida
que las palabras se introducen en la pila o salen de ella. El tercer registro de fines especiales esLR.
Se utiliza para que las llamadas a procedimientos retengan la dirección de retorno. El cuarto registro de
propósito especial, como se mencionó anteriormente, es el contador de programaORDENADOR PERSONAL.
El almacenamiento de un valor en este registro redirige la búsqueda de instrucciones al recién
depositado ordenador personal Dirección. Otro registro importante en la arquitectura ARM es el registro de
estado del programa (PSR), que mantiene el estado de los cálculos de ALU anteriores, incluidos Cero,
Negativo y Desbordamiento, entre otros bits.
El ARM ISA (cuando se configura con el coprocesador VFP) también tiene 32 registros de coma
flotante de 32 bits. Se puede acceder a estos registros directamente como 32 valores de punto flotante
de precisión simple o como 16 valores de punto flotante de precisión doble de 64 bits.
356 EL NIVEL DE ARQUITECTURA DEL CONJUNTO DE INSTRUCCIONES CAP. 5
valores. El tamaño del registro de punto flotante al que se accede está determinado por la
instrucción; en general, todas las instrucciones de punto flotante ARM vienen en variantes de
precisión simple y doble.
La arquitectura ARM es una arquitectura de carga / almacenamiento. Es decir, las únicas
operaciones que acceden a la memoria directamente son las instrucciones de carga y almacenamiento
para mover datos entre los registros y la memoria. Todos los operandos para instrucciones aritméticas
y lógicas deben provenir de registros o ser suministrados por la instrucción (no en la memoria), y todos
los resultados deben guardarse en un registro (no en la memoria).
El ATmega168 utiliza una organización de memoria de dos niveles para proporcionar una mejor
seguridad del programa. La memoria flash del programa se divide ensección del cargador de arranque y
sección de aplicación, el tamaño de cada uno está determinado por bits de fusible que se programan
una vez cuando el microcontrolador se enciende por primera vez. Por razones de seguridad, solo el
código que se ejecuta desde la sección del cargador de arranque puede actualizar la memoria flash. Con
esta función, cualquier código se puede colocar en el área de la aplicación (incluidas las aplicaciones
descargadas de terceros) con la confianza de que nunca se mezclará con otro código en el sistema
(porque el código de la aplicación se ejecutará desde el espacio de la aplicación que no puede escribir
memoria flash ). Para realmente atar un sistema, un proveedor puede firmar código digitalmente. Con
el código firmado, el cargador de arranque carga el código en la memoria flash solo si está firmado
digitalmente por un proveedor de software aprobado. Como tal, el sistema
SEGUNDO. 5.1 DESCRIPCIÓN GENERAL DEL NIVEL ISA 357
sólo ejecutará código que haya sido "bendecido" por un proveedor de software de confianza. El enfoque
es bastante flexible en el sentido de que incluso el cargador de arranque se puede reemplazar, si el
nuevo código se ha firmado digitalmente correctamente. Esto es similar a la forma en que Apple y TiVo
se aseguran de que el código que se ejecuta en sus dispositivos esté a salvo de daños.
El ATmega168 contiene 32 registros de uso general de 8 bits, a los que se accede mediante
instrucciones a través de un campo de 5 bits que especifica qué registro utilizar. Los registros se
llamanR0 mediante R31. Una propiedad peculiar de los registros ATmega168 es que también están
presentes en el espacio de la memoria. El byte 0 del espacio de datos es equivalente aR0 del
registro establecido en 0. Cuando una instrucción cambia R0 y luego lee el byte de memoria 0,
encuentra el nuevo valor de R0 allí. Del mismo modo, el byte 1 de memoria
es R1 y así sucesivamente, hasta el byte 31. Esta disposición se muestra en la Fig. 5-5.
Programa de memoria
16383
Memoria de datos
Solicitud
1023
memoria Bloc de notas
95
Memoria de E / S
32
Cargador de arranque 31
0 Registros
0
7 0
Registro de estado (SREG) ITHSVNZC
Elevado Dirección 80
con él, un bit de habilitación de interrupciones. Si la habilitación del dispositivo está configurada y la habilitación de interrupción
Todas las computadoras necesitan datos. De hecho, para muchos sistemas informáticos, el
objetivo principal es procesar datos financieros, comerciales, científicos, de ingeniería u otros. Los datos
deben estar representados de alguna forma específica dentro de la computadora. A nivel ISA, se utilizan
una variedad de diferentes tipos de datos. Estos se explicarán a continuación.
Una cuestión clave es si hay soporte de hardware para un tipo de datos en particular. El
soporte de hardware significa que una o más instrucciones esperan datos en un formato
particular, y el usuario no es libre de elegir un formato diferente. Por ejemplo, los contadores
tienen la peculiar costumbre de escribir números negativos con el signo menos a la derecha del
número en lugar de a la izquierda, donde lo ponen los científicos informáticos. Suponga que, en
un esfuerzo por impresionar a su jefe, el director del centro de cómputo de una empresa de
contabilidad cambia todos los números de todas las computadoras para usar el bit más a la
derecha (en lugar del bit más a la izquierda) como bit de signo. Sin duda, esto causaría una gran
impresión en el jefe, porque todo el software dejaría de funcionar correctamente al instante. El
hardware espera un cierto formato para los números enteros y no funciona correctamente
cuando se le da cualquier otra cosa.
Ahora considere otra firma de contabilidad, esta acaba de obtener un contrato para verificar
la deuda federal (cuánto el gobierno de los Estados Unidos les debe a todos). El uso de aritmética
de 32 bits no funcionaría aquí porque los números involucrados son mayores que 232 (alrededor
de 4 mil millones). Una solución es usar dos enteros de 32 bits para representar cada número, lo
que da 64 bits en total. Si la máquina no es compatiblePrecisión doble números, toda la
aritmética en ellos tendrá que hacerse en software, pero las dos partes pueden estar en cualquier
orden ya que al hardware no le importa. Este es un ejemplo de un tipo de datos sin soporte de
hardware y, por lo tanto, sin una representación de hardware requerida. En las siguientes
secciones, veremos los tipos de datos que son compatibles con el hardware y, por lo tanto, para
los que se requieren formatos específicos.
Los tipos de datos se pueden dividir en dos categorías: numéricos y no numéricos. El principal de
los tipos de datos numéricos son los enteros. Vienen en muchas longitudes, normalmente de 8, 16, 32 y
64 bits. Los enteros cuentan cosas (p. Ej., El número de destornilladores
SEGUNDO. 5.2 TIPOS DE DATOS 359
una ferretería tiene en stock), identificar cosas (por ejemplo, números de cuentas bancarias) y mucho
más. La mayoría de las computadoras modernas almacenan números enteros en notación binaria en
complemento a dos, aunque también se han utilizado otros sistemas en el pasado. Los números
binarios se analizan en el Apéndice A.
Algunas computadoras admiten enteros sin firmar y con signo. Para un entero sin signo, no
hay bit de signo y todos los bits contienen datos. Este tipo de datos tiene la ventaja de un bit
adicional, por lo que, por ejemplo, una palabra de 32 bits puede contener un solo entero sin
signo en el rango de 0 a 232 - 1, inclusive. Por el contrario, un entero de 32 bits con signo en
complemento a dos solo puede manejar números hasta 231 - 1, pero, por supuesto, también
puede manejar números negativos.
Para los números que no se pueden expresar como un número entero, como 3.5, se utilizan
números de coma flotante. Estos se analizan en el Apéndice B. Tienen longitudes de 32,
64 o 128 bits. La mayoría de las computadoras tienen instrucciones para realizar operaciones aritméticas en
coma flotante. Muchas computadoras tienen registros separados para almacenar operandos enteros y para
almacenar operandos de coma flotante.
Algunos lenguajes de programación, en particular COBOL, permiten números decimales
como tipo de datos. Las máquinas que desean ser compatibles con COBOL a menudo admiten
números decimales en el hardware, generalmente codificando un dígito decimal en 4 bits y luego
empaquetando dos dígitos decimales por byte (formato decimal de código binario). Sin embargo,
la aritmética binaria no funciona correctamente en números decimales empaquetados, por lo
que se necesitan instrucciones especiales de corrección decimalaritmética. Estas instrucciones
necesitan conocer la ejecución del bit 3. Esta es la razón por la que el código de condición a
menudo contiene un bit de ejecución auxiliar. Aparte, el infame problema Y2K (año 2000) fue
causado por programadores de COBOL que decidieron que podían representar el año en dos
dígitos decimales (8 bits) en lugar de cuatro dígitos decimales (o un número binario de 8 bits),
que puede contienen incluso más valores (256) que dos dígitos decimales (100).
Los valores booleanos también son importantes. Un valor booleano puede tomar uno de dos
valores: verdadero o falso. En teoría, un solo bit puede representar un booleano, con 0 como falso y 1
como verdadero (o viceversa). En la práctica, se utiliza un byte o una palabra por valor booleano porque
los bits individuales de un byte no tienen sus propias direcciones y, por lo tanto, son difíciles de acceder.
Un sistema común usa la convención de que 0 significa falso y todo lo demás significa verdadero.
La única situación en la que un valor booleano se representa normalmente por 1 bit es cuando hay una
matriz completa de ellos, por lo que una palabra de 32 bits puede contener 32 valores booleanos. Esta
estructura de datos se llamamapa de bits y ocurre en muchos contextos. Por ejemplo, se puede utilizar un
mapa de bits para realizar un seguimiento de los bloques libres en un disco. Si el disco tiene
norte bloques, entonces el mapa de bits tiene norte bits.
Nuestro último tipo de datos es el puntero, que es solo una dirección de máquina. Ya hemos
visto punteros repetidamente. En el micrófonoX máquinas, SP, PC, LV, y CPP son todos ejemplos de
punteros. Acceder a una variable a una distancia fija de un puntero, que es la formaYO CARGO
funciona, es extremadamente común en todas las máquinas. Si bien los punteros son útiles,
también son la fuente de una gran cantidad de errores de programación, a menudo con
consecuencias muy graves. Deben usarse con mucho cuidado.
El Core i7 admite enteros en complemento a dos con signo, enteros sin signo, números decimales
codificados en binario y números de coma flotante IEEE 754, como se muestra en la figura 5-6. Debido a
sus orígenes como una humilde máquina de 8 bits / 16 bits, maneja enteros de estas longitudes así
como de 32 bits, con numerosas instrucciones para realizar operaciones aritméticas, booleanas y
comparaciones sobre ellos. El procesador se puede ejecutar opcionalmente en modo de 64 bits, que
también admite registros y operaciones de 64 bits. Los operandos hacen
no tiene que estar alineado en la memoria, pero mejor el rendimiento se logra si la palabra
los vestidos son múltiplos de 4 bytes.
Figura 5-6. Los tipos de datos numéricos del Core i7. Los tipos admitidos están marcados con×.
Los tipos marcados con "64 bits" solo se admiten en el modo de 64 bits.
El Core i7 también es bueno para manipular caracteres ASCII de 8 bits: hay instrucciones
especiales para copiar y buscar cadenas de caracteres. Estas instrucciones se pueden utilizar
tanto con cadenas cuya longitud se conoce de antemano como con cadenas cuyo final está
marcado. A menudo se utilizan en bibliotecas de manipulación de cadenas.
SEGUNDO. 5.2 TIPOS DE DATOS 361
La CPU ARM OMAP4430 admite una amplia gama de formatos de datos, como se muestra en
la Fig. 5-7. Solo para enteros, puede admitir operandos de 8, 16 y 32 bits, tanto con signo como
sin signo. El manejo de tipos de datos pequeños en el OMAP4430 es un poco más inteligente que
en el Core i7. Internamente, el OMAP4430 es una máquina de 32 bits con rutas de datos e
instrucciones de 32 bits. Para cargas y almacenes, el programa puede especificar el tamaño y el
signo del valor que se cargará (por ejemplo, cargar byte con signo:LDRSB). A continuación, las
instrucciones de carga convierten el valor en un valor comparable de 32 bits. De manera similar,
las tiendas también especifican el tamaño y el signo del valor para escribir en la memoria, y solo
acceden a la parte especificada del registro de entrada.
Los enteros con signo utilizan el complemento a dos. Se incluyen operandos de coma
flotante de 32 y 64 bits que cumplen con el estándar IEEE 754. No se admiten números decimales
codificados en binario. Todos los operandos deben estar alineados en la memoria. Los tipos de
datos de caracteres y cadenas no son compatibles con instrucciones especiales de hardware. Son
manipulado íntegramente en software.
Punto flotante × ×
Figura 5-7. Los tipos de datos numéricos de la CPU ARM OMAP4430. Los tipos admitidos están
marcados con×.
El ATmega168 tiene un número muy limitado de tipos de datos. Con una excepción, todos los registros
tienen un ancho de 8 bits, por lo que los enteros también tienen un ancho de 8 bits. Los caracteres también
tienen 8 bits de ancho. En esencia, el único tipo de datos que realmente es compatible con el hardware.
para operaciones aritméticas es el byte de 8 bits, como se muestra en la figura 5-8.
Punto flotante
Figura 5-8. Los tipos de datos numéricos ATmega168. Tipos admitidos están marcados
con×.
362 EL NIVEL DE ARQUITECTURA DEL CONJUNTO DE INSTRUCCIONES CAP. 5
Para facilitar el acceso a la memoria, el ATmega168 también incluye soporte limitado para
punteros sin firmar de 16 bits. Los punteros de 16 bitsX, Y, y Z, se puede formar a partir de la
concatenación de pares de registros de 8 bits R26 / R27, R28 / R29, y R30 / R31, respectivamente.
Cuando una carga usaX, Y, o Z como operando de dirección, el procesador también incrementará
o reducirá opcionalmente el valor según sea necesario.
(a) (B)
(C) (D)
Figura 5-9. Cuatro formatos de instrucción comunes: (a) Instrucción de dirección cero.
(b) Instrucción de una dirección (c) Instrucción de dos direcciones. (d) Instrucción de tres
direcciones.
En algunas máquinas, todas las instrucciones tienen la misma longitud; en otros, puede
haber muchas longitudes diferentes. Las instrucciones pueden ser más cortas, iguales o más
largas que la longitud de la palabra. Tener todas las instrucciones de la misma longitud es más
simple y facilita la decodificación, pero a menudo desperdicia espacio, ya que todas las
instrucciones deben ser tan largas como la más larga. También son posibles otras
compensaciones. La figura 5-10 muestra algunas posibles relaciones entre la longitud de la
instrucción y la longitud de la palabra.
Figura 5-10. Algunas posibles relaciones entre la instrucción y la longitud de las palabras.
nuevas instrucciones y aprovechar otras oportunidades que surjan durante un período extendido período
es de gran importancia, pero solo si la arquitectura y la empresa que la construye
sobreviven lo suficiente para que la arquitectura sea un éxito.
La eficiencia de un ISA en particular depende en gran medida de la tecnología con la que se
implementará la computadora. Durante un largo período de tiempo, esta tecnología sufrirá
grandes cambios, y algunas de las opciones de ISA se considerarán (en retrospectiva 20/20) como
desafortunadas. Por ejemplo, si los accesos a la memoria son rápidos, un diseño basado en pila
(como IJVM) es bueno, pero si son lentos, entonces tener muchos registros (como la CPU
OMAP4430 ARM) es el camino a seguir. Se invita a los lectores que piensen que esta elección es
fácil a buscar un trozo de papel y escribir sus predicciones para (1) una velocidad de reloj de CPU
típica y (2) un tiempo de acceso a RAM típico para computadoras de 20 años en el futuro. Doble
este papel con cuidado y guárdelo durante 20 años. Luego desdóblalo y léelo. Los desafiados por
la humildad pueden olvidar el papelito y publicar sus predicciones en Internet ahora mismo.
Por supuesto, incluso los diseñadores con visión de futuro pueden no ser capaces de tomar
todas las decisiones correctas. E incluso si pudieran, también tienen que lidiar con el corto plazo.
Si este elegante ISA es un poco más caro que sus feos competidores actuales, es posible que la
empresa no sobreviva lo suficiente para que el mundo pueda apreciar la elegancia del ISA.
En igualdad de condiciones, las instrucciones breves son mejores que las largas. Un programa que
consta denorte Las instrucciones de 16 bits ocupan solo la mitad del espacio de memoria que norte
Instrucciones de 32 bits. Con los precios de la memoria en constante descenso, este factor podría ser menos importante
en el futuro, si no fuera por el hecho de que el software está haciendo metástasis incluso más rápido de lo que están
cayendo los precios de la memoria.
Además, minimizar el tamaño de las instrucciones puede hacer que sean más difíciles
de decodificar o de superponerlas. Por lo tanto, el logro del tamaño mínimo de instrucción
debe sopesarse con el tiempo requerido para decodificar y ejecutar las instrucciones.
Otra razón para minimizar la longitud de las instrucciones ya es importante y cada vez lo es más
con procesadores más rápidos: el ancho de banda de la memoria (la cantidad de bits / seg que la
memoria es capaz de suministrar). El impresionante crecimiento de las velocidades del procesador
durante las últimas décadas no ha ido acompañado de aumentos iguales en el ancho de banda de la
memoria. Una restricción cada vez más común en los procesadores proviene de la incapacidad del
sistema de memoria para proporcionar instrucciones y operandos tan rápido como
364 EL NIVEL DE ARQUITECTURA DEL CONJUNTO DE INSTRUCCIONES CAP. 5
el procesador puede consumirlos. Cada memoria tiene un ancho de banda que está determinado
por su tecnología y diseño de ingeniería. El cuello de botella del ancho de banda se aplica no solo
a la memoria principal sino también a todas las cachés.
Si el ancho de banda de una caché de instrucciones es t bps y la duración media de la instrucción
es r bits, la caché puede entregar como máximo t / r instrucciones por segundo. Tenga en cuenta que
este es unlimite superior sobre la velocidad a la que el procesador puede ejecutar instrucciones, aunque
existen esfuerzos de investigación actuales para romper incluso esta barrera aparentemente
insuperable. Claramente, la velocidad a la que se pueden ejecutar las instrucciones (es decir, la
velocidad del procesador) puede estar limitada por la longitud de la instrucción. Instrucciones más
cortas significan un procesador más rápido. Dado que los procesadores modernos pueden ejecutar
varias instrucciones en cada ciclo de reloj, es imperativo obtener varias instrucciones por ciclo de reloj.
Este aspecto de la caché de instrucciones hace que el tamaño de las instrucciones sea un criterio de
diseño importante que tiene importantes implicaciones para el rendimiento.
Un segundo criterio de diseño es espacio suficiente en el formato de instrucción para expresar
todas las operaciones deseadas. Una maquina con 2norte operaciones con todas las instrucciones
menores que norte bits es imposible. Simplemente no habrá suficiente espacio en el código de
operación para indicar qué instrucción se necesita. Y la historia ha demostrado una y otra vez la locura
de no dejar una cantidad sustancial de códigos de operación libres para futuras adiciones al conjunto
de instrucciones.
Un tercer criterio se refiere al número de bits en un campo de dirección. Considere el diseño
de una máquina con un carácter de 8 bits y una memoria principal que debe contener 232
caracteres. Los diseñadores pueden optar por asignar direcciones consecutivas a unidades de
8, 16, 24 o 32 bits, entre otras posibilidades.
Imagínese lo que sucedería si el equipo de diseño degenerara en dos facciones en
guerra, una abogando por hacer del byte de 8 bits la unidad básica de memoria y la
otra abogando por la palabra de 32 bits. El primer grupo propondría un recuerdo de 2
32 bytes, numerados 0, 1, 2, 3, ..., 4.294.967.295. Este último grupo propondría una
(por ejemplo, el Burroughs B1700). En el otro extremo hay una memoria que consta de palabras muy
largas (por ejemplo, la serie CDC Cyber tenía palabras de 60 bits).
Los sistemas informáticos modernos han llegado a un compromiso que, en cierto sentido,
captura lo peor de ambos. Requieren todos los bits necesarios para direccionar bytes
individuales, pero los accesos a la memoria leen una, dos o, a veces, cuatro palabras a la vez. La
lectura de 1 byte de la memoria en el Core i7, por ejemplo, trae un mínimo de 8 bytes y
probablemente una línea completa de caché de 64 bytes.
En la sección anterior vimos cómo las direcciones cortas y la buena resolución de memoria
pueden intercambiarse entre sí. En esta sección examinaremos nuevas compensaciones, que
involucran tanto códigos de operación como direcciones. Considere un (n + k) instrucción de bits
con un k-bit opcode y un solo norte-dirección de bit. Esta instrucción permite 2k diferentes
operaciones y 2norte celdas de memoria direccionables. Alternativamente, el mismon + k
los bits se pueden dividir en un (k - 1) código de operación de bits y un (n + 1) dirección de bit, lo
que significa solo la mitad de instrucciones pero el doble de memoria direccionable, o la misma
cantidad de memoria pero con el doble de resolución. A (k + 1) código de operación de bits y un (
norte - 1) la dirección de bit proporciona más operaciones, pero el precio es un número menor de
celdas direccionables o una resolución más pobre y la misma cantidad de memoria direccionable.
Son posibles compensaciones bastante sofisticadas entre los bits de código de operación y los
bits de dirección, así como los más simples que se acaban de describir. El esquema discutido en
los siguientes párrafos se llamaexpandiendo opcode.
El concepto de un código de operación en expansión se puede ver más claramente con un ejemplo
simple. Considere una máquina en la que las instrucciones tienen una longitud de 16 bits y las direcciones de 4
bits, como se muestra en la figura 5-11. Esta situación podría ser razonable para una máquina que tiene 16
registros (por lo tanto, una dirección de registro de 4 bits) en la que toda la aritmética
tienen lugar las operaciones. Un diseño sería un código de operación de 4 bits y tres direcciones en
cada instrucción, dando 16 instrucciones de tres direcciones.
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Figura 5-11. Una instrucción con un 4 bits código de operación y tres campos de dirección de 4 bits.
Sin embargo, si los diseñadores necesitan 15 instrucciones de tres direcciones, 14 instrucciones de dos
direcciones, 31 instrucciones de una dirección y 16 instrucciones sin dirección en absoluto, pueden usar los códigos de
operación 0 a 14 como instrucciones de tres direcciones pero interpretar el código de operación 15 de manera
diferente. (vea la Fig. 5-12).
El código de operación 15 significa que el código de operación está contenido en los bits 8 a 15 en lugar
de los bits 12 a 15. Los bits 0 a 3 y 4 a 7 forman dos direcciones, como es habitual. Las 14 dos direcciones
366 EL NIVEL DE ARQUITECTURA DEL CONJUNTO DE INSTRUCCIONES CAP. 5
16 bits
...
1100 xxxx yyyy zzzz 1101
xxxx yyyy zzzz 1110 xxxx
yyyy zzzz
15 12 11 8 7 4 3 0
Número de bits
Figura 5-12. Un código de operación en expansión que permite 15 instrucciones de tres direcciones, 14
instrucciones de dos direcciones, 31 instrucciones de una dirección y 16 instrucciones de dirección cero.
Los campos marcadosxxxx, aaaa, y zzzz son campos de dirección de 4 bits.
SEGUNDO. 5.3 FORMATOS DE INSTRUCCIONES 367
todas las instrucciones tienen 1111 en los 4 bits más a la izquierda y números de 0000 a 1101 en los bits
8 a 11. Las instrucciones con 1111 en los 4 bits más a la izquierda y 1110 o 1111 en los bits 8 a 11 serán
tratadas especialmente. Se tratarán como si sus códigos de operación estuvieran en los bits 4 a 15. El
resultado son 32 códigos de operación nuevos. Debido a que solo se necesitan 31, el código de
operación 111111111111 se interpreta en el sentido de que el código de operación real está en los bits
0 a 15, dando 16 instrucciones sin dirección.
A medida que avanzábamos en esta discusión, el código de operación se hizo más y más largo: las instrucciones
de tres direcciones tienen un código de operación de 4 bits, las instrucciones de dos direcciones tienen un código de
operación de 8 bits, las instrucciones de una dirección tienen un código de operación de 12 bits, y las instrucciones de
dirección cero tienen un código de operación de 16 bits.
La idea de expandir los códigos de operación demuestra una compensación entre el espacio para los
códigos de operación y el espacio para otra información. En la práctica, expandir los códigos de operación no
es tan limpio y regular como en nuestro ejemplo. De hecho, la capacidad de utilizar tamaños variables de
códigos de operación se puede aprovechar de dos formas. Primero, todas las instrucciones pueden
mantenerse con la misma longitud, asignando los códigos de operación más cortos a las instrucciones que
necesitan más bits para especificar otras cosas. En segundo lugar, el tamaño delpromedio la instrucción se
puede minimizar eligiendo códigos de operación que sean más cortos para instrucciones comunes y más
largos para instrucciones raras.
Llevando la idea de códigos de operación de longitud variable al extremo, es posible
minimizar la longitud promedio de instrucción codificando cada instrucción para minimizar el
número de bits necesarios. Desafortunadamente, esto daría como resultado instrucciones de
varios tamaños que ni siquiera se alinean en los límites de bytes. Si bien ha habido ISA que tenían
esta propiedad (por ejemplo, el desafortunado Intel 432), la importancia de la alineación es tan
grande para la rápida decodificación de instrucciones que este grado de optimización es casi con
certeza contraproducente.
Los formatos de instrucción del Core i7 son muy complejos e irregulares, y tienen hasta seis
campos de longitud variable, de los cuales cinco son opcionales. El patrón general se muestra en la
figura 5-13. Esta situación se produjo porque la arquitectura evolucionó a lo largo de muchas
generaciones e incluyó algunas malas elecciones desde el principio. En nombre de la compatibilidad con
versiones anteriores, estas primeras decisiones no se pudieron revertir más adelante. En general, para
las instrucciones de dos operandos, si un operando está en la memoria, es posible que el otro no esté
en la memoria. Por lo tanto, existen instrucciones para agregar dos registros, agregar un registro a la
memoria y agregar memoria a un registro, pero no para agregar una palabra de memoria a otra
palabra de memoria.
En arquitecturas Intel anteriores, todos los códigos de operación eran de 1 byte, aunque el concepto de
byte de prefijo se usaba ampliamente para modificar algunas instrucciones. Abyte de prefijo es un código de
operación adicional pegado al frente de una instrucción para cambiar su acción. los
AMPLIO La instrucción en IJVM es un ejemplo de un byte de prefijo. Desafortunadamente, en algún momento
durante la evolución, Intel se quedó sin códigos de operación, por lo que un código de operación, 0xFF, fue
designado comocódigo de escape para permitir un segundo byte de instrucción.
368 LOS CONJUNTO DE INSTRUCCIONES NIVEL DE ARQUITECTURA CAP. 5
Bits 6 11 Bits 2 3 3
INSTRUCCIÓN ÍNDICE DE ESCALA BASE
Byte / palabra
Bits 2 3 3
MODIFICACIÓN REG R/M
Los bits individuales en los códigos de operación del Core i7 no brindan mucha información
sobre la instrucción. La única estructura en el campo del código de operación es el uso del bit de
orden inferior en algunas instrucciones para indicar byte / palabra, y el uso del bit contiguo para
indicar si la dirección de memoria (si está presente) es el origen o el destino. . Por lo tanto, en
general, el código de operación debe decodificarse completamente para determinar qué clase de
operación se va a realizar y, por lo tanto, cuánto tiempo dura la instrucción. Esto dificulta las
implementaciones de alto rendimiento, ya que es necesaria una decodificación extensa antes de
que se pueda determinar dónde comienza la siguiente instrucción.
Después del byte del código de operación en la mayoría de las instrucciones que hacen referencia
a un operando en la memoria hay un segundo byte que dice todo sobre el operando. Estos 8 bits se
dividen en 2 bits.MODIFICACIÓN campo y dos campos de registro de 3 bits, REG y R / M. A veces, los primeros
3 bits de este byte se utilizan como una extensión para el código de operación, dando un total de 11 bits
para el código de operación. Sin embargo, el campo de modo de 2 bits significa que solo hay cuatro
formas de direccionar operandos y uno de los operandos siempre debe ser un registro. Lógicamente,
cualquiera deEAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP debe ser especificable como cualquiera de los registros,
pero las reglas de codificación prohíben algunas combinaciones y las usan para casos especiales.
Algunos modos requieren un byte adicional, llamadoSIB (escala, índice, base), dando una
especificación adicional. Este esquema no es ideal, sino un compromiso dadas las demandas
competitivas de compatibilidad con versiones anteriores y el deseo de agregar nuevas características no
previstas originalmente.
Además de todo esto, algunas instrucciones tienen 1, 2 o 4 bytes más que especifican una
dirección de memoria (desplazamiento) y posiblemente otros 1, 2 o 4 bytes que contienen una
constante (operando inmediato).
operandos y un registro de destino único. Las instrucciones de 16 bits son versiones reducidas de
la instrucción de 32 bits. Realizan las mismas operaciones, pero permiten solo dos operandos de
registro (es decir, el registro de destino debe ser el mismo que una de las entradas) y solo los
primeros ocho registros pueden especificarse como entradas. Los arquitectos de ARM llamaron a
esta versión más pequeña de ARM ISA el Thumb ISA.
Las variantes adicionales permiten que las instrucciones proporcionen una constante sin
signo de 3, 8, 12, 16 o 24 bits en lugar de uno de los registros. Para una instrucción de carga, se
suman dos registros (o un registro y una constante con signo de 8 bits) para especificar la
dirección de memoria a leer. Los datos se escriben en el otro registro especificado.
El formato de las instrucciones ARM de 32 bits se ilustra en la figura 5-14. El lector
atento notará que algunos de los formatos tienen los mismos campos (por ejemplo,
MULTIPLICACIÓN LARGA y INTERCAMBIO). En el caso de la INTERCAMBIO instrucción, el decodificador sabe
que la instrucción es una INTERCAMBIO sólo cuando ve que la combinación de valores de campo
para el MUL es ilegal. Se han agregado formatos adicionales para extensiones de instrucciones y
Thumb ISA. En el momento de escribir este artículo, la cantidad de formatos de instrucción era 21
y estaba aumentando. (¿Puede pasar mucho tiempo antes de que veamos a alguna empresa
anunciando la "máquina RISC más compleja del mundo"?)
ciones, sin embargo, todavía utilizan los formatos que se muestran en la figura.
Cond 1 1 1 0 Op1 CRn CRd CPNum Op2 0 CRm Rd Operación de datos del coprocesador
Cond 1 1 1 0 Op1 L CRn 1 1 1 CPNum Op2 1 CRm Transferencia de registro del coprocesador
Los bits 26 y 27 de cada instrucción son la primera parada para determinar el formato de
instrucción y le dicen al hardware dónde encontrar el resto del código de operación, si hay más.
Por ejemplo, si los bits 26 y 27 son ambos cero, y el bit 25 es cero (el operando no es inmediato) y
el desplazamiento del operando de entrada no es ilegal (lo que indica que la instrucción es un
intercambio de multiplicación o bifurcación), entonces ambas fuentes son registros. Si el bit 25 es
uno, entonces una fuente es un registro y la otra es una constante en el rango de 0 a 4095.
370 EL NIVEL DE ARQUITECTURA DEL CONJUNTO DE INSTRUCCIONES CAP. 5
El ATmega168 tiene seis formatos de instrucciones simples, como se ilustra en la figura 5-15. Las
instrucciones tienen una longitud de 2 o 4 bytes. El formato uno consta de un código de operación y dos
operandos de registro, los cuales son entradas y el otro también es la salida de la instrucción. los
AGREGAR instrucción para registros utiliza este formato, por ejemplo.
El formato 2 también es de 16 bits, que consta de 16 códigos de operación adicionales y un
número de registro de 5 bits. Este formato aumenta el número de operaciones codificadas en el
ISA a costa de reducir el número de operandos de instrucción a uno. Las instrucciones que
utilizan este formato realizan una operación unaria, tomando una única entrada de registro y
escribiendo la salida de la operación en el mismo registro. Ejemplos de este tipo de instrucción
incluyen "negar" e "incrementar".
El formato 3 tiene un operando inmediato sin firmar de 8 bits. Para acomodar un valor
inmediato tan grande en una instrucción de 16 bits, las instrucciones que usan esta
codificación pueden tener solo un operando de registro (usado como entrada y salida) y el
registro solo puede serR16-R31 (que limita la codificación del operando a 4 bits). También el
SEGUNDO. 5.3 FORMATOS DE INSTRUCCIONES 371
Formato
15 0
3 01cc KKKK dddd KKKK ALU + Imm: Código de operación (c) Rd, #K
31 0
número de Los bits de código de operación se reducen a la mitad, lo que permite que solo cuatro instrucciones utilicen este formato.
esteraSUBCI, SUBI, ORI, y Y YO).
El formato 4 codifica la instrucción de carga y almacenamiento, que incluye un operando inmediato sin
firmar de 6 bits. El registro base es un registro fijo no especificado en la codificación de instrucciones porque
está implícito en el código de operación de carga / almacenamiento.
Los formatos 5 y 6 se utilizan para saltos y llamadas a procedimientos. El primer formato
incluye un valor inmediato con signo de 12 bits que se agrega al valor de PC de la instrucción
para calcular el objetivo de la instrucción. El último formato expande el desplazamiento a 22 bits,
haciendo que la instrucción AVR tenga un tamaño de 32 bits.
5.4 DIRECCIÓN
La mayoría de las instrucciones tienen operandos, por lo que se necesita alguna forma de
especificar dónde están. Este tema, que discutiremos ahora, se llamadireccionamiento.
Hasta ahora, hemos prestado poca atención a cómo se interpretan los bits de un campo de
dirección para encontrar el operando. Ha llegado el momento de investigar este tema, llamado
modos de dirección. Como veremos, hay muchas formas de hacerlo.
372 EL NIVEL DE ARQUITECTURA DEL CONJUNTO DE INSTRUCCIONES CAP. 5
La forma más sencilla de que una instrucción especifique un operando es que la parte
de dirección de la instrucción contenga realmente el operando en sí en lugar de una
dirección u otra información que describa dónde está el operando. Tal operando se llama
operando inmediato porque se recupera automáticamente de la memoria al mismo tiempo que
se recupera la instrucción misma; por lo tanto, está inmediatamente disponible para su uso. Una
posible instrucción inmediata para cargar el registro.R1 con la constante 4 se muestra en la figura
5-16.
MOV R1 4
En este pequeño programa, usamos varios modos de direccionamiento. Las primeras tres
instrucciones usan el modo de registro para el primer operando (el destino) y el modo inmediato
para el segundo operando (una constante indicada por el signo #). La segunda instrucción pone el
Dirección de A en R2, no el contenido. Eso es lo que le dice el signo # al ensamblador. De manera
similar, la tercera instrucción coloca la dirección de la primera palabra más allá de la matriz enR3.
Lo que es interesante notar es que el cuerpo del bucle en sí no contiene ninguna dirección
de memoria. Utiliza registrar y registrar el modo indirecto en la cuarta instrucción. Utiliza el modo
de registro e inmediato en la quinta instrucción y el modo de registro dos veces en la sexta
instrucción. losBLT podría usar una dirección de memoria, pero lo más probable es que
especifique la dirección a la que se bifurcará con un desplazamiento de 8 bits en relación con el
BLT instrucción
en sí. Al evitar por completo el uso de direcciones de memoria, hemos
producido un ciclo corto y rápido. Además, este programa es realmente para el Core i7,
excepto que hemos cambiado el nombre de las instrucciones y los registros y cambiado el
374 EL NIVEL DE ARQUITECTURA DEL CONJUNTO DE INSTRUCCIONES CAP. 5
notación para que sea fácil de leer porque la sintaxis estándar en lenguaje ensamblador (MASM)
del Core i7 raya en lo extraño, un remanente de la vida anterior de la máquina como un
8088.
Vale la pena señalar que, en teoría, hay otra forma de realizar este cálculo sin utilizar el
direccionamiento indirecto de registros. El bucle podría haber contenido una instrucción
para agregarA para R1, tal como
AÑADIR R1, A
AÑADIR R1, A + 4
significa que el destino usa el modo de registro con R4 ya que el registro y la fuente utilizan el
modo indexado, con A como el desplazamiento y R2 como el registro. SiA tiene el valor,
digamos, 124300, la instrucción real de la máquina para esto es es probable que se parezca a
la que se muestra en la Fig. 5-19.
MOV R4 R2 124300
La primera vez a través del bucle, R2 es 0 (debido a que se inicializa de esa manera), por lo que
la palabra de memoria direccionada es A0, en la dirección 124300. Esta palabra se carga en R4.
La próxima vez a través del bucle, R2 es 4, por lo que la palabra de memoria direccionada es A1, a
124304 y así sucesivamente.