martes, 31 de julio de 2012

Curso Ensámblalo! Cap. 5 - Lenguaje Máquina del 6502. Las Instrucciones De Carga/Almacenamiento de Datos



En capitulos anteriores hemos visto como ensamblar nuestros programas en código máquina, bien a mano, con la ayuda de un cargador Basic, o bien con la ayuda de un monitor de CM, como el incluido en el emulador WinVice. Con ello habéis conseguido tener una idea bastante clara de cómo se introducen programas en lenguaje máquina, y a su vez los rudimentos más básicos en los que se basa cualquier compilador de programas en lenguaje ensamblador.

Vimos de paso, unas pocas instrucciones de código máquina y alguna que otra directiva de lenguaje ensamblador (como ORG), pero para poder empezar a trabajar en serio con Kickass (el ensamblador en que se basa el curso) tenemos que conocer a fondo el lenguaje máquina del procesador. De esto precisamente tratará éste y los próximos capitulos.



Aprendamos pues, de una vez, el...

Lenguaje Máquina del 6502



Antes de continuar, una pequeña aclaración: Ya que el 6510 (el chip de la CPU del c64) es una versión levemente modificada del 6502, cuando hablemos del lenguaje máquina en general, veréis que me refiero a la CPU con el nombre del chip "padre" de la familia (la 65xx). El 6510, precisando un poco más, tan sólo es un 6502 con dos patillas extra conectadas a las direcciones RAM 0 y 1, y sirven para configurar la memoria. Sin embargo, todo lo demás es exactamente igual y 100% compatible.

De esto podéis deducir correctamente que programar en lenguaje máquina del 6502, nos servirá para programar Apples, Ataris, BBC Micros, los de la familia Commodore: los PET, los CBM, los TED, el VIC-20, y en definitiva, cualquier ordenador de la familia 65xx (¡incluso la consola NES!). Una vez sabemos el lenguaje máquina de un sistema, tan sólo tendremos que comprender la arquitectura particular de cada uno de ellos, para manejar correctamente sus dispositivos de E/S.

Las instrucciones que usa el 6502 son relativamente muy pocas, en comparación con otros procesadores de su generación, pero como podéis imaginar son más que suficientes, y usadas con ingenio, es posible realizar tareas de lo más complejas, como se puede comprobar sólo echando un vistazo a los numerosos programas hechos para este microprocesador.

Un procesador de 8 bits, está limitado a poder codificar 256 instrucciones diferentes, debido al ancho de su bus de datos. Aunque también se pueden codificar más instrucciones, creando opcodes de 16 bits, simplemente creando una lógica de procesamiento de varios bytes consecutivos, como hace el Z-80, el popular microchip de Zilog. Sin embargo, éste no fue el camino elegido por los ingenieros de los demás microprocesadores de esa generación, incluido el 6502 de MOS.

En el 6502, sólo tenemos códigos de operación de 8 bits, y no se usan las 256 combinaciones posibles para codificar instrucciones, tan sólo se han codificado 151, aunque también hay algunas instrucciones extra, escondidas, no soportadas oficialmente por las especificaciones del 6502, pero que ahi están y algunas pueden resultar útiles. Se verá en capitulos más avanzados.

Digo 151 instrucciones y en realidad no son tantas, pues muchas de esas instrucciones hacen lo mismo, pero tomando los datos a usar mediante almenos uno de 13 modos de direccionamiento distintos. ¿Modos de direccionamiento? Calma, ya lo veremos detenidamente, cuando toque.

De esos códigos de operación, 56 representan comandos únicos especializados en hacer una función determinada. De cara a su estudio, podemos dividirlos en varios grupos dependiendo de las funciones que realizan.

Hoy veremos el grupo de instrucciones destinados a cargar o almacenar datos desde o hacia la memoria.

Instrucciones de Carga / Almacenamiento de Datos



Estas instrucciones se encargarán como decia, de cargar o recuperar un dato en la memoria o hacia esta. Y siempre trabajaremos los datos usando la propia memoria interna de la CPU: Los registros.

Para cargar un dato siempre usaremos uno de los 3 registros (A, X, o Y) y al cargarlos (con un byte), algunas de las banderas del sistema serán modificadas reflejando la naturaleza del dato.

Las instrucciones de carga son:

LDA
LDX
LDY

LD es una abreviatura de LOAD (Carga), y como véis cada mnemónico se explica perfectamente.

En este grupo de instrucciones, se verán afectadas las banderas "Negative" y "Zero" (N y Z).

N será = 1, si el byte cargado es negativo, y cero si es positivo.

Z será = 1, si el byte cargado fue un cero, en caso contrario Z será igual a 0.

Para hacer referencia al byte que queremos cargar en el registro, debemos usar uno de los modos de direccionamiento válidos para cada instrucción (no todos están implementados para cada instrucción).

Por ejemplo si queremos introducir un número directamente en el registro, usaremos el Modo de Direccionamiento INMEDIATO, y esto, en ensamblador, lo expresaremos con el simbolo # precediendo al dato a cargar.

Ejemplo: Cargar el Acumulador con el valor $12

LDA #$12

Que en código máquina puro quedaria en memoria como:

A9 12

si queremos cargar un número, pero necesitamos que éste sea cogido de una determinada dirección, usaremos el Direccionamiento ABSOLUTO, o Direccionamiento de Página Cero, si la dirección de memoria es menor que 256, como precisamente asi sucede en este caso.

Ejemplo: Cargar el Registro A con el valor de la dirección de memoria $0012

LDA $0012

Que en código máquina puro quedaria en memoria como:

A5 12

si hubieramos empleado el direccionamiento Página Cero, o bien:

AD 12 00

