Professional Documents
Culture Documents
o CISC?
Introducción
¿Para qué queremos realmente una computadora? ¿Qué es lo que realmente
importa en su ciclo de vida?.
La respuesta a la primera pregunta es evidente. Un ordenador está diseñado
para poder ejecutar programas, sino ¿para qué lo querríamos?. Evidentemente, existen
sistemas cuyo diseño está orientado a tareas específicas y otros que no. Pero todos
ellos deben dar el mejor soporte posible al software que procesarán.
La respuesta a la segunda pregunta depende del momento histórico en que nos
situemos. En los últimos años el coste del hardware se ha abaratado, mientras que el
del software se ha visto incrementado enormemente. Así pues, lo que realmente
importa en el ciclo de vida de una máquina es el software.
Es muy importante tener en cuenta que la demanda de software provoca la
aparición en el mercado de productos con una calidad en ocasiones más que dudosa
en cuanto a rendimiento se refiere.
Estas respuestas y consideraciones, unidas a que el diseño de aplicaciones está
inherentemente unido a la aparición de errores difíciles de detectar, han hecho que la
industria haya desarrollado lenguajes de alto nivel.
Sin embargo, la utilización de lenguajes de alto nivel provoca la aparición de
un gran problema. Existe un ‘salto semántico’ entre las operaciones propias de la
máquina y las de los lenguajes de alto nivel. Este salto semántico provoca una
ineficiencia en la ejecución y un tamaño excesivo en los programas, así como la
complejidad del diseño de compiladores. De esta manera, la respuesta a la pregunta
de cómo mejorar el software deriva inexorablemente en buscar la forma de poder
optimizar el uso de los lenguajes de alto nivel.
Para ello, lo que realmente importa no es la tecnología de semiconductores,
sino la arquitectura del microprocesador. La tecnología de los circuítos es un
problema más que solucionado. Sin embargo, conseguir una arquitectura óptima no
tiene fácil respuesta.
La arquitectura de un computador viene definida por el repertorio de
instrucciones, el tipo de direccionamientos y el tipo de operandos que es capaz de
ofrecer al compilador. Existen dos alternativas de arquitecturas contrapuestas para
solucionar los problemas derivados del salto semántico.
Por un lado hay toda una familia de microprocesadores conocida como CISC
(complex instruction set computer). Mientras que por otra parte se ha desarrollado
otra clase de microprocesadores conocidos como RISC (reduced instruction
setcomputer). Estas dos formas de arquitectura no sólo se diferencian en la
complejidad del conjunto de instrucciones, sino que poseen filosofías distintas para
solucionar otros problemas referentes al diseño de un computador. Sin embargo,
ambas poseen juegos de instrucciones basadas en registros. Es decir, basan el
almacenamiento interno de los operandos en los registros de la CPU (otras
alternativas consisten en utilizar una pila o un acumulador).
Veamos, pues, las filosofías de estas dos familias de microprocesadores para
solucionar los problemas derivados del salto semántico ¿Cómo hay que actuar para
conseguir programas cortos, rápidos y ayudar a los compiladores para que generen un
código óptimo?
Filosofía CISC
Históricamente la memoria a tenido un elevado coste y en consecuencia se
han ido buscando arquitecturas que maximizasen el uso de la misma. Las
arquitecturas de computadores que aparecieron en primer lugar fueron CISC. Por
tanto, no es de extrañar que una de las mayores preocupaciones de esta familia haya
sido siempre el ahorro de la memoria.
Como hemos comentado, han hecho su aparición los lenguajes de alto nivel,
imponiéndose en la programación al lenguaje más básico del computador, el
assember.
Así pues, CISC es una arquitectura que persigue la programación fácil y al
mismo tiempo un uso eficiente de la memoria.
¿Qué tipo de operandos son los más utilizados? ¿Cómo acceder a ellos?
Los estudios de Patterson revelan que la mayoría de las referencias que se dan
en un programa se hacen a variables escalares simples. Además, estas variables están
muy bien localizadas por ser la mayoría de ellas locales al procedimiento que las
referencia. No sólo son locales las variables escalares, sino que las referencias a
estructuras más complejas como arrays y matrices precisan de una referencia previa
a un índice o puntero que también suele ser local al procedimiento.
Otro aspecto relevante que se puede extraer de los estudios de Patterson es
que cada instrucción referencia en promedio 0,5 operandos de memoria y 1,4
registros. Esto nos hace pensar que no es tan necesario disponer de modos de
direccionamiento complejos que permitan operar directamente con posiciones de
memoria, ya que la proporción de referencias a registros es mucho más elevada.
Así pues, es muy importante poder disponer de un acceso y almacenamiento
rápido de los operandos, sobre todo para aquellos que son locales dentro de un
procedimiento. Como veremos más adelante, esta es una de las razones básicas que
motivan que las arquitecturas RISC también sean conocidas como arquitecturas
load/store.
Para poder apreciar los efectos que las optimizaciones de los compiladores
tienen sobre el rendimiento de los programas, ilustramos el siguiente cuadro.
Evidentemente, los registros del procesador son los que brindan los tiempos
de acceso más cortos debido tanto a la tecnología de acceso como al número de bits
necesarios para direccionarlos. En una arquitectura de tipo load/store Lo ideal sería
poder tener todos los operandos que se necesiten en la ejecución de un programa
ubicados en registros. Pero entonces el coste del hardware se vería incrementado
notablemente.
Se necesita una estrategia para ubicar aquellos operandos a los que se accede
con más frecuencia y reducir el tráfico registro-memoria generado en las operaciones
de tipo load y store. Una estrategia consistiría en confiar al compilador la
maximización del uso de los registros. La otra estrategia, más acorde con la filosofía
RISC, es disponer de una cantidad elevada de registros para poder mantener ubicadas
las variables durante un período de tiempo mayor.
Siguiendo la segunda estrategia, cabe considerar que con cada llamada de
procedimiento el aspecto local de las variables cambia y se debe realizar un paso de
parámetros. Si todos los registros fuesen visibles para cada procedimiento, se
deberían salvar en memoria muchos de ellos con cada llamada. Por esta razón se
utiliza un conjunto de numerosos registros de propósito general, al que se llama
fichero de registros.
Se define una ventana o marco de visibilidad para cada procedimiento. Es
decir, cada procedimiento posee asociado un marco de registros del procesador para
almacenar sus operandos. En cada momento sólo es visible una ventana de registros
que se direccionan como si sólo existiesen ellos. Los marcos se dividen en tres
secciones que suelen ser de la misma longitud:
Se debe tener en cuenta que los bits necesarios para codificar una instrucción
típica de CISC es mayor que para una RISC. Esto es debido, en primer lugar, a que
un mayor número de instrucciones en el repertorio implica un mayor número de bits
para codificar el código de operación. En segundo lugar, es debido a que el uso de
modos de direccionamientos a registros, utilizados mayoritariamente por un RISC,
precisan de menor número de bits para realizar la referencia que los
direccionamientos a memoria que suele utilizar CISC.
El hecho de que instrucciones complejas aceleren la ejecución de funciones
complicadas no está tampoco tan claro. Hemos visto que, aunque se disponga en el
repertorio de instrucciones muy complejas, se acaban utilizando las más sencillas.
Pero poder disponer de tantas instrucciones hace que la unidad de control se
complique y que se necesite utilizar microcódigo para ejecutarlas. Por muy rápida que
sea la captación de las microinstrucciones desde una ROM con respecto a la
captación de instrucciones simples desde memoria principal, la fase de decodificación
consume un tiempo mayor en las arquitecturas CISC.
Hemos visto que las arquitecturas RISC poseen un gran número de registros
de uso general o fichero de registros, mientras que las arquitecturas CISC poseen casi
exclusivamente registros de uso dedicado y utilizan una caché para almacenar los
datos más utilizados. ¿Qué opción es mejor?
Conclusión
Las opciones RISC y CISC se deben entender como arquitecturas
complementarias y no como rivales. Los diseños RISC pueden sacar provecho de
características CISC, como por ejemplo añadir una caché dedicada exclusivamente a
instrucciones. Por su parte, los CISC pueden adquirir características RISC, como
implementar sólo aquellas instrucciones que son usadas con mayor frecuencia y dejar
de lado otras tan complejas como inútiles. Ejemplos de arquitectura ‘híbridas’ son el
PowerPC (basado en RISC, pero con características CISC) y el Pentium (basado
mayoritariamente en CISC).
Las arquitecturas RISC son más recomendables para aquellas aplicaciones que
necesiten una importante capacidad de cálculo, mientras que las CISC ofrecen
grandes posibilidades dentro del sector industrial. Sin embargo, las arquitecturas
RISC están desplazando a las CISC en la mayoría de las áreas de aplicación. Esto es
debido a que el deseo por mantener la compatibilidad entre distintas versiones le
privan de una mayor capacidad de innovación. De hecho, la aparición de
arquitecturas CISC que incorporan características RISC está motivada por el deseo de
ofrecer nuevas soluciones.
2.- ¿Qué arquitectura ayuda más a los lenguajes de alto nivel RISC o CISC, y
como pretenden hacerlo principalmente?
3.- ¿En qué se basa y qué ventajas tiene una arquitectura load/store?
Problemas propuestos
1.- ¿Qué tipo de instrucciones son las más usadas, y conviene que el
compilador optimice?
2.- ¿Cómo hay que gestionar los diferentes tipos de operandos para mejorar el
rendimiento del computador?