Anatomía de la CPU

La CPU a menudo se denomina cerebro de una computadora y, al igual que el cerebro humano, consta de varias partes que trabajan juntas para procesar la información. Hay partes que reciben información, partes que almacenan información, partes que procesan información, partes que ayudan a generar información y más. En el explicativo de hoy, repasaremos los elementos clave que componen una CPU y cómo funcionan todos juntos para alimentar su computadora.

Debe saber que este artículo es parte de nuestra serie Anatomy que analiza toda la tecnología detrás de los componentes de PC. También tenemos una serie dedicada al diseño de CPU que profundiza en el proceso de diseño de CPU y cómo funcionan las cosas internamente. Es una lectura técnica muy recomendable. Este artículo de anatomía revisará algunos de los fundamentos de la serie CPU, pero a un nivel superior y con contenido adicional.

En comparación con los artículos anteriores de nuestra serie Anatomía, este será inevitablemente más abstracto. Cuando mira dentro de algo como una fuente de alimentación, puede ver claramente los condensadores, transformadores y otros componentes. Eso simplemente no es posible con una CPU moderna, ya que todo es tan pequeño y porque Intel y AMD no divulgan públicamente sus diseños. La mayoría de los diseños de CPU son propietarios, por lo que los temas que se tratan en este artículo representan las características generales que tienen todas las CPU.
Serie Anatomía del hardware informático de TechSpot

Es posible que tenga una PC de escritorio en el trabajo, la escuela o el hogar. Puede utilizar uno para elaborar declaraciones de impuestos o jugar a los juegos más recientes; incluso podría estar interesado en construir y ajustar computadoras. Pero, ¿qué tan bien conoce los componentes que componen una PC?

Así que vamos a sumergirnos. Todo sistema digital necesita algún tipo de Unidad Central de Procesamiento. Básicamente, un programador escribe código para hacer lo que sea su tarea, y luego una CPU ejecuta ese código para producir el resultado deseado. La CPU también está conectada a otras partes de un sistema como la memoria y la E / S para ayudar a mantenerla alimentada con los datos relevantes, pero no cubriremos esos sistemas hoy.

El modelo de la CPU: una ISA

Al analizar cualquier CPU, lo primero que encontrará es la Arquitectura de conjunto de instrucciones (ISA). Este es el plano figurativo de cómo funciona la CPU y cómo interactúan todos los sistemas internos entre sí. Al igual que hay muchas razas de perros dentro de la misma especie, hay muchos tipos diferentes de ISA en los que se puede construir una CPU. Los dos tipos más comunes son x86 (que se encuentra en computadoras de escritorio y portátiles) y ARM (que se encuentra en dispositivos integrados y móviles).

Hay algunos otros como MIPS, RISC-V y PowerPC que tienen más aplicaciones de nicho. Una ISA especificará qué instrucciones puede procesar la CPU, cómo interactúa con la memoria y los cachés, cómo se divide el trabajo en las muchas etapas de procesamiento, y más.

Para cubrir las partes principales de una CPU, seguiremos la ruta que toma una instrucción cuando se ejecuta. Los diferentes tipos de instrucciones pueden seguir diferentes caminos y usar diferentes partes de una CPU, pero generalizaremos aquí para cubrir las partes más importantes. Comenzaremos con el diseño más básico de un procesador de un solo núcleo y agregaremos complejidad gradualmente a medida que avanzamos hacia un diseño más moderno.

Unidad de control y ruta de datos

Las partes de una CPU se pueden dividir en dos: la unidad de control y la ruta de datos. Imagina un vagón de tren. La locomotora es lo que mueve el tren, pero el conductor tira de las palancas detrás de escena y controla los diferentes aspectos de la locomotora. Una CPU es igual.

La ruta de datos es como el motor y, como sugiere el nombre, es la ruta por la que fluyen los datos a medida que se procesan. La ruta de datos recibe las entradas, las procesa y las envía al lugar correcto cuando están listas. La unidad de control le dice a la ruta de datos cómo operar como el conductor del tren. Dependiendo de la instrucción, la ruta de datos enrutará señales a diferentes componentes, encenderá y apagará diferentes partes de la ruta de datos y monitoreará el estado de la CPU.


