cursos:ensamblador:arquitectura

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anterior Revisión previa
Próxima revisión
Revisión previa
cursos:ensamblador:arquitectura [19-01-2024 06:22] – [Opcodes y código máquina] sromerocursos:ensamblador:arquitectura [20-01-2024 20:11] (actual) – [Partes del mapa de Memoria del Spectrum] sromero
Línea 334: Línea 334:
  
 En un modelo 48K, encontraremos después de $6000 mucha más RAM. Aparte de los 8KB entre $6000 y $7fff, tenemos otros 2 bloques de 16KB (un total de 32KB más) de $8000 (32768) a $bfff (49151) y de $c000 (49152) a $ffff (65535). En un modelo 48K, encontraremos después de $6000 mucha más RAM. Aparte de los 8KB entre $6000 y $7fff, tenemos otros 2 bloques de 16KB (un total de 32KB más) de $8000 (32768) a $bfff (49151) y de $c000 (49152) a $ffff (65535).
 +
 +La siguiente figura, extraída del libro "//Sprites y Graficos En Lenguaje Maquina//" (de //John Durst//), muestra un esquema del mapa de memoria del Spectrum 48K:
 +
 +\\ 
 +{{ :cursos:ensamblador:mapa-mem-sprites-y-graficos-lenguajemaquina.jpg }}
 +\\ 
  
 \\  \\ 
Línea 403: Línea 409:
           o Ejecutar la instrucción           o Ejecutar la instrucción
      Fin Mientras      Fin Mientras
-     
 </code> </code>
  
Línea 485: Línea 490:
     * Leer el byte contenido en la dirección de memoria "PC" (40000).     * Leer el byte contenido en la dirección de memoria "PC" (40000).
     * Incrementar PC (PC=PC+1).     * Incrementar PC (PC=PC+1).
-    * El byte es "$3e", con lo cual el Spectrum sabe que +    * El byte es "$3e", con lo cual el Spectrum sabe que el opcode 
-      tiene que meter en A un valor numérico.+      la instrucción es un "ld a, valor", y que por tanto tiene 
 +      que meter en A un valor numérico.
     * El valor extra para "ld a," está a continuación en memoria,      * El valor extra para "ld a," está a continuación en memoria, 
       así que se lee la memoria de nuevo:       así que se lee la memoria de nuevo:
Línea 496: Línea 502:
 </code> </code>
  
-Esto que hemos visto es el proceso de "Lectura de Instrucción (fetch)", "decodificación (decode)", y "ejecución (execute)". Pero recordemos que este proceso se ejecuta una y otra vez, sin parar, de modo que el procesador sigue con la siguiente instrucción (inc a):+Esto que hemos visto es el proceso de "Lectura de Instrucción (fetch)", "decodificación (decode)", y "ejecución (execute)". Pero recordemos que este proceso se ejecuta una y otra vez, sin parar, de modo que el procesador sigue con la siguiente instrucción (''inc a''):
  
 <code> <code>
     * Leer el byte contenido en la dirección de memoria "PC" (40002).     * Leer el byte contenido en la dirección de memoria "PC" (40002).
     * Incrementar PC (PC=PC+1).     * Incrementar PC (PC=PC+1).
-    * El byte es **$3c**, con lo cual el Spectrum sabe que tiene que incrementar A.+    * El byte es "$3c", con lo cual el Spectrum sabe que tiene que incrementar A.
     * No hacen falta operandos extra, inc a no requiere nada más.     * No hacen falta operandos extra, inc a no requiere nada más.
-    * Ya se tiene el "código de instrucción completo", así que se ejecuta: ''inc a''.+    * Ya se tiene el "código de instrucción completo", así que se ejecuta: "inc a".
 </code> </code>
  
Línea 511: Línea 517:
     * Leer el byte contenido en la dirección de memoria "PC" (40009).     * Leer el byte contenido en la dirección de memoria "PC" (40009).
     * Incrementar PC (PC=PC+1).     * Incrementar PC (PC=PC+1).
-    * El byte es "$c9", con lo cual el Spectrum sabe que tiene que hacer un ret.+    * El byte es "$c9", con lo cual el Spectrum sabe que tiene que hacer un "ret".
     * No hacen falta operandos extra, ret no requiere nada más.     * No hacen falta operandos extra, ret no requiere nada más.
     * Ya se tiene el "código de instrucción completo", así que se ejecuta: "ret".     * Ya se tiene el "código de instrucción completo", así que se ejecuta: "ret".
Línea 522: Línea 528:
     * La primera parte leída de la instrucción es el OPCODE (código de operación), y es lo que permite al Spectrum, mediante una "tabla interna", saber qué tarea exacta tiene que realizar. Si la instrucción necesita datos extra para leer de memoria, se almacenan tras el opcode, y se conocen como "operandos". Así, ''ld a, 00'' se corresponde con la instrucción **$3e $00**, donde **$3e** es el código de operación (opcode) y **$00** es el operando.     * La primera parte leída de la instrucción es el OPCODE (código de operación), y es lo que permite al Spectrum, mediante una "tabla interna", saber qué tarea exacta tiene que realizar. Si la instrucción necesita datos extra para leer de memoria, se almacenan tras el opcode, y se conocen como "operandos". Así, ''ld a, 00'' se corresponde con la instrucción **$3e $00**, donde **$3e** es el código de operación (opcode) y **$00** es el operando.
  
-    * Para el Spectrum, no hay diferencia entre instrucciones y datos. Un **$3c** puede ser un ''inc a'' o un valor númerico **$3c** como parte de una cadena de texto, o de un gráfico, o un operador (el valor que queremos meter en un registro). ¿Cómo distingue el Spectrum uno de otro? Sencillo: todo depende de si se encuentra al principio de un ciclo de decodificación o no. Es decir, si cuando vamos a empezar a leer una instrucción leemos un "$3c", es un ''inc a''. Pero si lo leemos en el proceso de lectura de un operando, su significado cambia. Pensad en por ejemplo en ''ld a, $3c'', que se codificaría como "$3e $3c", pero no ejecutaría un inc a porque la lectura del "$3cse realiza como operando para el ''ld a,''.+    * Para el Spectrum, no hay diferencia entre instrucciones y datos. Un **$3c** puede ser un ''inc a'' o un valor númerico **$3c** como parte de una cadena de texto, o de un gráfico, o un operador (el valor que queremos meter en un registro). ¿Cómo distingue el Spectrum uno de otro? Sencillo: todo depende de si se encuentra al principio de un ciclo de decodificación o no. Es decir, si cuando vamos a empezar a leer una instrucción, cuando estamos leyendo el opcode de la misma, leemos un **$3c**, es un ''inc a''. Pero si lo leemos en el proceso de lectura de un operando, su significado cambia. Pensad en por ejemplo en ''ld a, $3c'', que se codificaría como **$3e $3c**, pero no ejecutaría un ''inc a'' porque la lectura del **$3c** se realiza como operando para el ''ld a,''.
  
     * Al no existir diferencia entre instrucciones y datos, si cambiamos PC de forma que apunte a una zona de la memoria donde hay datos y no código, el Z80 tratará de interpretar los números que va leyendo como si fueran opcodes (con resultados imprecedibles, seguramente con el cuelgue del Spectrum o un reset).     * Al no existir diferencia entre instrucciones y datos, si cambiamos PC de forma que apunte a una zona de la memoria donde hay datos y no código, el Z80 tratará de interpretar los números que va leyendo como si fueran opcodes (con resultados imprecedibles, seguramente con el cuelgue del Spectrum o un reset).
  
-    * Por último, existen una serie de opcodes compuestos (dejando de lado los operandos) que ocupan más de 1 byte. Esos opcodes suelen comenzar por CB, ED o FD, de forma que, por ejemplo el opcode "$cb $04se corresponde con la operación ''rlc l''. Si sólo pudieramos utilizar un byte para representar el opcode, sólo tendríamos disponibles 256 posibles instrucciones en el procesador. Para poder disponer de más instrucciones se utilizan códigos de instrucción de más de un byte. Así, cuando nuestro procesador encuentra un CB, ED o FD sabe que el próximo código que lea después tendrá un significado diferente al que tendría sin el CB, ED o FD delante. Es por eso que "$04significa ''inc b'',"$cb $04significa ''rlc l'' (una instrucción diferente).+    * Por último, existen una serie de opcodes compuestos (dejando de lado los operandos) que ocupan más de 1 byte. Esos opcodes suelen comenzar por CB, ED o FD, de forma que, por ejemplo el opcode **$cb $04** se corresponde con la operación ''rlc l''. Si sólo pudieramos utilizar un byte para representar el opcode, sólo tendríamos disponibles 256 posibles instrucciones en el procesador. Para poder disponer de más instrucciones se utilizan códigos de instrucción de más de un byte. Así, cuando nuestro procesador encuentra un CB, ED o FD sabe que el próximo código que lea después tendrá un significado diferente al que tendría sin el CB, ED o FD delante. Es por eso que **$04** significa ''inc b'',**$cb $04** significa ''rlc l'' (una instrucción diferente).
  
-    * Cuando un operando es de 16 bits (2 bytes), primero encontramos el byte bajo y luego el byte alto. Así, nuestro ''ld de, $aabb'' no se codifica como "$11 $aa $bbsino como "$11 $bb $aa". El opcode para ''LD DE'' es "$11", y "$bb $aalos operandos (en este caso, un valor numérico directo). Esta forma de almacenamiento se denomina técnicamente "little endian", como veremos en el siguiente apartado.+    * Cuando un operando es de 16 bits (2 bytes), primero encontramos el byte bajo y luego el byte alto. Así, nuestro ''ld de, $aabb'' no se codifica como **$11 $aa $bb** sino como **$11 $bb $aa**. El opcode para ''LD DE'' es **$11**, y **$bb $aa** los operandos (en este caso, un valor numérico directo). Esta forma de almacenamiento se denomina técnicamente "little endian", como veremos en el siguiente apartado.
  
 \\  \\ 
Línea 555: Línea 561:
 | 50003 | $c9 | | 50003 | $c9 |
  
-Si ahora saltamos a la dirección 50000 para ejecutar el programa, lo primero que encuentra el procesador es $21, que indica al procesador que la instrucción es un ''ld hl,'' y que el valor a cargar en HL viene en memoria a continuación en las 2 siguientes celdillas de memoria. Pero al ser un procesador little-endian, no nos encontramos primero $40 y luego $00 (como en el $4000 que nosotros tecleamos en nuestro programa ensamblador) sino que en memoria está almacenado al revés: $00 primero y $40 en el byte siguiente. Cuando el procesador haya terminado de leer los 3 bytes y ejecute la instrucción, el registro HL contendrá el valor $4000 (no $0040, ya que el orden de aparición sólo es una cuestión de orden de almacenamiento).+Si ahora saltamos a la dirección 50000 para ejecutar el programa, lo primero que encuentra el procesador es $21, que indica al procesador que la instrucción es un ''ld hl,'' y que el valor a cargar en HL viene en memoria a continuación en las 2 siguientes celdillas de memoria. Pero al ser un procesador little-endian, no nos encontramos primero **$40** y luego **$00** (como en el **$4000** que nosotros tecleamos en nuestro programa ensamblador) sino que en memoria está almacenado al revés: **$00** primero y **$40** en el byte siguiente. Cuando el procesador haya terminado de leer los 3 bytes y ejecute la instrucción, el registro HL contendrá el valor $4000 (no $0040, ya que el orden de aparición sólo es una cuestión de orden de almacenamiento).
  
 Esto no sólo ocurre con las instrucciones ensambladas, sino que ocurre lo mismo con los datos de 16 bits almacenados en memoria. Si ejecutamos: Esto no sólo ocurre con las instrucciones ensambladas, sino que ocurre lo mismo con los datos de 16 bits almacenados en memoria. Si ejecutamos:
Línea 564: Línea 570:
 </code> </code>
  
-Si revisamos los valores almacenados en memoria, encontraremos el valor $34 en $4000 y el valor $12 en $4001.+Si revisamos los valores almacenados en memoria, encontraremos el valor **$34** en **$4000** y el valor **$12** en **$4001**.
  
 Y si después hacemos: Y si después hacemos:
  • cursos/ensamblador/arquitectura.1705645337.txt.gz
  • Última modificación: 19-01-2024 06:22
  • por sromero