Blog Personal.

Conceptos Básicos

Formato de Instrucciones y Conversión a Binario

Por petición en el buzón de sugerencias:

Hola una duda como convierten las instrucciones a operaciónes que entienda la cpu

Una instruccion esta compuesta por 3 bloques:

El Opcode nos marca que instrucción es la que va a ejecutar el procesador y para todas las CPUs bajo una misma familia es el mismo y no cambia. Es decir, el Opcode nos marca la acción que realiza el procesador en el programa de dentro de una lista marcada y el valor de cada opcode corresponde a una instrucción.

Por ejemplo el 6502 tiene hasta unas 256 instrucciones en total, para ello necesita que el Opcode sea de 8 bits ya que 28 son unas 256 combinaciones distintas.

El Modo nos marca en el caso de que la instrucción en concreto tenga diferentes maneras de funciona cual queremos utilizar, no todas las instrucciones tienen un modo asignado.

En cuanto a la dirección tenemos 4 tipos de instrucciones según la cantidad de direcciones de memoria que utilicen:

  • 3 Direcciones.
  • 2 Direcciones
  • 1 Dirección
  • 0 direcciones

Una dirección le marca a la CPU en que posición de la memoria se encuentra el dato. El direccionamiento puede ser directo o indirecto, el indirecto es cuando la dirección de memoria apunta a la dirección de memoria del dato y por tanto es más lenta. Hay que tener en cuenta además que cuanto más accesos a memoria necesite una CPU más latencia tendrá dicha instrucción y cuanto menos accesos más rápida será. Es decir, las instrucciones con mayor cantidad de ciclos por instrucción son las de 3 direcciones y las que menos obviamente las de 0 direcciones y que obviamente el acceso indirecto es mucho más lento que el acceso directo.

  • En el formato de 3 direcciones lo que hacemos es escoger donde se encuentran los operandos A y B de la instrucción y especificamos donde escribimos el resultado C.
  • En el formato de 2 direcciones A y B pueden ser operandos o A puede ser origen y B destino.
  • En el formato de 1 dirección solo tenemos A como dirección de destino o de origen del dato.
  • En el formato de 0 direcciones el dato que hay en la instrucción es con el que tenemos que operar de manera directa.

¿Direcciones de memoria?

La RAM esta organizada en direcciones de memoria, de manera abstracta es como una hoja de cálculo…

Cada dirección de la RAM se divide en dos mitades, una mitad corresponde a fila (Row) y la otra mitad a la columna (Column) y en cada celda esta el dato con el que operar. Si la instrucción pide una lectura del dato será copiado hacía los registros, si es una de escritura se reemplazará el contenido de la celda por el nuevo dato.

Pero actualmente las CPUs ya no acceden de esta manera tan simple sino que lo que han hecho es pasar a utilizar páginas y en realidad tampoco es muy complejo, la memoria virtual cambia el direccionamiento y en vez de tener un enorme mapa con X e Y coordenadas digamos que ha pasado a ser un libro donde tenemos V páginas de un tamaño concreto. Dicho direccionamiento es traducido por una unidad llamada MMU a lo que es el direccionamiento normal pero concede un nivel de privilegios y cuando un programa accede a una parte que no tiene permitida y solo puede el sistema operativo entonces le hace:

Cuando la CPU accede a la memoria RAM esta va por tiempos, lo primero que hace es enviarle la dirección a través de los pines de direccionamiento que van de la CPU a la RAM y le dicen que dato ha de buscar, cada pin corresponde a un 1 bit del direccionamiento, así pues un direccionamiento de n bits tendra n pins y podrá direccionar 2n direcciones de memoria distintas donde cada dirección representa un byte, esto nos marca además la RAM máxima a la que puede acceder cada CPU.

¿Pero que ocurre si un dato es de más de un byte? Pues no hay problema porque los datos se almacenan de manera secuencial en el caso que tengamos un solo chip de memoria pero con varios chips el direccionamiento apunta a la vez a todos los chips pero cada uno de ellos enviará una parte distinta del dato a través de su bus de datos, esta forma de acceder a los datos en paralelo acelera como es obvió el tiempo por instrucción que le ha pedido la CPU.

En todo caso, perdón por el inciso pero tenia que dejar la parte del direccionamiento clara para no dejar la explicación a medias.

#2 De lenguaje a binario

Bueno, hay dos formas de hacerlo.

Forma#1: Conversión a Assembler

Cada familia de procesadores agrupada en un conjunto de registros+instrucciones en común (x86, MIPS, PowerPC, ARM…) tienen un lenguaje Assembler propio.

El Assembler es la versión entendible para los seres humanos de como la CPU lee las instrucciones, obviamente no esta en binario pero el orden de sus instrucciones y las instrucciones disponibles en principio son las que tiene disponibles la familia de procesadores de las que dispones y digo en principio por el hecho de que hay modelos de CPU dentro de una misma familia cuyas instrucciones son un superconjunto y tienen instrucciones adicionales aparte de las del estándar marcado. Obviamente a no ser que tu software vaya a utilizar un modelo concreto de dicha familia de CPUs no vas a poder utilizar esas instrucciones adicionales en otros núcleos del familia porque no las van a entender.

Muchos compiladores lo que hacen es generar lenguaje ensamblador, el problema viene cuando hay ciertas instrucciones en lenguajes de alto nivel que equivalen a varias en lenguaje ensamblador y aquí tenemos que separar funcionalidad de comportamiento donde una cosa es lo que hace y lo otro como lo hace por lo que dependiendo de un compilador u otro este generará internamente un código ensamblador u otro y dara un rendimiento mejor o peor dependiendo del caso.

El lenguaje ensamblador no es más que la version entendible para los seres humanos del formato de instrucción que he comentado antes. Esto fácilita la conversión directa, el compilador entonces transforma la instrucción en la tabla de opcodes y lo transforma en el binario correspondiente. Según que tipo de instrucción sea pues tratará los datos que vienen a continuación como marca el formato de la instrucción (3, 2, 1 o ninguna dirección).

Forma#2: Bytecode

En este caso no se convierte el código a ensamblador sino a una máquina virtual inexistente con un conjunto de registros e instrucciones concreto pero no se hace convirtiendo a ensamblador el código sino a lo que es llamado bytecode.

En realidad no es más que un assembler, pero no para una arquitectura fisica sino para una abstracción que además no esta pensada para que la entiendan los seres humanos sino para poder trasladar dicha instrucción a la arquitectura en la que nos encontramos. El Bytecode puede funcionar de tres maneras distintas:

  • A través de una máquina virtual que corre emulada por la CPU real (Caso Java).
  • Como lenguaje intermedio de conversión a un binario concreto (Plataforma .NET y su Common Language Interface).
  • Como lenguaje interpretado a tiempo real (Python, Javascript).

El Bytecode permite la total portabilidad, pero en el caso de que haya una máquina virtual o un lenguaje interpretado vamos a necesitar un programa que interprete esto para cada tipo de procesador, lo cual hace que pierdan velocidad a favor de tener portabilidad.

Esto es todo, tenéis el Discord y los comentarios de esta entrada para comentarla.

0 0 vote
Article Rating
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Steven

Gracias por La repuesta

Dani

Qué trabajazo. Gracias.