Diagrama de bloques de una CPU básica. Las líneas negras indican el flujo de datos, las rojas indican el flujo de control. Ilustración de Lambtron a través de Wikipedia

El ciclo de instrucción: búsqueda

Lo primero que debe hacer nuestra CPU es averiguar qué instrucciones ejecutar a continuación y transferirlas de la memoria a la CPU. Las instrucciones son producidas por un compilador y son específicas del ISA de la CPU. Las ISA compartirán los tipos de instrucciones más comunes, como cargar, almacenar, sumar, restar, etc., pero hay muchos tipos especiales adicionales de instrucciones únicas para cada ISA en particular. La unidad de control sabrá qué señales deben enrutarse a dónde para cada tipo de instrucción.

Cuando ejecuta un .exe en Windows, por ejemplo, el código para ese programa se mueve a la memoria y se le dice a la CPU en qué dirección comienza la primera instrucción. La CPU siempre mantiene un registro interno que contiene la ubicación de la memoria de la siguiente instrucción que se ejecutará. Esto se denomina Contador de programas (PC).

Una vez que sabe por dónde empezar, el primer paso del ciclo de instrucción es obtener esa instrucción. Esto mueve la instrucción de la memoria al registro de instrucciones de la CPU y se conoce como etapa Fetch . Siendo realistas, es probable que la instrucción ya esté en el caché de la CPU, pero cubriremos esos detalles en un momento.

El ciclo de instrucción: decodificación

Cuando la CPU tiene una instrucción, necesita averiguar específicamente qué tipo de instrucción es. A esto se le llama etapa de decodificación . Cada instrucción tendrá un cierto conjunto de bits llamado Opcode que le dice a la CPU cómo interpretarlo. Esto es similar a cómo se usan diferentes extensiones de archivo para decirle a una computadora cómo interpretar un archivo. Por ejemplo, .jpg y .png son archivos de imagen, pero organizan los datos de forma diferente, por lo que la computadora necesita saber el tipo para interpretarlos correctamente.

Dependiendo de cuán complejo sea el ISA, la parte de decodificación de instrucciones de la CPU puede volverse compleja. Un ISA como RISC-V puede tener solo unas pocas docenas de instrucciones, mientras que x86 tiene miles. En una CPU Intel x86 típica, el proceso de decodificación es uno de los más desafiantes y ocupa mucho espacio. Los tipos más comunes de instrucciones que decodificaría una CPU son instrucciones de memoria, aritméticas o de bifurcación.

3 tipos de instrucciones principales

Una instrucción de memoria puede ser algo como “leer el valor de la dirección de memoria 1234 en el valor A” o “escribir el valor B en la dirección de memoria 5678”. Una instrucción aritmética podría ser algo así como “agregar valor A al valor B y almacenar el resultado en el valor C”. Una instrucción de bifurcación podría ser algo así como “ejecutar este código si el valor C es positivo o ejecutar ese código si el valor C es negativo”. Un programa típico puede encadenarlos para obtener algo como “agregar el valor en la dirección de memoria 1234 al valor en la dirección de memoria 5678 y almacenarlo en la dirección de memoria 4321 si el resultado es positivo o en la dirección 8765 si el resultado es negativo” .

Antes de comenzar a ejecutar la instrucción que acabamos de decodificar, debemos hacer una pausa por un momento para hablar sobre los registros.

Una CPU tiene algunas piezas de memoria muy pequeñas pero muy rápidas llamadas registros. En una CPU de 64 bits, estos tendrían 64 bits cada uno y puede haber solo unas pocas docenas para el núcleo. Estos se utilizan para almacenar valores que se están utilizando actualmente y se pueden considerar algo así como una caché L0. En los ejemplos de instrucciones anteriores, los valores A, B y C se almacenarían todos en registros.

La ALU

De vuelta a la etapa de ejecución ahora. Esto será diferente para los 3 tipos de instrucciones de los que hablamos anteriormente, por lo que cubriremos cada una por separado.

