Una solución puede ser usar desplazamientos hacia la izquierda. Cada desplazamiento de un bit a la izquierda multiplica por dos el contenido de un registro. De este modo, si queremos multiplicar por 8 el registro B, podemos hacerlo tan fácil como:
lslb ; B*2
lslb ; B*2*2 = B*4
lslb ; B*2*2*2 = B*8
Es una pena que no podamos multiplicar así de fácil por otros
valores, ¿no? Bueno, pues no es del todo cierto. Imaginemos que
queremos multiplicar B por 5, esto es, B*5. Pero B*5 = B*(4+1) =
B*4 + B. Luego no es tan difícil:
stb temp ; guardamos B
lslb ; B*2
lslb ; B*4
addb temp ; B*4+B = 5*B
Vamos a intentar aplicar estas instrucciones en un ejemplo que saca por la pantalla el contenido del registro A, en hexadecimal. Tendremos que aguzar el ingenio, pues apenas hemos visto todavía instrucciones en ensamblador. El programa lo mejoraremos bastante en sucesivas sesiones:
.area PROG (ABS)
; definimos una constante
fin .equ 0xFF01
pantalla .equ 0xFF00
.org 0x100
.globl programa
temp: .word 0 ; una variable temporal
programa:
lda #28 ; pongamos este nUmero como prueba
; imprimamos 0x
ldb #'0
stb pantalla
ldb #'x
stb pantalla
; primero imprimamos la primera cifra hexadecimal
tfr a,b
lsrb
lsrb
lsrb
lsrb ; en B estA la primera cifra, de 0 a 15
std temp
clra
addb #246
adca #0 ; en A hay un 1 si la primera cifra es mayor o igual que 10
ldb #'A-'9-1
mul
addb temp+1
addb #'0
stb pantalla
; ahora imprimimos la segunda cifra hexadecimal
ldb temp
lslb
lslb
lslb
lslb
lsrb
lsrb
lsrb
lsrb ; en B estA la segunda cifra, de 0 a 15
std temp
clra
addb #246
adca #0 ; en A hay un 1 si la segunda cifra es mayor o igual que 10
ldb #'A-'9-1
mul
addb temp+1
addb #'0
stb pantalla
; imprimamos un salto de lInea al final
ldb #'\n
stb pantalla
; el programa acaba
clra
sta fin
.org 0xFFFE ; vector de RESET
.word programa
Hagamos un poco la luz en semejante embrollo. La salida del programa
si cargamos A con 28, como en el ejemplo, ha de ser dicho número
en hexadecimal: 0x1C. La primera parte es muy sencilla, pues solamente
consiste en imprimir un cero y una equis. No obstante, prestad atención
a que si queremos imprimir el carácter '0' en la
pantalla no cargamos el registro con cero sino con el código ASCII del
carácter '0', que es 48. O eso, o que haga
el ensamblador el trabajo sucio y usamos, como en el ejemplo, el
apóstrofo que aparece.
A continuación vamos a imprimir la primera cifra hexadecimal.
Vimos en Computadores I que cada cifra hexadecimal se corresponde con
cuatro bits. Luego habrá en un número de 8 bits dos
cifras hexadecimales. La primera de ellas se corresponde con los cuatro
bits más significativos. Para quedarnos solo con ellos, usamos
cuatro instrucciones de desplazamiento lógico a la derecha
(LSR).
Después de esto, tenemos en B la primera cifra hexadecimal o, quizá hablando con más propiedad, un número de 0 a 15 que representa la primera cifra hexadecimal del número. Todo sería más fácil si no fuera por el pequeño detalle de que tenemos que escribir el código ASCII en la dirección asociada con la pantalla para que aparezca la cifra hexadecimal correspondiente. Observemos la parte de la tabla ASCII que nos interesa, con sus valores:
Queda claro, pues, que debemos imprimir 48 si B vale 0, 49 si vale uno, ..., 57 si B vale 9 y ... 65 si B vale 10, 66 si B vale 11, ... 70 si B vale 15. Como aún no sabemos cómo poner condiciones, seguimos la siguiente estrategia:
std temp
clra
addb #246
adca #0 ; en A hay un 1 si la primera cifra es mayor o igual que 10
ldb #'A-'9-1
mul
addb temp+1
addb #'0
'A-'9-1 = 65-57-1 = 7. El
resultado se ha quedado en D, cuya parte baja es B. Por consiguiente,
en este punto B tiene 7 si B valía 10 o más y cero en
caso contrarioLa segunda parte del código es igual que la primera. Solamente que usamos la parte baja de A en lugar de la parte alta. Para dejar a cero la parte alta, primero desplazamos cuatro bits a la izquierda y, luego, desplazamos otros cuatro, de modo lógico, a la derecha.
Como habréis podido observar, un programa en ensamblador puede ser casi imposible de descifrar, incluso en los casos más sencillos. Es por eso fundamental que documentéis muy bien vuestros programas. Según vayamos avanzando en las sesiones, volveremos a este código varias veces para ver cómo se va simplificando.
Más adelante en la carrera estudiaréis un tipo de procesadores más moderno (los RISCs) en los que, en ocasiones, se aplican técnicas parecidas a la que hemos estudiado para evitar las realización de condiciones, en las que este tipo de procesadores pierden mucha eficiencia.
clra
addb #246
adca #0 ; en A hay un 1 si la primera cifra es mayor o igual que 10
sumar primero 246 a B y, luego, limpiar A y añadir el bit de acarreo?
Uno de los problemas de trabajar en BCD es que, como vimos en la teoría de Computadores I, la suma/resta normal no nos funciona bien. En este punto acude en nuestra ayuda la instrucción del 6809 DAA (Decimal Adjustment for A). Se usa del siguiente modo:
; Vamos a sumar 6 y 7 en BCD
lda #0x06
adda #0x07 ; En A hay ahora 0xD (es decir, 13)
daa ; DespuEs del ajuste decimal, en A hay 0x13, 13 en BCD
El 6809, como todos los procesadores, es un autómata que,
una vez ejecutadas las instrucciones no recuerda nada más que lo
que ha quedado en los registros o la memoria. ¿Cómo sabe
el 6809 qué es lo que tiene que hacer con A para ajustarlo a BCD?
El truco reside en que usa internamente el flag H cada vez que hace una
suma. Desafortunadamente, el 6809 no está preparado para
hacer ajustes decimales en las restas.
Desafortunadamente, en muchas versiones del simulador m6809-run
usado en estas prácticas hay un error que hace que la
instrucción DAA no funcione correctamente. En caso de ser necesaria
para el desarrollo de algún programa, se puede usar el código
que aparece aquí.
37 17 37+17=54
| Cifra original: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| Cambiar por: | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Veamos un ejemplo: pretendemos restar, en dos cifras y en decimal, 27-13. Hacemos el opuesto del 13. Primer paso, sustituir las cifras según la tabla anterior: 86. Ahora, sumar 1: 87. 87 es el equivalente a -13, pues. Sumamos ya directamente: 27+87=114. Despreciamos el primer 1, pues estamos trabajando con dos cifras y nos queda el resultado correcto: 27-13=14.
ROLxRORxLSLx y ASLxLSRxASRxROL, ROR, LSL, ASL, LSR y ASRDAAlscdrmmancatecho $?