La arquitectura de un procesador, como el usado en la tarjeta raspberry pi4b, soporta un conjunto de instrucciones, llamado: armv8-a. de este conjunto de instrucciones, hay un subconjunto llamado: legv8, el cual, esta más optimizado para procesamiento de 64 bits. Usaremos, este subconjunto, por ser un avance en la arquitectura de los procesadores ARM.

En la siguiente figura podemos observar los bloques del procesador usado en la tarjeta Raspberry Pi4B

 


| Clique na imagem para ampliar |

 

 

Podemos destacar la capacidad de ejecutar instrucciones para 32 y 64 bits. En este apartado veremos el subconjunto LEGv8, el cual esta mas optimizado para 64 bits. Observa la siguiente figura:

 


 

 

 

La arquitectura LEGv8 en la tarjeta Raspberry Pi4B, es basado en un subconjunto de instrucciones del conjunto de instrucciones: ARMv8-A. La siguiente figura muestra el simulador de instrucciones para este subconjunto (LEGv8):

 

 


| Clique na imagem para ampliar |

 

 

En el simulador, podemos notar: el editor de instrucciones, el conjunto de registros (X0, X27), los registros de uso especial (SP, FP, LR, XZR), donde podemos ver los resultados de las instrucciones y el camino que siguen los datos (datapath). La siguiente figura muestra el diagrama de la arquitectura LEGv8 de la tarjeta Raspberry Pi4B:

 


| Clique na imagem para ampliar |

 

 

Observemos como esta arquitectura tiene: Memoria de Instrucciones, Contador de Programa, Registros, Unidad Logica Aritmetica (ALU), Multiplexores, Memoria RAM, Logica de Control, Datos, Direcciones, Instrucciones, etc. La siguiente figura muestra las partes mas inportantes de la arquitectura LEGv8:

 

 


| Clique na imagem para ampliar |

 

 

Como visto en el capítulo anterior, el procesador de la Raspberry Pi4B, tiene un contador de programa (PC) para accesar la instrucción que se va a ejecutar. Este contador se incrementa en 4 por cada búsqueda o ciclo de reloj. Observa la siguiente imagen:

 


| Clique na imagem para ampliar |

 

 

Así, el contador de programa tiene la dirección de la “instrucción” que se está ejecutando. La memoria de instrucciones solo puede ser direccionada por el contador de programa. Esto asegura el correcto funcionamiento de acceso y búsqueda de instrucciones. Aunque existen algunos modos de direccionamiento a memoria, el contador de programa debe contener la dirección de la instrucción. Observa en la siguiente imagen, donde se ubica la dirección de la memoria de instrucciones:

 


 

 

 

Escribe este bloque de código y observemos lo que pasa en el camino de datos:

 


| Clique na imagem para ampliar |

 

 

Recuerde que es necesario ensamblar y ejecutar las instrucciones, presionando en los botones mostrados en la siguiente imagen:

 


| Clique na imagem para ampliar |

 

 

Al ejecutarse las instrucciones, el camino de datos, de la dirección de la “memoria de instrucciones”, sigue por el sumador mostrado en la siguiente imagen:

 


 

 

 

Esto se debe a que cada instrucción tiene un ancho de 32 bits y por eso es necesario el incremento de 4, en el sumador, para así, encontrar la dirección de la próxima instrucción que ejecutara el procesador. Entonces, de la memoria de instrucciones, leemos las instrucciones que se ejecutaran. Así, encontramos el concepto: “instrucción”, como mostrado en la siguiente imagen:

 


| Clique na imagem para ampliar |

 

 

Las instrucciones van a la entrada de un “decodificador de instrucciones”. Un decodificador, en electrónica digital, es un circuito con un número de entradas digitales y un numero de salidas digitales. De acuerdo a los valores colocados a la entrada del decodificador, se activarán algunas salidas. Observa la siguiente imagen:

 

 


| Clique na imagem para ampliar |

 

Como las instrucciones tienen un ancho de 32 bits, es posible, colocar ciertos valores en la instrucción, para seleccionar determinadas partes del procesador. Observa en la siguiente imagen, por ejemplo: los bits [4-0] seleccionan el registro destino (rd), los bits [9-5] seleccionan el registro fuente 1 (rs1), los bits [20-16] seleccionan el registro fuente 2 (rs2), los bits [31-21] contienen el “OpCode” de la instrucción. El OpCode es la parte que identifica la instrucción, siendo única para cada instrucción.

 


 

 

 

En la siguiente figura se resume el trabajo del decodificador de instrucciones. Aunque hay que tener en cuenta, que, dependiendo del tipo de instrucción, los bits de la instrucción tendrán informaciones referentes a esa instrucción. Por ejemplo: para una instrucción de movimiento de registros, la instrucción indicara: el registro fuente 1, el registro fuente 2 y el registro destino. Para una instrucción del salto, la instrucción contendrá la dirección a donde debe buscar la próxima instrucción.

 


| Clique na imagem para ampliar |

 

Aquí, entra el concepto: “Registros”. La arquitectura LEGv8 cuenta con 32 registros. La siguiente figura muestra como se seleccionan los registros en una instrucción:

 


| Clique na imagem para ampliar |

 

 

La siguiente figura muestra, los registros del procesador:

 


 

 

 

Hasta aquí, con un procesador como el mostrado en las figuras anteriores, podemos cargar datos en los registros y mover datos entre registros. Es momento de agregar lógica para hacer saltos incondicionales. En la siguiente figura, podemos notar como se puede usar una instrucción (OpCode) para hacer saltos en la memoria de instrucciones:

 