Comenzando con instrucciones aritméticas, ya que son las más fáciles de entender. Este tipo de instrucciones se introducen en una unidad de registro aritmético (ALU) para su procesamiento. Una ALU es un circuito que normalmente toma dos entradas con una señal de control y genera un resultado.

Imagina una calculadora básica que usaste en la escuela secundaria. Para realizar una operación, escriba los dos números de entrada, así como el tipo de operación que desea realizar. La calculadora realiza el cálculo y genera el resultado. En el caso de la ALU de nuestra CPU, el tipo de operación está determinado por el código de operación de la instrucción y la unidad de control lo enviaría a la ALU. Además de la aritmética básica, las ALU también pueden realizar operaciones bit a bit como AND, OR, NOT y XOR. La ALU también generará información de estado para la unidad de control sobre el cálculo que acaba de completar. Esto podría incluir cosas como si el resultado fue positivo, negativo, cero o tuvo un desbordamiento.

Una ALU está más asociada con operaciones aritméticas, pero también se puede usar para instrucciones de memoria o bifurcaciones. Por ejemplo, la CPU puede necesitar calcular una dirección de memoria dada como resultado de una operación aritmética previa. También puede ser necesario calcular el desplazamiento para agregar al contador del programa que requiere una instrucción de bifurcación. Algo como “si el resultado anterior fue negativo, avance 20 instrucciones”.

Instrucciones y jerarquía de memoria

Para obtener instrucciones sobre la memoria, necesitaremos comprender un concepto llamado Jerarquía de la memoria . Esto representa la relación entre cachés, RAM y almacenamiento principal. Cuando una CPU recibe una instrucción de memoria para un dato que aún no tiene localmente en sus registros, descenderá en la jerarquía de memoria hasta que lo encuentre. La mayoría de las CPU modernas contienen tres niveles de caché: L1, L2 y L3. El primer lugar que verificará la CPU es la caché L1. Este es el más pequeño y rápido de los tres niveles de caché. La caché L1 generalmente se divide en una parte para datos y una parte para instrucciones. Recuerde, las instrucciones deben obtenerse de la memoria al igual que los datos.

Una caché L1 típica puede tener unos cientos de KB. Si la CPU no puede encontrar lo que busca en la caché L1, comprobará la caché L2. Esto puede ser del orden de unos pocos MB. El siguiente paso es la caché L3, que puede tener unas pocas decenas de MB. Si la CPU no puede encontrar los datos que necesita en la caché L3, irá a la RAM y finalmente al almacenamiento principal. A medida que bajamos en cada paso, el espacio disponible aumenta aproximadamente en un orden de magnitud, pero también lo hace la latencia.

Una vez que la CPU encuentra los datos, los mostrará en la jerarquía para que la CPU tenga acceso rápido a ellos si es necesario en el futuro. Hay muchos pasos aquí, pero asegura que la CPU tenga acceso rápido a los datos que necesita. Por ejemplo, la CPU puede leer de sus registros internos en solo uno o dos ciclos, L1 en unos pocos ciclos, L2 en diez o más ciclos y L3 en unas pocas docenas. Si necesita ir a la memoria o al almacenamiento principal, podrían tardar decenas de miles o incluso millones de ciclos. Dependiendo del sistema, es probable que cada núcleo tenga su propia caché L1 privada, comparta una L2 con otro núcleo y comparta una L3 entre grupos de cuatro o más núcleos. Hablaremos más sobre las CPU multinúcleo más adelante en este artículo.

Instrucciones de bifurcación y salto

El último de los tres tipos principales de instrucción es la instrucción de rama. Los programas modernos saltan todo el tiempo y una CPU rara vez ejecutará más de una docena de instrucciones contiguas sin una rama. Las instrucciones de bifurcación provienen de elementos de programación como sentencias if, bucles for y sentencias return. Todos estos se utilizan para interrumpir la ejecución del programa y cambiar a una parte diferente del código. También hay instrucciones de salto que son instrucciones de bifurcación que siempre se toman.

