Un microprocesador moderno es una entidad tremendamente complicada, y han sido necesarias décadas de trabajo por parte de miles de personas para llegar hasta donde está ahora. Es casi imposible cubrir todas las bases aquí, pero haré un intento. Tened preparado un cubo de palomitas, porque esto va a ser largo.
Cualquier sistema moderno funciona sobre la base de buenas abstracciones, es decir, módulos más simples sobre los que se construyen cosas más complejas. En mi opinión, el procesador moderno se puede descomponer en las siguientes capas muy amplias:
- Dispositivos (transistores)
- Circuitos
- Puertas lógicas
- Bloques lógicos simples
- Procesador
- Software
- Para empezar, partamos de un «término medio», que no es ni demasiado complicado de entender ni demasiado alejado de un procesador real: la puerta lógica. Una puerta lógica tomará un cierto número de entradas, todas ellas 0 o 1, y dará como resultado un bit que es de nuevo 0 o 1 según alguna regla. Por ejemplo, una puerta AND dará como resultado un 1 sólo si todas sus entradas son 1.
- Para empezar, partamos de un «término medio», que no es ni demasiado complicado de entender ni demasiado alejado de un procesador real: la puerta lógica. Una puerta lógica tomará un cierto número de entradas, todas ellas 0 o 1, y dará como resultado un bit que es de nuevo 0 o 1 según alguna regla. Por ejemplo, una puerta AND dará como resultado un 1 sólo si todas sus entradas son 1.
Puede que ahora empieces a preguntarme «¿Pero qué quieres decir con 0 y 1? Qué significa eso en términos de electricidad?». La respuesta es fantásticamente complicada. Puede significar un nivel de voltaje (0 es 0V, 1 es 1V), un pulso eléctrico (0 es ningún pulso, 1 es un pulso de 1V durante 1 nanosegundo, una milmillonésima de segundo), un fotón (0 es ningún fotón, 1 es 1000 fotones), y así sucesivamente, todo dependiendo de cómo se haya diseñado el circuito. Este es el poder de las abstracciones. No necesitas saber qué significan los 0 y los 1 para diseñar cosas más arriba (pero tomarás malas decisiones más arriba si no lo sabes, así que quizá la abstracción no sea perfecta).
Ahora pensemos cómo podemos hacer algo con estas puertas tan simples. Pensemos que estás a punto de montar tu propia empresa de procesadores y quieres hacer un bloque sencillo que sume dos números usando sólo estas puertas.
«Pero espera», dices, «¿qué es un número en términos de 0 y 1? Yo sólo conozco números como el 57 y el 42, que están formados por dígitos del 0 al 9, no sólo por el 0 y el 1». Cierto, pero mira, 57 es sólo una «representación» del número que hay debajo, que en realidad es 5*10+7. También puedes representar 57 como 1*2^5+1*2^4+1*2^3+0*2^2+0*2^1+1*2^0. Ahí lo tienes, 57 es lo mismo que 111001 en este nuevo sistema. Puedes convencerte de que cualquier número se puede representar de esta forma.
Ahora, pensemos cómo vamos a construir un sumador. En primer lugar, vamos a intentar construir un «medio sumador», uno que tome dos bits y los sume para dar salida a dos bits. Así, si los dos bits son 0, saldrá 00, si sólo uno de ellos es 1, saldrá 01, y si ambos son 1 saldrá 10. Pensemos en un bit a la vez y tomemos el primer bit al principio. Después de un tiempo, nos damos cuenta de que ese bit es 1 sólo si los dos bits de entrada son 1. Así que podemos obtener por una puerta AND. Impresionante!». Ahora tenemos la mitad de nuestro trabajo hecho. Sólo queda un bit.
Ahora nos sentamos a pensar de nuevo. Hmm, este otro bit parece más difícil. Es casi como una puerta OR, pero no da la salida 1 si ambas entradas son 1. Vale, no le demos más vueltas y decidamos llamarla un nuevo tipo de compuerta, una compuerta OR exclusiva.
«No’te preocupes», digo, «contrataremos a unos ingenieros de circuitos superimpresionantes que pueden diseñar una compuerta así mientras duermen». Ahora dibujamos una imagen de nuestro asombroso nuevo circuito: un medio sumador.
Pero, ahora dices, «sólo podemos sumar números de 1 bit. Nuestra empresa rival puede sumar números de más de mil millones. ¿Cómo lo hacemos?». La respuesta es, sorpresa, sorpresa, abstracciones. Verás, nuestro diseño actual sólo puede sumar dos números de un bit, y la salida es una suma y un «carry», que ahora hay que sumar al siguiente bit superior. Esto necesita la adición de tres bits, que nuestro pequeño tipo no puede hacer.
Así que después de otro día completo de romper nuestras cabezas sobre esto, pensamos que este será un buen circuito para hacer esto y lo llamamos un sumador «completo».
Ahora tenemos todo el poder de adición del mundo en nuestras manos. Verás, ahora podemos encadenar 32 de estos pequeños tipos como el siguiente y tenemos en nuestras manos un monstruo que puede sumar números de más de mil millones, en un abrir y cerrar de ojos.
Y aquí está la maravillosa noticia: puedes seguir haciendo puertas cada vez mejores, y tu circuito será cada vez mejor. Ese es el poder de la abstracción.
Por supuesto, resulta que nuestra forma de añadir cosas no es realmente tan buena. Se puede hacer mejor… mucho mejor. Pero, gracias a nuestra amiga la abstracción, eso se puede hacer independientemente de las puertas. Si tu circuito más nuevo es 2 veces mejor que el antiguo, Y tienes 2 puertas más rápidas, ¡tienes un circuito 4 veces mejor! Ese es uno de los principales factores que contribuyen a que hayamos mejorado miles de veces en unas pocas décadas. Construimos puertas más pequeñas, más rápidas y que consumen menos energía. Y hemos descubierto formas cada vez mejores de hacer el mismo cálculo. Y luego las unimos. Funcionó como magia!
Ahora trabajamos durante un año en nuestro garaje y construimos circuitos que pueden multiplicar, sumar, restar, dividir, comparar y hacer todo tipo de aritmética, todo ello en 1 nanosegundo. Incluso fabricamos un diminuto circuito que puede «almacenar» un valor, es decir, su salida dependerá del valor que se le haya escrito antes (alguien sugiere que lo llamemos flip-flop. Parece un nombre gracioso, nos lo quedamos ^_^ ). Pero, como ves, una cosa que tienen en común todos nuestros circuitos es que se limitan a tomar entradas y hacer la misma operación sobre ellas para dar la salida. ¿Qué pasa si a veces quiero hacer una multiplicación, y a veces una suma?
¡Ahora, tenemos una idea! Decimos, no consideremos los bits como simples números. Intentemos representar las propias «acciones» en bits. Digamos que 0 significa «sumar», 1 significa «multiplicar». Ahora, construyamos un pequeño circuito que vea un bit como una «orden», y que seleccione entre dos entradas, I0 e I1, y que dé como salida I0 si la orden es 0, e I1 si es 1. Esto es un multiplexor.
«¡¡Wow!», dices, «¡ahora sólo necesitamos un multiplexor para elegir entre las salidas de un sumador y un multiplicador, y ya tenemos nuestra solución! De hecho, por qué no tener muchos de estos multiplexores para elegir entre tantas salidas, y tenemos una máquina increíble. Puede hacer muchas operaciones aritméticas dependiendo de lo que le des como «orden»».
¡Ahora tenemos otra idea INCREÍBLE! Os acordáis de esos divertidos flip-flops que construimos antes? Pensamos, ¿y si conectamos un multiplexor 1024-1 a la salida de 1024 flip-flops? ¡¡Ahora tenemos lo que se llama una memoria de 1 Kilobit!! Podemos darle una «dirección», y nos devolverá un bit, que era el bit almacenado en esa posición numerada. ¿No es genial? Además, estos bits pueden ser «números» (datos) o «comandos» (instrucciones).
Sentémonos y pensemos en lo que tenemos hasta ahora: tenemos muchas funciones aritméticas, tenemos un multiplexor genial que selecciona qué salida elegir, y tenemos una memoria, que puede darnos cualquier bit si le damos una «dirección».
Aquí está lo sorprendente ahora. Tenemos TODO lo que necesitamos para construir un procesador. Veamos cómo:
- En primer lugar, tenemos una matriz de memoria MEM que contiene todos los «comandos» (instrucciones) y «números» (datos).
- En segundo lugar, tenemos un número llamado «contador de programa», uno que utilizamos para seleccionar qué instrucción ejecutar desde la MEM. Normalmente sólo se incrementa en 1 en cada paso.
- Tercero, tenemos un bloque aritmético con multiplexores.
- Cuarto, generamos las dos entradas a nuestro bloque aritmético desde la MEM.
- Por último, hay dos tipos de instrucciones: instrucciones de datos e instrucciones de control. Cada instrucción de datos contiene cuatro cosas: dos direcciones que especifican qué dos números hay que coger de la MEM, una orden que dice qué operación hay que realizar y otra ubicación que dice dónde hay que devolver el resultado. Las instrucciones de control simplemente devuelven otra dirección al «contador de programa».
Esta cosa que acabas de construir se llama máquina de Von-Neumann (sí, los locos como él descubrieron todo esto en 1945, no sé cómo). Hoy en día la gente está empezando a cuestionar si esta es la mejor manera de construir cosas, pero esta es la forma estándar en que se construye cualquier procesador hoy en día.
Bueno, cuando dije antes que esta es la forma en que se construyen todos los procesadores, quise decir «teóricamente», y por «teóricamente», quiero decir «consideremos que una vaca es una esfera» teóricamente. Verás, la CPU de tu competidor’ puede correr en círculos alrededor de tu CPU básica Von-Neumann. Usted sólo tiene 1000 Kilobits de memoria, su competidor puede manejar hasta miles de millones (Gb) o trillones (Tb) de bits de memoria. Pero ahora dices, no hay manera de que esos tipos puedan crear un multiplexor de mil millones a uno y tener sus datos en 1 nanosegundo. Es cierto. Su salsa secreta es algo llamado localidad.
Lo que esto significa es que su programa normalmente sólo utiliza unas pocas ubicaciones de datos y memoria de instrucciones a la vez. Así que lo que haces es tener una gran memoria que consiste en GB’s de datos, entonces traes una pequeña parte de ella – la parte que se está utilizando actualmente, a una matriz mucho más pequeña (tal vez 1 MB) llamada la caché. Por supuesto, ahora puedes tener una caché aún más pequeña debajo de esta caché, y así sucesivamente, hasta que puedas llegar a algo que puedas leer o escribir en aproximadamente la misma cantidad de tiempo que puedes hacer un cálculo aritmético.
Otra idea poderosa que puedes hacer se llama procesamiento fuera de orden. El concepto detrás de esto se puede ilustrar con el siguiente programa que calcula X = (A+B)*(C+D)
- Suma A y B y guárdelo en U
- Suma C y D y guárdelo en V
- Multiplique U y V y guárdelo en X
En la forma normal, simplemente lo hará secuencialmente, yendo una instrucción tras otra y terminando la ejecución en 3 pasos. Pero, si tienes dos sumadores en tu sistema, puedes ejecutar las instrucciones 1 y 2 en paralelo, y así terminar en 2 pasos. Así ejecutas lo máximo posible en cada paso y terminas tu ejecución más rápido.
Ahora, piensa en el momento en que todo lo que conocías era una simple puerta AND. Esto que has construido parece muy ajeno a eso. Pero en realidad no es más que capas sobre capas de bloques, y la reutilización de un bloque más simple para construir un bloque más complejo. Esta es la idea clave aquí. Una CPU se construye únicamente uniendo partes, que se construye uniendo partes más pequeñas. Al final, sin embargo, si te quedas mirando la cosa, se ve así:
- Adder (electrónica)
- Arquitectura Von Neumann
- Caché de la CPU
- Ejecución fuera de orden
- ARK |Procesador Intel® Core™ i7-3960X Extreme Edition (15M de caché, hasta 3,90 GHz)
- Edición: Hay muchos detalles que me he dejado en la respuesta original. Esta respuesta será equivalente a responder a «¿Cómo funciona un coche de F1?» con «Tiene ruedas, y una dirección que guía las ruedas, y un motor para hacer funcionar las ruedas». Realmente, el diseño y la construcción de una CPU es uno de los milagros de la tecnología moderna que implica un enorme número de disciplinas de ingeniería (incluyendo, por ejemplo, la física cuántica, la metalurgia, la fotónica, etc.). Intentaré abordar algunas cuestiones más a continuación.
Fabricación
Una de las hazañas más asombrosas de la tecnología ha sido la capacidad de crear y conectar miles de millones de diminutos transistores, cada uno de ellos de menos de 100 nm (sí, eso es nano, lo que significa una milmillonésima parte de un metro) de ancho, en un patrón preciso definido por los diseñadores de circuitos y los arquitectos de la CPU, y aún así hacerla imposiblemente barata. Está claro que crear y conectar un número tan grande de transistores uno a uno es imposible a mano o incluso por cualquier forma de mecánica.
El método para fabricar un chip se llama fotolitografía, y es la razón detrás del precio extremadamente bajo de los procesadores en comparación con su complejidad. La idea es similar a cómo se «revelaba» una foto analógica (si es que alguien se acuerda de aquellas). Primero describiré cómo crear un patrón de óxido de silicio sobre silicio (esto se utiliza en las puertas de los transistores). Primero se deposita una capa de óxido de silicio sobre el silicio. A continuación, se aplica una capa de material fotorresistente encima. Este material es sensible a la luz, pero es resistente al «grabado». La inversa del patrón a crear también se realiza en forma de «máscara», a través de la cual se proyecta luz UV sobre la fotorresistencia. Sin embargo, esto plantea la cuestión de cómo se creó la máscara en primer lugar.
Aquí está la magia de la fotolitografía: la máscara es en realidad mucho más grande que el tamaño del patrón a grabar. La luz que brilla a través de la máscara es simplemente enfocada por una lente para que tenga el tamaño adecuado cuando caiga sobre el silicio. Una vez que la luz cambia la fotorresistencia, ésta es grabada por una ráfaga de plasma, dejando sólo el patrón deseado en el óxido de silicio.
Para crear una capa de metal, por otro lado, se sigue un procedimiento similar. Sin embargo, ahora se graba el inverso del patrón sobre SiO2, y luego se deposita el metal sobre los «surcos» creados por el SiO2.
La razón por la que esto es tan económico es porque una vez que se tiene la «máscara», se puede crear un número muy grande de chips a partir de ella. Así, aunque una máscara es bastante cara (unos cuantos millones de dólares), su coste se divide en muchos chips, lo que hace que cada chip sea muy barato (no es un juego de palabras).
Tipos de memorias
Como he dicho antes, se puede construir una memoria conectando flip-flops a multiplexores. Sin embargo, esa no es una forma especialmente eficiente de hacer las cosas. Un flip-flop consume entre 15 y 20 transistores. Sin embargo, en la práctica hay dos tipos de estructuras de memoria: la RAM estática (o SRAM, por sus siglas en inglés), que utiliza 6 transistores por bit, y la RAM dinámica (o DRAM, por sus siglas en inglés), que sólo utiliza un transistor y un condensador por bit. Una RAM estática es esencialmente dos puertas NOT conectadas en un bucle como este.
Claramente, hay dos estados posibles para A y B, o bien A = 1, B = 0, o bien A = 0, B = 1. La idea es aplicar algún voltaje externo para empujar el bucle a un estado u otro, que es entonces el bit «almacenado», y luego simplemente leer el voltaje en A o B para «leer» el bit.
Por otro lado, la RAM dinámica o DRAM, es aún más simplista y es aproximadamente así.
En este diseño, el transistor simplemente actúa como un interruptor para almacenar la carga en el condensador, en cuyo caso se lee como un 1, de lo contrario un 0. Sin embargo, la carga en el condensador se escapa del transistor cada cierto tiempo. Así que necesita ser leída y reescrita a intervalos fijos, y por eso se llama RAM dinámica.
Las memorias caché de un chip suelen ser SRAM, ya que son más rápidas. Sin embargo, las memorias principales de un ordenador suelen ser DRAM, ya que tienen un tamaño mucho menor, y así puede caber una mayor cantidad de memoria en un solo chip.
- Fotolitografía
- Memoria estática de acceso aleatorio
- Memoria dinámica de acceso aleatorio
- P.S. He iniciado un blog sobre ideas básicas de la arquitectura de la CPU en CPU Architecture. En caso de que esta respuesta te interese, puede que quieras echarle un vistazo.