CURSO de ASM 6502 [NES]

Modos de direccionamiento

Por DaRKWiZaRDX

Aquí estoy de nuevo (para el lamento de tantos... xDDD), esta vez la lección será bastante corta, ya que se trata de un tema bastante simple, pero MUY importante.
Se trata de los modos de direccionamiento, que son las formas que tiene el programador de decirle al procesador dónde leer/escribir, de forma que el procesador no termine leyendo o escribiendo datos donde no debe. de hecho, en el poco código que hemos visto hasta ahora ya vimos algunos modos de direccionamiento:

LDA #$00    ; carga el valor $00 en A

Este es un modo de direccionamiento, el más simple de todos, denominado "Immediate", carga un valor dado por el programador (una constante) en un registro, sea A, X o Y.

Veámoslos todos juntos:

MODO DE DIRECCIONAMIENTO

EJEMPLO

DESCRIPCIÓN

Immediate LDA #$80 El programador le da un valor constante. No debe leer de memoria.
Accumulator ASL A Actúa siempre sobre el acumulador (A).
Implied SEI No recibe parámetros, la instrucción de por sí sabe sobre qué registros actuar (si es que actúa sobre alguno).
Zero Page LDA $80 Actúa sobre el valor contenido en un offset de 8bits (1 byte).
Absolute LDA $6100 Actúa sobre el valor contenido en un offset de 16bits (2 bytes)
Zero Page indexed X LDA $80,X Actúa sobre el valor contenido en un offset de 8bits + X.
Zero Page indexed Y LDA $80,Y Actúa sobre el valor contenido en un offset de 8bits + Y.
Absolute indexed X LDA $6100,X Actúa sobre el valor contenido en un offset de 16bits + X.
Absolute indexed Y LDA $6100,Y Actúa sobre el valor contenido en un offset de 16bits + Y.
Indexed indirect LDA ($80,X) Ver abajo.
Indirect indexed LDA ($80),Y Ver abajo.
Indirect absolute JMP ($6100) Ver abajo.
Relative BRA $FE (je) Ver abajo.

Modos de direccionamiento indexados:

Como verás hay cuatro modos que usan indexado, ¿Qué significa esto? Que además de utilizar la dirección que le da el programador para leer/escribir, le sumarán a esa dirección el valor de un registro (sea X o Y) y usarán el resultado de esa cuenta para saber en qué dirección realmente van a leer/escribir. Veamos un ejemplo:

Supongamos que quiero poner un valor (supongamos que $10) en 10 direcciones distintas, esto podría ser que estoy "limpiando" memoria que usaré luego. El valor lo pondré en el acumulador y lo guardaré en 10 direcciones comenzando en $200.

Podría hacer:

LDA #$10    ;cargamos el valor en A
STA $200    ;lo guardamos en la primera
STA $201    ;en la segunda
STA $202    ;etc.
STA $203
STA $204
STA $205
STA $206
STA $207
STA $208
STA $209    ;en la décima

Pero haciendo esto ocuparíamos MUCHÍSIMO espacio de la ROM, cuando es mucho más simple hacer una rutina con el modo de direccionamiento indexado.

Al usar indexado sumaremos al offset (que en este ejemplo comienza en $200) el valor actual del registro X o Y. Es decir que si por ejemplo tenemos en el registro X el valor $16, si hacemos algo como "LDA $10,X" la operación real sería "LDA $10+$16", por lo que realmente no estaríamos leyendo de la dirección de memoria $10 sino de la $26.
Pero sigamos entonces con nuestro ejemplo, sabiendo ya lo del indexado haremos lo siguiente:

LDA #$10     ;el valor a guardar
LDX #$00     ;X comienza en 0, será nuestro contador
repetir:
STA $200,X   ;guardamos en $200+X
INX          ;instrucción que incrementa X por 1
CPX #10      ;comparamos X con #10 (decimal) (esto lo veremos en detalle más adelante)
BNE repetir  ;si no es igual vuelve al principio (también lo veremos más adelante)

Cada vez que se llega al INX se incrementa X por 1, y el "CPX #$10 | BNE repetir" verifica si ya se llegó a 10 (nota que no puse #$10 sino #10, ya que no es un valor hexadecimal sino uno decimal).

Modos de direccionamiento indirectos:

Estos modos no actúan directamente sobre el parámetro que les da el programador, sino sobre el que está contenido EN LA DIRECCIÓN QUE LE DA EL PROGRAMADOR. Por ejemplo:

LDX #$00
LDA ($80,X)

Esta instrucción no leerá el valor que está en $80 y lo guardará en el acumulador (eso lo haría LDA $80), lo que hará esta instrucción será sumar el valor del registro X a $80, lo que da como resultado $80, y entonces leer un valor de 16bits (2 bytes) de $80 - $81, y usar ese valor para determinar el offset del que debe leer.
Si en el ejemplo anterior en $80-$81 estuviera almacenado (en orden invertido, claro) $6589 entonces LDA ($80) sería igual a LDA $6589.

La razón por la que usaríamos LDA ($80) y no LDA $6589 es porque podríamos volver a utilizar el LDA ($80) para leer de OTRA posición de memoria simplemente cambiando el contenido de $80-$81, lo que no podríamos hacer si hubiéramos utilizado LDA $6589.

Modo de direccionamiento indirecto indexado:

LDA ($80),Y

Lo que hace este modo de direccionamiento es leer un valor de 16bits de $80-$81, supongamos que en este caso el valor que leyó era $6589, entonces a ese número le suma el valor del índice Y (supongamos que sea $14), y el valor que se cargue en A será el contenido en la dirección $659D ($6589 + $14). Sólo puede usarse como índice en este modo de direccionamiento el registro Y.

Modo de direccionamiento indexado indirecto:

LDA ($80,X)

En este modo de direccionamiento se suma el operando (en este caso es $80) más el contenido del registro X (supongamos que es $14), entonces la operación sería LDA ($94), por lo tanto, el valor que se cargará en A será el contenido en el valor que tenga $94 (si el offset $94 contiene $18, entonces $18 se carga en A). Sólo puede usarse como índice en este modo de direccionamiento el registro X.

Modos de direccionamiento relativos:

Los modos de direccionamiento se basan en la posición actual del PC (el registro que contiene el offset de la instrucción que se está por ejecutar), al valor que le da el programador se le suma 1 para que un BRA $00 no salte hacia sí mismo. Por ejemplo:

LDA #$14
STA $86
BRA $02     ; este #$02 + 1 da #$03, lo que saltea el LDX #$20
LDX #$20
STX $87

Como señalé en el comentario, en el BRA (instrucción para saltar, que lo hace siempre, sin condición), sabemos que si el parámetro hubiera sido 0 habría seguido hacia el LDX #$20, ya que siempre se le suma 1 al parámetro, pero como el parámetro es #$02, y 2 + 1 = 3, entonces sabemos que el branch adelantará 3 bytes, lo que lo dejará en el STX $87. Espero que haya quedado claro, la verdad es que es bastante simple, pero por mi forma de explicar...

Pero igualmente cuando escribas código probablemente usarás etiquetas. Por ejemplo:

LDA #$00
TAX
loop:
STA $4000,X
INX
CPX #$20
BNE loop
<sigue el código>    ; por si no lo entendiste este código llena con $00 una zona de 32 bytes (20 hex) a partir de $4000.

Como ves en lugar de poner un número puedes poner una etiqueta, todos los ensambladores que conozco soportan etiquetas, si el tuyo no lo hace, pues cambia de ensamblador :P

Vamos, que falta poco, una lección más y ya terminamos xD

<< Anterior - Siguiente >>