Las bifurcaciones condicionales son especialmente complicadas para una CPU, ya que puede estar ejecutando varias instrucciones a la vez y no puede determinar el resultado de una bifurcación hasta después de que haya comenzado en instrucciones posteriores.

Para comprender completamente por qué esto es un problema, tendremos que tomar otro desvío y hablar sobre la canalización. Cada paso del ciclo de instrucción puede tardar algunos ciclos en completarse. Eso significa que mientras se busca una instrucción, la ALU estaría inactiva. Para maximizar la eficiencia de una CPU, dividimos cada etapa en un proceso llamado canalización.

La forma clásica de entender esto es a través de una analogía con lavar la ropa. Tienes dos cargas que hacer y lavar y secar cada una toma una hora. Puede poner la primera carga en la lavadora y luego en la secadora cuando esté lista, y luego comenzar la segunda carga. Esto tomaría cuatro horas. Sin embargo, si dividió el trabajo y comenzó el lavado de la segunda carga mientras se secaba la primera carga, podría terminar ambas cargas en tres horas. La reducción de una hora se escala con la cantidad de cargas que tiene y la cantidad de lavadoras y secadoras. Todavía se necesitan dos horas para hacer una carga individual, pero la superposición aumenta el rendimiento total de 0.5 cargas / hr a 0.75 cargas / hr.

Una representación gráfica de la canalización utilizada en el núcleo Bobcat de AMD a partir de 2011. Observe lo complejo que es y cuántas etapas están presentes.

Las CPU utilizan este mismo método para mejorar el rendimiento de las instrucciones. Una CPU ARM o x86 moderna puede tener más de 20 etapas de canalización, lo que significa que en cualquier punto dado, ese núcleo está procesando más de 20 instrucciones diferentes a la vez. Cada diseño es único, pero una división de muestra puede ser de 4 ciclos para buscar, 6 ciclos para decodificar, 3 ciclos para ejecutar y 7 ciclos para actualizar los resultados a la memoria.

Volviendo a las ramas, espero que pueda empezar a ver el problema. Si no sabemos que una instrucción es una bifurcación hasta el ciclo 10, ya habremos comenzado a ejecutar 9 nuevas instrucciones que pueden no ser válidas si se toma la bifurcación. Para solucionar este problema, las CPU tienen estructuras muy complejas llamadas predictores de rama. Usan conceptos similares del aprendizaje automático para intentar adivinar si se tomará una rama o no. Las complejidades de los predictores de sucursales están mucho más allá del alcance de este artículo, pero en un nivel básico, rastrean el estado de las sucursales anteriores para saber si es probable que se tome una sucursal próxima o no. Los predictores de rama modernos pueden tener una precisión del 95% o más.

Una vez que se conoce con certeza el resultado de la bifurcación (ha finalizado esa etapa de la canalización), el contador del programa se actualizará y la CPU continuará ejecutando la siguiente instrucción. Si la rama se pronosticó mal, la CPU descartará todas las instrucciones después de la rama que comenzó a ejecutar por error y se iniciará nuevamente desde el lugar correcto.

Ejecución fuera de orden

Ahora que sabemos cómo ejecutar los tres tipos de instrucciones más comunes, echemos un vistazo a algunas de las características más avanzadas de una CPU. Prácticamente todos los procesadores modernos no ejecutan las instrucciones en el orden en que se reciben. Se utiliza un paradigma llamado ejecución fuera de orden para minimizar el tiempo de inactividad mientras se espera que finalicen otras instrucciones.

Si una CPU sabe que una próxima instrucción requiere datos que no estarán listos a tiempo, puede cambiar el orden de las instrucciones y traer una instrucción independiente de más adelante en el programa mientras espera. Este reordenamiento de instrucciones es una herramienta extremadamente poderosa, pero está lejos de ser el único truco que usan las CPU.

Otra característica que mejora el rendimiento se llama captación previa. Si tuviera que medir el tiempo que tarda una instrucción aleatoria en completarse de principio a fin, encontrará que el acceso a la memoria ocupa la mayor parte del tiempo. Un prefetcher es una unidad en la CPU que intenta anticipar instrucciones futuras y qué datos requerirán. Si ve venir uno que requiere datos que la CPU no tiene en caché, se comunicará con la RAM y buscará esos datos en el caché. De ahí el nombre de búsqueda previa.