en caso del direccionamiento absoluto. Fijaos que al usar éste último gastamos un byte adicional en memoria. Nótese tambien que internamente, en memoria, se almacena la dirección de forma invertida.

Cada modo de direccionamiento tiene un código de operación en lenguaje máquina distinto aún siendo la misma instrucción.

Aqui tenéis una tabla/resumen de lo visto hasta ahora:

Instrucciones de Carga del 6502:

LDA

 
Carga acumulador con memoria
(LoaD Accumulator with memory)
Operación: M => A
N Z C I D V
x x - - - -
 
                     * Añadir 1 si cruza límite de página.
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Inmediato lda # Oper $a9  2  2
Página Cero lda   Oper $a5  2  3
Página Cero, x lda   Oper, x $b5  2  4
Absoluto lda   Oper $ad  3  4
Absoluto, x lda   Oper, x $bd  3  4*
Absoluto, y lda   Oper, y $b9  3  4*
(Indirecto, x) lda  (Oper, x) $a1  2  6
(Indirecto), y lda  (Oper),y $b1  2  5*


LDX

 
Carga registro índice x con memoria
(LoaD index X with memory)
Operación: M => X
N Z C I D V
x x - - - -
 
                     * Añadir 1 si cruza límite de página.
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Inmediato ldx # Oper $a2  2  2
Página Cero ldx   Oper $a6  2  3
Página Cero, y ldx   Oper, y $b6  2  4
Absoluto ldx   Oper $ae  3  4
Absoluto, y ldx   Oper, y $be  3  4*


LDY

 
Carga registro índice y con memoria
(LoaD index Y with memory)
Operación: M => Y
N Z C I D V
x x - - - -
 
                     * Añadir 1 si cruza límite de página.
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Inmediato ldy # Oper $a0  2  2
Página Cero ldy   Oper $a4  2  3
Página Cero, x ldy   Oper, x $b4  2  4
Absoluto ldy   Oper $ac  3  4
Absoluto, x ldy   Oper, x $bc  3  4*


Las instrucciones de almacenamiento son:

STA
STX
STY

ST viene de STORE (Almacenar). Se usan de forma análoga a las instrucciones de carga, sólo que aqui un dato de un registro es almacenado en la memoria, en lugar de ser cargado. Otra diferencia es que ninguna bandera se ve afectada por estas operaciones, al contrario que sucede con las de carga.

Instrucciones de Almacenamiento del 6502:

STA

 
Almacena acumulador en memoria
(STore Accumulator in memory)
Operación: A => M
N Z C I D V
- - - - - -
 
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Página Cero sta   Oper $85  2  3
Página Cero, x sta   Oper, x $95  2  4
Absoluto sta   Oper $8d  3  4
Absoluto, x sta   Oper, x $9d  3  5
Absoluto, y sta   Oper, y $99  3  5
(Indirecto, x) sta  (Oper, x) $81  2  6
(Indirecto), y sta  (Oper),y $91  2  6


STX

 
Almacena registro índice x en memoria
(STore index X in memory)
Operación: X => M
N Z C I D V
- - - - - -
 
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Página Cero stx   Oper $86  2  3
Página Cero, y stx   Oper, y $96  2  4
Absoluto stx   Oper $8e  3  4


STY

 
Almacena registro índice y en memoria
(STore index Y in memory)
Operación: Y => M
N Z C I D V
- - - - - -
 
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Página Cero sty   Oper $84  2  3
Página Cero, x sty   Oper, x $94  2  4
Absoluto sty   Oper $8c  3  4


Como podéis comprobar en las 3 últimas fichas, no hay ninguna "X" que indique que la operación haya afectado las banderas (ó "flags") en la palabra de estado del procesador (registro P). ¡Recordad!, las instrucciones de almacenamiento no afectan para nada las banderas.

También es apreciable que en éste grupo de instrucciones, no se puede emplear el direccionamiento inmediato. Lo cual es totalmente lógico:

Recordad siempre que, para cargar un dato en un registro debemos cargarlo de algún lugar de la memoria, y éste podria ser perfectamente justo la siguiente dirección a la que apunta el registro PC (en esto consiste un direccionamiento inmediato), sin embargo, para almacenar un dato en la memoria, tenemos que ponerlo del contenido de un registro.

Un último punto a observar es que, si os fijáis en los dos grupos de instrucciones hasta aqui presentados, existen un mayor número de modos de direccionamiento para las instrucciones que trabajen con el acumulador. Esto es debido a que, como ya dije en los capitulos introductorios, éste registro es el más usado y el que soporta el peso de la mayor parte de operaciones, además de que varios modos de direccionamiento indexan una dirección de memoria, a través de X ó Y. A nivel de diseño, el rol que se le ha dado a los otros dos registros, los índice X e Y, es el de recorrer tablas, de ahi su nomenclatura también.

8 comentarios:

Jose Zanni dijo...

Gracias por este nuevo capítulo!

Lobogris dijo...

No hay de qué!

Bieno64 dijo...

Enorme. Que trabajazo y como te lo curras.

Lobogris dijo...

Me hace mucha ilusión, por eso hago todo lo que puedo.

Jose Zanni dijo...

Mi apoyo haciendo un PDF con todos los cursos sigue en pie!

Daniel Garcia Gonzalez dijo...

Hola buenas, por casualidad no conoceréis un modulador del 6502 para practicar el lenguaje ensamblador?,sería de mucha ayuda,gracias. :)

Josepzin Ungoliante dijo...

De hecho sí que he visto uno online... a ver...

Josepzin Ungoliante dijo...

¿Algo asi? http://www.6502asm.com/

Si es eso, busca "6502 online emulator" en Google

Publicar un comentario