| Clique na imagem para ampliar |

 

 

Cuando una instrucción de salto es ejecutada, normalmente, se informa la cantidad de instrucciones, que es necesario saltar. Es importante notar que los saltos pueden ser hacia adelante o hacia atrás. Cuando los saltos son hacia adelante, el número de instrucciones a saltar es positivo. Cuando el salto es hacia atrás, el número de instrucciones a saltar es negativo. En ambos casos en necesario, hacer una multiplicación por 4. Esto se puede hacer, desplazando hacia la izquierda, el número de instrucciones a saltar. Es necesario usar un multiplexor, para seleccionar la dirección donde se ejecutará la próxima instrucción. Observa la siguiente figura:

 


| Clique na imagem para ampliar |

 

 

Escribe estas instrucciones en el editor y observemos la instrucción de salto incondicional:

 


 

 

 

Observa que cuando se ejecutan las tres primeras instrucciones, es usado el sumador de la parte superior del “datapath”, como se muestra en la siguiente imagen:

 


| Clique na imagem para ampliar |

 

 

Pero cuando es ejecutada la instrucción de salto incondicional, se usa el otro sumador para encontrar la dirección de la memoria de instrucciones. Observa esto en la siguiente figura:

 


| Clique na imagem para ampliar |

 

 

La instrucción que el simulador esta ejecutando, puede ser vista en la parte inferior del diagrama de camino de datos o “datapath”, como mostrado en la siguiente figura:

 


 

 

 

Si fuese agregada una: “Unidad Lógica Aritmética” (ALU), a la salida de datos de los registros, entonces, se pueden ejecutar instrucciones de este tipo. Observa en la siguiente figura, como fue colocada una ALU, a la salida de los registros:

 


| Clique na imagem para ampliar |

 

 

Cuando la ALU ejecute alguna operación, es posible saber si el resultado fue: “Cero”. Basado en esta información es posible realizar un salto condicional.

 


| Clique na imagem para ampliar |

 

 

Escribe en el editor de instrucciones, un programa como el siguiente:

 


| Clique na imagem para ampliar |

 

 

El programa carga el registro X1 con el valor: 10, el registro X2 con el valor: 10, después se ejecuta la instrucción de sustracción (SUB), entre los registros X2 y X1, dejando el resultado en el registro X2. Después, es ejecutada la instrucción: “CBZ”, la cual está verificando, si el registro X2, tiene el valor de cero. Caso esto sea verdadero, entonces saltar a la etiqueta: “rep_sub”. Podemos observar que la primera vez que se pasa por la instrucción de salto condicional, la verificación es verdadera, pero la segunda vez, no. Para ejecutar el programa, presione el botón: “Assemble” y después el botón: “Execute Instruction”. Observa en el “datapath”, como al ejecutarse la instrucción: “CBZ”, por la primera vez, la puerta lógica AND, tiene sus 2 entradas a nivel lógico alto:

 

 


 

 

 

La Unidad Lógica Aritmética, además de ejecutar instrucciones de este tipo, también da información de los resultados de las operaciones. Esto lo hace a través de unas banderas (flags), las cuales tienen los siguientes nombres: N, Z, C, V.

La bandera: “N”: indica si una operación dio negativo.

La bandera: “Z”: indica si una operación dio Cero.

La bandera: “C”: indica si una operación lleva un “1” (Carry).

La bandera: “V”: indica si una operación tuvo un desbordamiento (Overflop).

Observa en la siguiente imagen, que podemos hacer saltos condicionales, verificando el valor de estas banderas:

 


| Clique na imagem para ampliar |

 

 

La siguiente figura muestra las banderas de la ALU en el “datapath”:

 


 

 

 

La siguiente tabla muestra los tipos de condiciones que se pueden verificar en las banderas de la ALU:

 


| Clique na imagem para ampliar |

 

 

Con lo visto hasta aquí, es fácil entender como un lenguaje de alto nivel como Python o C++, puede interpretar código y convertirlo en lenguaje ensamblador. Vamos a crear un programa simple en Python.

El siguiente programa, crea una variable llamada: “k” y le asigna el valor: 10. Después, crea una variable: “j” y le asigna el valor: 10. Después, hace una resta (k-j), y el resultado lo almacena en la variable: “r”. Después, compara si el resultado es igual a cero. Si esto es verdadero, carga el valor: 4, en la variable: “r”. El programa en Python seria así:

 


 

 

 

Un interpretador que use el subconjunto de instrucciones LEGv8, podría generar el siguiente programa ensamblador:

 


 

 

 

Así, el interpretador de Python, asigno a:

X22, la variable: “k”

X23, la variable: “j”

X9, la variable: “r”

La instrucción: “CBNZ”, verifica si el valor en la variable: “r”, no es cero. Si es cero, entonces carga el registro: X9, con el valor: 4

 

 

Conclusión

La arquitectura de un procesador es fácil de entender, a medida que se practica con sus instrucciones. Para el caso de la Raspberry Pi4B, usamos el subconjunto de instrucciones LEGv8. El simulador LEGv8, permite escribir instrucciones en ensamblador y ver sus resultados en los registros. También, nos permite ver que caminos siguieron las instrucciones y los datos que estas manejan. En este apartado, tomamos los componentes más importantes del procesador. Mucho se puede explorar, más la “arquitectura de un procesador”, se puede entender y tener una mejor visión de la manera en que fue construida.

 

 

 

Buscador de Datasheets



N° de Componente