Aceleradores y el futuro

Otra característica importante que comienza a incluirse en las CPU son los aceleradores para tareas específicas. Estos son circuitos cuyo trabajo completo es realizar una pequeña tarea lo más rápido posible. Esto puede incluir cifrado, codificación de medios o aprendizaje automático.

La CPU puede hacer estas cosas por sí sola, pero es mucho más eficiente tener una unidad dedicada a ellas. Un gran ejemplo de esto son los gráficos integrados en comparación con una GPU dedicada. Seguramente la CPU puede realizar los cálculos necesarios para el procesamiento de gráficos, pero tener una unidad dedicada para ellos ofrece órdenes de magnitud de mejor rendimiento. Con el auge de los aceleradores, es posible que el núcleo real de una CPU solo ocupe una pequeña fracción del chip.

La siguiente imagen muestra una CPU Intel de varios años atrás. La mayor parte del espacio está ocupado por núcleos y caché. La segunda imagen a continuación es para un chip AMD mucho más nuevo. La mayor parte del espacio está ocupado por componentes distintos de los núcleos.


Arriba: la matriz de la arquitectura Nehalem de primera generación de Intel. Tenga en cuenta que los núcleos y la caché ocupan la mayor parte del espacio.


Arriba: la matriz de un SoC AMD que muestra la gran cantidad de espacio dedicado a los aceleradores y las interfaces externas

Pasando a multinúcleo

La última característica importante a cubrir es cómo podemos conectar un montón de CPU individuales para formar una CPU multinúcleo. No es tan simple como poner varias copias del diseño de un solo núcleo del que hablamos anteriormente. Al igual que no existe una manera fácil de convertir un programa de un solo subproceso en un programa de subprocesos múltiples, el mismo concepto se aplica al hardware. Los problemas provienen de la dependencia entre los núcleos.

Para, digamos, un diseño de 4 núcleos, la CPU debe poder emitir instrucciones 4 veces más rápido. También necesita cuatro interfaces separadas para la memoria. Con varias entidades que operan potencialmente con los mismos datos, se deben resolver problemas como la coherencia y la consistencia . Si dos núcleos estuvieran procesando instrucciones que usaran los mismos datos, ¿cómo saben quién tiene el valor correcto? ¿Qué pasa si un núcleo modifica los datos pero no llega al otro núcleo a tiempo para que se ejecute? Dado que tienen cachés separados que pueden almacenar datos superpuestos, se deben usar algoritmos y controladores complejos para eliminar estos conflictos.

La predicción de ramas adecuada también es extremadamente importante a medida que aumenta el número de núcleos en una CPU. Cuantos más núcleos estén ejecutando instrucciones a la vez, mayor será la probabilidad de que uno de ellos esté procesando una instrucción de bifurcación. Esto significa que el flujo de instrucciones puede cambiar en cualquier momento.

Normalmente, los núcleos separados procesarán secuencias de instrucciones de diferentes subprocesos. Esto ayuda a reducir la dependencia entre núcleos. Es por eso que si marca el Administrador de tareas, a menudo verá un núcleo trabajando duro y los otros apenas. Muchos programas no están diseñados para subprocesos múltiples. También puede haber ciertos casos en los que sea más eficiente que un núcleo haga el trabajo en lugar de pagar las multas por tratar de dividir el trabajo.

Diseño fisico

La mayor parte de este artículo se ha centrado en el diseño arquitectónico de una CPU, ya que ahí es donde reside la mayor parte de la complejidad. Sin embargo, todo esto debe crearse en el mundo real y eso agrega otro nivel de complejidad.

Para sincronizar todos los componentes en todo el procesador, se utiliza una señal de reloj. Los procesadores modernos generalmente funcionan entre 3.0GHz y 5.0GHz y eso no parece haber cambiado en la última década. En cada uno de estos ciclos, los miles de millones de transistores dentro de un chip se encienden y apagan.

