S05 - myTeachingURJC/Arq-computadores-01 GitHub Wiki
Sesión de Teoría 5: ISA. Repertorios CISC y RISC
- Tiempo: 2h
- Objetivos de la sesión:
- Entender el concepto de ISA
- Conocer los dos enfoques de procesadores: CISC vs RISC
- Introducción al RISC-V
- Conocer los tipos de almacenamiento interno de los operandos
Contenido
- Introducción
- ISA: La interfaz entre el software y el hardware
- Tipos de repertorios: CISC y RISC
- Ejercicios
- Autores
- Licencia
- Enlaces
Introducción
Comenzamos el Tema 2, en el que nos centraremos en entender los repertorios de instrucciones de los procesadores, y todos los aspectos a tener en cuenta en su diseño. Aunque particularizaremos para el RISC-V, vamos a estudiar los repertorios en genérico, para entender todas las ideas que hay detrás, y cómo se clasifican atendiendo a diferntes criterios
ISA: La interfaz entre el software y el hardware
Los procesadores son circuitos digitales que ejecutan instrucciones almacenadas en una memoria. Utilizamos las siglas ISA (Instruction Set Architecture) para referirnos a la arquitectura del conjunto de instrucciones, también llamado repertorio de instrucciones o simplemente arquitectura: qué operaciones realiza el procesador, qué formato tienen las instrucciones, su tamaño... En la ISA se define toda la información que necesita un programador para generar instrucciones que pueda ejecutar el procesador. La ISA de un procesador es la frontera entre el mundo del hardware y del software
Cada procesador tiene su propio repertorio de instrucciones (su propia arquitectura) definido por el fabricante. El procesador sólo ejecutará las instrucciones definidas en ese repertorio. Si queremos realizar alguna operación que no está en el repertorio, tendremos que combinar las instrucciones disponibles para lograr implementar esa operación
Veremos algunos ejemplos de la operación de suma en diferentes procesadores. En cada uno de ellos el formato de la instrucción es diferente, y por tanto el código máquina también lo será
Instrucción de suma en el computador EDSAC
Las instrucciones del EDSAC (1949) tienen un tamaño de 17 bits. Dispone de una instrucción de suma que añade el valor de una posición de memoria al registro acumulador. Este es el formato de la instrucción:
Como instrucción de ejemplo, usamos una que suma el dato que se encuentra almacenado en dirección 36 de la memoria principal. Al ejecutar el procesador esta instrucción, realiza la siguiente operación:
A = A + mem[36]
La instrucción en lenguaje ensamblador del EDSAC es esta:
A36S
Y al traducirse a código máquina se convierte en este número de 17 bits:
11100000001001000
Este formato de la instrucción define que las instrucciones del EDSAC están formadas por 4 campos. Los 5 bits de mayor peso son el código de operación (opcode), que indica la función que hace la instrucción. En este caso la función es una suma. El siguiente campo de un bit está reservado. A continuación hay 10 bits para la dirección del dato y por último un bit (T) que define el tamaño del dato
Instrucción de suma en el computador del Apolo XI
El Apolo XI (1969) fue la primera nave espacial en llevar humanos a la Luna. El computador empleado es el AGC (Apollo Guidance Computer). Las instrucciones son de 15 bits, con este formato:
Sólo consta de dos campos: el código de operación (Opcode) de 3 bits y una dirección de 12 bits. La instrucción que suma al registro acumulador el dato almacenado en la dirección se escribe así en lenguaje ensamblador:
AD 63
Y la operación que realiza es esta:
A = A + mem[63]
La instrucción en código máquina es este número de 15 bits:
011000000111111
[!NOTE] Nota Friki: Todo el código original del Apolo XI está disponible en este repositorio de Github: Apolo-11. Anímate a echar un vistazo 😉️ (Por ejemplo a este fichero DISPLAY_INTERFACE_ROUTINES.agc)
[!NOTE] Margaret Hamilton fue la científica jefe que lideró el desarrollo del software del apollo
Instrucción de suma en el procesador Z80
El procesador Z80 (1976) se hizo muy popular en los 80s por ser utilizado en los primeros ordenadores personales de 8 bits que llegaron a los hogares, como el zx spectrum o el Amstrad CPC. El tamaño de las instrucciones es variable, de 1 a 3 bytes. Este es un ejemplo del formato de la instrucción de suma:
Hay varias instrucciones de suma. En la que se muestra en este ejemplo se hace la operación de sumar el número 20 al registro acumulador A:
A = A + 20
La instrucción en ensamblador es:
ADD A, 20
Y el código máquina es este número de 16 bits:
1100011000010100
que se suele representar en hexadecimal:
C614
Instrucción de suma en el Intel 8086
El procesador 8086 (1978) de intel fue el primero de la arquitectura x86, que se encuentra en la mayoría de ordenadores personales de todo el mundo (PCs). Las instrucciones del 8086 tienen también un tamaño variable, de 1 a 4 bytes. Hay varias instrucciones de suma. Aquí se muestra el formato de la que permite sumar al registro de 8 bits AL el valor 15
La operación que se realiza es:
AL = AL + 15
La instrucción en ensamblador es:
add al, 15
Y el código máquina en binario:
0000010000001111
que normalmente representamos en hexadecimal:
040F
Instrucción de suma en el Risc-V
En esta asignatura profundizaremos en el ISA del RISC-V (2013), que es abierto. Todas tienen la misma longitud: 32 bits. Las instrucciones se dividen en 6 tipos, cada uno con su propio formato. Por ejemplo, la instrucción para realizar una suma de un registro con un dato (addi) es de tipo I, y tiene el siguiente formato
La operación que se realiza en el ejemplo es:
x6 = x5 + 15
La instrucción en ensamblador ya la conocemos por el laboratorio:
addi x6, x5, 15
El código máquina en binario es:
00000000111100101000001100010011
Y normalmente lo representamos en hexadecimal:
00F28313
Tipos de repertorios: CISC y RISC
Las arquitecturas de los procesadores se pueden clasificar atendiendo a diferentes criterios. Uno de ellos es la complejidad, que nos divide las arquitecturas en CISC (Complex Instruction Set Computer) o RISC (Reduced Instruction Set Computer)
Máquinas CISC
Se corresponden con la primera tendencia de construcciones de computadores. La idea central era esta: implementar en el microprocesador instrucciones cada vez más potentes, que nos permitan hacer más operaciones usando pocas instrucciones en ensamblador. Se quiere elevar el nivel del ensamblador, acercándolo a los lenguajes de alto nivel, para que la programación sea más fácil. Esto tenía mucho sentido inicialmente, porque la programación en ensamblador era frecuente, y los compiladores eran caros, tardaban mucho en compilar y los programas ocupaban más memoria
En estos procesadores las instrucciones tienen multitud de maneras de acceder a memoria (modos de direccionamiento) y hay instrucciones muy especializadas. La cantidad de instrucciones es alta. Una consecuencia de todo esto es que la implementación en el hardware es compleja. El hardware se complica mucho
Un ejemplo de arquitectura CISC son los procesadores de Intel
Máquinas RISC
Las máquinas RISC se diseñan haciendo hincapié en la simplifiación del hardware: que el hardware sea lo más sencillo posible, aunque la programación en ensamblador requiera de más instrucciones. Esto se consigue implementando pocas instrucciones y que estas sean muy regulares: todas del mismo tamaño y con pocos formatos. Sólo pueden acceder a memoria dos instrucciones: load y store. El resto de las instrucciones realizan operaciones con la información contenida en los registros. Esto se denomina arquitectura de carga y almacenamiento
Al ser el hardware más sencillo, es más fácil aumentar su rendimiento utilizando el paralelismo y en concreto la segmentación. También se aumenta por la reducción de los accesos a memoria, ya que las operaciones de lectura y escritura de memoria son lentas (cuello de botella)
Por otro lado, al simplificar el hardware, la programación en ensamblador es más complicada: hay que usar más instrucciones. Sin embargo, los RISC están diseñados para que haya que utilizar un compilador que se encargue de los detalles. El objetivo NO es hacer que el ensamblador sea más sencillo, sino programarlos en un lenguaje de alto nivel, y usar compiladores
Tabla resumen de comparación
En esta tabla se resumen las ideas principales que diferencias a los procesadores CISC de los RISC
Criterio | CISC | RISC |
---|---|---|
Tamaño repertorio | Muchas instrucciones | Pocas instrucciones |
Tamaño instrucciones | Variable | Fijo |
Modos direccionamiento | Muchos | Muy pocos |
Programa en ensamblador | Más cortos | Más largos |
Compilador | Más sencillo | Más complejo |
Hardware | Más complejo, lento y caro | Sencillo, rápido y barato |
Optimización | Difícil | Más fácil |
Ejemplo: Suma de dos variables de memoria
Vamos a hacer un ejemplo para captar la esencia de los enfoques CISC y RISC. Queremos sumar dos variables situadas en memoria y dejar el resultado almacenado en una de ellas. Estas dos variables son: var1 y var2. La operación a realizar, descrita en un lenguaje de alto nivel sería así:
var1 = var1 + var2
Utilizaremos dos máquinas ficticias, una CISC y una RISC. Compararemos el resultado atendiendo al número total de accesos a memoria y al número de instrucciones en ensamblador (supondremos que cada instrucción en ensamblador se corresponde con una instrucción en código máquina)
Enfoque CISC
Se quiere que el programa en ensamblador tenga el menor número posible de instrucciones, y que sea, por tanto, lo más cercano a un lenguaje de alto nivel. Por ello, el diseñador del CISC ha implementado una instrucción de suma que puede acceder directamente a memoria: lectura de las dos variables y almacenamiento del resultado en una de ellas. Todo en la misma instrucción
El programa en ensamblador tendría una única instrucción. Var1 y var2 son las direcciones de las variables en memoria (etiquetas)
Add var1, var2 #-- var1 = var1 + var2
Una sola instrucción, pero lenta
- Número de accesos a memoria: 4 (uno para leer la instrucción, uno para leer var1, uno para leer var2 y uno para guardar el resultado)
- Número de instrucciones: 1
Enfoque RISC
El enfoque en el RISC es simplificar el hardware, aunque la programación en ensamblador requiera de más instrucciones. Sólo hay dos instrucciones para acceder a memoria: load y store. La instrucción de suma sólo opera con registros internos. Por ello, para realizar la suma de las dos variables situadas en memoria hay que cargar las variables en registros internos (con load), realizar la suma depositando el resultado en un registro (add) y finalmente almacenar el resultado en memoria (store). Esta es la secuencia de instrucciones:
load x1, var1 #-- Leer la variable var1 y almacenarla en el registro x1
load x2, var2 #-- Leer la variable var2 y almacenarla en el registro x2
add x1, x2 #-- Realizar la operacion: x1 = x1 + x2
store x1, var1 #-- Almacenar el resultado en memoria
Más instrucciones, pero más rápidas
En total hay 7 accesos a memoria: 4 para la lectura de cada una de las instrucciones, para que el procesador las ejecute. Dos lecturas de los loads y una escritura de store
- Número de accesos a memoria: 7
- Número de instrucciones: 4
Comparación
Para realizar una comparación más minuciosa necesitaríamos conocer más detalles de ambos procesadores, pero grosso modo tendríamos lo siguiente
CISC | RISC | |
---|---|---|
Instrucciones | 1 | 4 |
Accesos a memoria | 4 | 7 |
Viendo esta tabla, el CISC es mejor en todo. Tiene sólo 4 accesos a memoria y una única instrucción, mientras que el RISC requiere de 4 instrucciones y realiza un total de 7 accesos. La intuición nos dice que los CISC son mejores. Y esa fue la razón por la que se empezaron a hacer así los procesadores
Sin embargo, los RISC tienen un rendimiento mejor, aunque son menos intuitivos. La razón está en que los procesadores ejecutan millones de instrucciones y es ahí, cuando hay muchas instrucciones, cuando se puede apreciar el aumento del rendimiento
Ejemplo: Suma de 3 variables en memoria
Repetiremos la misma comparación, pero sumando 3 variables de memoria. La nueva operación que se quiere hacer es:
var1 = var1 + var2 + var3
Intenta resolverlo por tu cuenta primero, antes de continuar. Utilizaremos las mismas máquinas ficticias anteriores, con las mismas instrucciones de suma
Enfoque CISC
El programa en ensamblador sería este:
add var1, var2 #-- var1 = var1 + var2
add var1, var3 #-- var1 = var1 + var3
El programa tiene 2 instrucciones. El número de accesos a memoria es de 2 para la lectura de las dos instrucciones, y cada instrucción hace 3 accesos a memoria. En total hay: 2 + 3*2 = 8 accesos
CISC | Programa 1 | Programa 2 |
---|---|---|
Instrucciones | 1 | 2 |
Accesos a memoria | 4 | 8 |
Enfoque RISC
En el procesador RISC este podría ser un posible programa
load x1, var1
load x2, var2
load x3, var3
add x1, x2
add x1, x3
store x1, var1
Tiene 6 instrucciones y hay por tanto 10 accesos a memorias. Seis de ellos son para la lectura de las instrucciones, 3 para la lectura de las 3 variables y 1 para la escritura del resultado
RISC | Programa 1 | Programa 2 |
---|---|---|
Instrucciones | 4 | 6 |
Accesos a memoria | 7 | 10 |
Comparación
Esta tabla resume los datos de ambos procesadores, cuando se usa el programa 2
CISC | RISC | |
---|---|---|
Instrucciones | 2 | 6 |
Accesos a memoria | 8 | 10 |
El CISC sigue siendo mejor: Tiene 8 accesos a memoria frente a los 10 del RISC, pero la diferencia se ha reducido...
Ejemplo: Suma de 5 variables en memoria
Repetiremos la misma comparación, pero sumando 5 variables de memoria. La nueva operación que se quiere hacer es:
var1 = var1 + var2 + var3 + var4 + var5
Intenta resolverlo por tu cuenta primero, antes de continuar. Utilizaremos las mismas máquinas ficticias anteriores, con las mismas instrucciones de suma
Enfoque CISC
El programa en ensamblador sería este:
add var1, var2
add var1, var3
add var1, var4
add var1, var5
El programa tiene 4 instrucciones. El número de accesos a memoria es de 4 para la lectura de las cuatro instrucciones, y cada instrucción hace 3 accesos a memoria. En total hay: 4 + 4*3 = 16 accesos
CISC | Programa 1 | Programa 2 | Programa 3 |
---|---|---|---|
Instrucciones | 1 | 2 | 4 |
Accesos a memoria | 4 | 8 | 16 |
Enfoque RISC
En el procesador RISC este podría ser un posible programa
load x1, var1
load x2, var2
load x3, var3
load x4, var4
load x5, var5
add x1, x2
add x1, x3
add x1, x4
add x1, x5
store x1, var1
Tiene 10 instrucciones y hay por tanto 16 accesos a memorias. Diez de ellos son para la lectura de las instrucciones, 5 para la lectura de las 5 variables y 1 para la escritura del resultado
RISC | Programa 1 | Programa 2 | Programa 3 |
---|---|---|---|
Instrucciones | 4 | 6 | 10 |
Accesos a memoria | 7 | 10 | 16 |
Comparación
Esta tabla resume los datos de ambos procesadores, cuando se usa el programa 3
CISC | RISC | |
---|---|---|
Instrucciones | 4 | 10 |
Accesos a memoria | 16 | 16 |
Ahora el número de accesos a memoria es el mismo en ambos procesadores. Pero ya se ve la tendencia: cuantas más variables se usen mejor será el RISC. Esto es debido a que en este CISC hay accesos a memoria innecesarios. Se utilizan para lograr que la instrucción de suma sea más potente y más parecida a los lenguajes de alto nivel, pero hace que se pierda rendimiento
Sin embargo, en el RISC, aunque hay más instruccciones, el uso de los accesos a memoria es más eficiente
Por supuesto hay muchísimos más detalles involucrados. Esto es simplemente un ejemplo muy vago para tener una intuición inicial de las diferencias entre CISC y RISC, y cómo el rendimiento de los RISC tiende a ser mejor en media que el de los CISC
Lecturas del libro de referencia
Libro de referencia: "Computer Organization and Design. Hardware/Software interface. Risc-V"
- Apartado 2.1: Introduction (Pag 62-63)
- Apartado 2.2: Operations of the Computer Hardware (Pag 63-66)
Otras lecturas recomendadas
Ejercicios
Para concretar las ideas aprendidas en esta sesión es fundamental que hagas los ejercicios. Sólo practicando conseguirás entender todas las ideas importantes que se quieren transmitir
Ejercicio 1
El formato de las instrucción del computador EDSAC (1949) es el siguiente:
a) ¿Cuantas instrucciones como máximo se pueden tener en esta arquitectura?
b) ¿Cual es el tamaño máximo de la memoria del EDSAC (en palabras)? Supón que todos los datos son palabras de 17 bits
c) En la posición de memoria 921 se encuentra la variable var1, que tiene el valor 30 (de 17 bits). El código de operación de la instrucción de suma es el 11100 en binario, que suma al regisgtro acumulador el contenido de la variable de memoria indicada: A = A + variable, donde A es el acumulador del EDSAC. Escribe la instrucción en código máquina que hace la operación: A = A + var1
Ejercicio 2
El formato de las instrucciones del Computador de guiado del Apolo XI (1969), la nave que nos llevó a la Luna, es el siguiente:
En cada posición de memoria se almacena un dato de 16 bits (medias palabras). Así, en la dirección 0 está el primer dato de 16 bits, en la direción 1 el segundo, etc... La unidad mínima de intercambio con la memoria son 16 bits
a) ¿Cuantas instrucciones como máximo se pueden tener en esta arquitectura?
b) ¿Cual es el tamaño máximo de la memoria del AGC (en unidades de 16 bits)?
c) En la memoria se encuentran dos variables de 16 bits referenciadas por las etiquetas var1 y var2. La instrucción en ensamblador que realiza la operación A = A + var se escribe como: AD var, donde var es la etiqueta de referencia de la variable y A es el registro acumulador. Escribe las instrucciones en ensamblador del AGCC para calcular A = var1 + var2. Supón que inicialmente el acumulador vale 0
d) Si las etiquetas var1
y var2
se corresponden con las direcciones 0x080 y 0x1F0, y el código de operación de la instruccion AD es 011 en binario, escribe en código máquina (en hexadecimal) del programa del apartado c
Ejercicio 3
Sabiendo que la instrucción addi
en el RISC-V tiene el siguiente formato:
a) Obtén el código máquina (en hexadecimal) del siguiente programa:
addi x0, x0, 0
addi x31, x15, 0x0F
b) Desensambla este programa en código máquina y obtén su equivalente en lenguaje ensamblador. ¿Qué hace este programa?
0x00100193
0x00218193
Notas para el profesor
- Título informal de la clase: "En el formato hallarás la verdad..."
- Ej básico. Instrucción alto nivel: a=15
- Al compilar se obtiene li t0, 15 (ensamblador)
- Esto, a su vez, se convierte en instrucciones básicas: addi x5,x0,15
- Y finalmente el código máquina: 00F00293
- Lo ponemos en binario (la realidad: 0000_0000_1111_0000_0000_0010_1001_0011)
- ¿Qué significa cada bit? --> Eso me lo dice la ISA del procesador
Autores
- Katia Leal Algara
- Juan González-Gómez (Obijuan)
Licencia
Créditos
- Foto de Margaret Hamilton: De Adam Cuerden - Esta es una imagen retocada, lo que significa que ha sido alterada digitalmente de su versión original. Modificaciones: dust and scratches removed; curves tweaked to bring out shadows, approximately 3 pixels cropped from bottom in order to remove a border. See upload history of the PNG for version without colour tweaks. La original se puede ver aquí: Margaret Hamilton.gif., Dominio público, https://commons.wikimedia.org/w/index.php?curid=59655977
- Imagen del procesaor 80486. By Henry Mühlpfordt - Own work, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=1849256
- Imagen del procesador ARM. By Open Grid Scheduler / Grid Engine - Own work, CC0, https://commons.wikimedia.org/w/index.php?curid=67895534