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*8Es 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 programaHagamos 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 10sumar 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 BCDEl 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.
ROLx
RORx
LSLx
y ASLx
LSRx
ASRx
ROL, ROR, LSL, ASL, LSR y ASR
DAA
ls
cd
rm
man
cat
echo $?