Los relojes son fundamentales para garantizar que a medida que avanza cada etapa del proceso, todos los valores se muestran en el momento adecuado. El reloj determina cuántas instrucciones puede procesar una CPU por segundo. El aumento de su frecuencia mediante el overclocking hará que el chip sea más rápido, pero también aumentará el consumo de energía y la salida de calor.

El calor es el peor enemigo de una CPU. A medida que la electrónica digital se calienta, los transistores microscópicos pueden comenzar a degradarse. Esto puede provocar daños en un chip si no se elimina el calor. Es por eso que todas las CPU vienen con disipadores de calor. La matriz de silicio real de una CPU solo puede ocupar el 20% del área de superficie de un dispositivo físico. El aumento de la huella permite que el calor se distribuya de manera más uniforme a un disipador de calor. También permite más pines para interactuar con componentes externos.

Las CPU modernas pueden tener mil o más pines de entrada y salida en la parte posterior. Sin embargo, un chip móvil solo puede tener unos pocos cientos de pines, ya que la mayoría de las partes de la computadora están dentro del chip . Independientemente del diseño, alrededor de la mitad de ellos se dedican a la entrega de energía y el resto se utilizan para comunicaciones de datos. Esto incluye comunicación con RAM, chipset, almacenamiento, dispositivos PCIe y más. Con CPU de alto rendimiento que consumen cien o más amperios a plena carga, necesitan cientos de pines para distribuir el consumo de corriente de manera uniforme. Los pines suelen estar chapados en oro para mejorar la conductividad eléctrica. Los diferentes fabricantes utilizan diferentes disposiciones de pines en sus numerosas líneas de productos.

Poniéndolo todo junto con un ejemplo

Para terminar, echaremos un vistazo rápido al diseño de una CPU Intel Core 2. Esto se remonta a 2006, por lo que algunas piezas pueden estar desactualizadas, pero los detalles de los diseños más nuevos no están disponibles.

Comenzando por la parte superior, tenemos la caché de instrucciones y la ITLB. El búfer de búsqueda de traducción (TLB) se utiliza para ayudar a la CPU a saber a qué lugar de la memoria debe ir para encontrar la instrucción que necesita. Esas instrucciones se almacenan en una caché de instrucciones L1 y luego se envían a un pre-decodificador. La arquitectura x86 es extremadamente compleja y densa, por lo que hay muchos pasos para decodificar. Mientras tanto, tanto el predictor de rama como el prefetcher están mirando hacia el futuro para detectar posibles problemas causados ​​por las instrucciones entrantes.

Desde allí, las instrucciones se envían a una cola de instrucciones. Recuerde cómo el diseño fuera de orden permite que una CPU ejecute instrucciones y elija la más oportuna para ejecutar. Esta cola contiene las instrucciones actuales que está considerando una CPU. Una vez que la CPU sabe qué instrucción sería la mejor para ejecutar, se decodifica en microoperaciones. Si bien una instrucción puede contener una tarea compleja para la CPU, las microoperaciones son tareas granulares que la CPU interpreta más fácilmente.

Estas instrucciones luego van a la tabla de alias de registro, el ROB y la estación de reserva. La función exacta de estos tres componentes es un poco compleja (piense en un curso universitario de posgrado), pero se utilizan en el proceso desordenado para ayudar a gestionar las dependencias entre las instrucciones.

Un solo “núcleo” en realidad tendrá muchas ALU y puertos de memoria. Las operaciones entrantes se colocan en la estación de reserva hasta que una ALU o puerto de memoria esté disponible para su uso. Una vez que el componente requerido esté disponible, la instrucción se procesará con la ayuda de la caché de datos L1. Los resultados de salida se almacenarán y la CPU estará lista para comenzar con la siguiente instrucción. ¡Eso es todo!

Si bien este artículo no pretendía ser una guía definitiva sobre cómo funciona exactamente cada CPU, debería darte una buena idea de su funcionamiento y complejidad internos. Francamente, nadie fuera de AMD e Intel sabe realmente cómo funcionan sus CPU. Cada sección de este artículo representa un campo completo de investigación y desarrollo, por lo que la información que se presenta aquí solo es superficial.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *