Objetivo:
Hacer uso de las distintas instrucciones
para el HCS12 en el programa code warrior, con el fin de aplicar y entender
cada uno de ellos.
Material
y Equipo:
Ø Computadora
personal
Ø Programa:
Code Warrior
Marco
Teórico:
El procesador o CPU. Es
el elemento más importante del microcontrolador y determina sus principales
características, tanto a nivel hardware como software.
Se encarga de
direccionar la memoria de instrucciones, recibir el código OP de la instrucción
en curso, su decodificación y la ejecución de la operación que implica la
instrucción, así como la búsqueda de los operandos y el almacenamiento del
resultado. A continuación se explica de manera general como está formado un
procesador. La función esencial de un procesador se describe en lo que se
conoce como “ciclo de ejecución” consiste en 1.Traer una instrucción de
la Memoria, 2.
Decodificar la instrucción y 3. Ejecutar la instrucción, el ciclo
continúa indefinidamente. El primer paso se realiza en varias etapas, puesto
que tiene que acceder a la memoria para leer la instrucción, esto requiere
enviar la dirección donde se encuentra la instrucción, las señales de lectura y
selección de la memoria se envían mediante un grupo de señales que forman el
bus de control.
Desarrollo:
Instrucciones de carga y
almacenamiento.
Las instrucciones de carga
copian el contenido de una localidad de memoria a un acumulador o registro,
nótese que el contenido de la memoria no cambia debido a la operación de carga.
En cambio las instrucciones de almacenamiento copian lo que se encuentra en un acumulador
o registro del CPU a una localidad de memoria sin alterar el valor que se
encuentre en el registro o acumulador del CPU.
Las instrucciones de carga
se representan con las iniciales LD que quiere decir Load, la segunda parte del
mnemónico depende del acumulador o registro que se esté utilizando, ya sea el
acumulador A, B o los registros X, Y o SP (de los cuales SP no es recomendable
usar si no se tiene suficiente experiencia programando) que se representan de
la siguiente manera LDAA, LDAB, LDD, LDX, LDY, LDS.
Para tener un concepto más
detallado a continuación se vera una tabla que muestra los códigos objetos que
se generan para el acumulador A cuando se le carga el contenido de una
localidad de memoria, nótese que este código varía dependiendo del modo de
direccionamiento que se esté usando.
Para ejemplificar esto, veamos
ahora como en el simulador de code warrior se representa el código objeto en
los distintos acumuladores y registros.
Para las instrucciones de
almacenamiento al igual que las instrucciones de carga se reprecentan con un
mnemónico, el cual inicia con ST y dependiendo del acumulador o registro es la
terminación de este, las cuales son STAA, STAB, STD, STX, STY, STS (del cual no
se recomienda usar el STS sin alta experiencia como programador). Como demostración a
continuación se mostrara una tabla con los códigos objetos de almacenamiento
para el acumulador A.
Si somos observadores
notaremos que en diferencia con la tabla de carga, la de almacenamiento no se
puede usar el modo de direccionamiento inmediato, ya que si hacemos uso del
sentido común nos daremos cuenta que no se puede guardar a un valor desde un
acumulador o registro, sino solamente a localidades de memoria.
Para ilustrar esto, se
mostrara como se almaceno desde los registros a localidades de memoria:
Transferencia, intercambio y extensión de signo.
La instrucción de transferencia copia el contendió de un
acumulador o registro a el contenido de otro acumulador o registro. Se pueden hacer transferencias de
A a B usando la instrucción TAB, ó de B a A usando la instrucción TBA. También
hay una instrucción que podría decirse que es universal dentro de las
instrucciones de transferencias, ya que no necesita un mnemónico relacionado
con algún la letra de acumulador o registro, este mnemónico es TFR, capaz de transferir
(copiar) de cualquier acumulador o registro a cualquier otro acumulador o
registro no importando la cantidad de bits que se quieran transferir.
En comparación con las instrucciones de transferencia, la
instrucción EXG intercambia los valores de ambos acumuladores o registros, por
ejemplo si en A<=$20 y en B<=30, después de usar la instrucción EXG ahora
los acumuladores tendrán A<=30 y en B<=20. Hay que tomar en cuenta que si
queremos intercambia un dato de 16 bits a un acumulador de solo 8 bits, se
perderá la parte alta del dato de 16 bits, en cambio si queremos intercambiar
un dato de 8 bits a un registro de 16
bits, se hará a la parte baja del registro llenando con ceros la parte más alta
de este registro.
Para la extensión de signo, hay una instrucción especial
SEX, ya que cuando transferimos o intercambiamos de una acumulador de 8 bits a
un registro de 16 bits este dato quede en la parte baja del registro (como ya
se explicó anteriormente), entonces si este dato es negativo al momento de que
este en un registro de 16 bits se hará positivo ya que el ultimo bit es el que
define si es positivo o negativo el dato (1-> negativo, 0-> positivo).
Para hacer el cambio de signo se utiliza la instrucción SEX, la cual rellena
con 1’s en lugar de 0’s los otros 8 bits del registro de 16 bits, y de esta
manera el dato que anteriormente era de 8 bits y se transfirió o intercambio al
de 16 bits ya conserve el signo negativo en caso de que lo haya sido.
:
Transferencia y extensión de signo
Sumas y restas.
La suma entre registros y
registro, y registro y memora de 8 y 16 bits con y sin signo. También hay
instrucciones de suma que suman el bit de acarreo (carry) en el CCR. Al igual
que en la suma también en la resta se puede hacer entre registro y registro y
registro y memoria de 8 y 16 bits con signo y sin signo. Y al igual que en las
sumas se usa un bit de acarreo del CCR, pero en esta ocasión nos sirve como
pedir prestado (borrow).
Como se mencionó anteriormente,
se considera un bit del CCR para realizar la suma o resta en algún registro o
memoria, además de que se alteran los registros de las banderas medio acarreo
(H), signo (N), cero (z), sobrecupo (V) y por supuesto el acarreo (C). Algunas
de estas instrucciones son solamente inherentes como la suma y resta entre
registros, en cambio la suma y resta entre un registro y memoria los modo de
direccionamiento son los complementarios al inherente, es decir, aplican el resto de los modos de
direccionamiento. A continuación se mostrara la lo anterior dicho de los modos
de direccionamiento.
Ejemplificando la suma entre
registros se realiza una suma entre registros A + B ($70 + $90) y el resultado
de esta suma es $100, en el cual en el procesador solo nos dará el resultado de
$00, ya que se queda cargado el resultado de esta operación en acumulador A (y
este es de 8 bits), entonces se queda el resultado de $00 ahí, pero se activa la
bandera de acarreo y esto nos indica que el resultado de esta operación es un
número mayor a 8 bits.
Ahora, para la suma de un
registro con memoria, al igual que en el ejemplo anterior se usa el modo de
direccionamiento inmediato. Hay que notar que el ejemplo anterior para cargar
los datos que se usaron se utilizó el modo inmediato, pero solo para cargar el
dato, no para realizar la operación, como ya se había explicado anteriormente
en la suma o resta entre registros solo se puede usar el modo inherente. Ahora,
para el siguiente ejemplo de suma que se realizara entre registro y memoria se
suma al $00 un $FF, entonces esto nos dará como resultado $FF, pero hay que
notar el para esta instrucción se toma en cuenta el carreo y en caso de que el
bit este activado debido al resultado de la suma anterior, entonces se le suma
1 al resultado de la operación, es decir, $FF+1 y el resultado efectivo de esta
suma (por así llamarlo) es $00 y se vuelva a activar el bit de acarreo, porque
el resultado real es $100.
Para el caso de la resta
ocurre lo mismo, pero en lugar de ser acarro es pedir prestado (carry/borrow).
Instrucciones BCD
Las instrucciones BCD, son
usadas para ajustar un número hexadecimal a un número decimal, una de las
principales condiciones es que los números en hexadecimal no contengan letras,
es decir, que los operandos no sean mayores a $9. Para el uso de ajuste decimal
se usan las instrucciones de suma que consideran el medio acarreo (H) del CCR,
y después se ajusta el resultado de la operación usando la instrucción DAA. Para
ejemplificar esto, se realizara una suma entre un registro y memoria después,
como el resultado está en el registro B se cambia al registro A para poder
realizar el juste decimal.
Instrucciones de decrementos
e incrementos.
Estas instrucciones pueden
ser usadas para registros de 8 y 16 bits. Estas instrucciones se usan o aplican
para realizar contadores ascendentes o descendentes, ya que el bit de acarreo
(C) en el CCR no afecta. A continuación se mostrara una tabla de los distintos
tipos de decrementos e incrementos.
Hay que destacar que estas
instrucciones son inherentes, si se desea guardar en una localidad de memoria
como por ejemplo, una tabla se pueden usar varios métodos distintos, pero en
si, estas instrucciones son puramente inherentes.
A continuación se presentara
una aplicación de un contador y llenado de una tabla con los resultados.
En este ejemplo primero se
carga la dirección de la tabla (que para este caso está en el origen de la RAM)
después el valor de inicio $FF, y por sentido común sabremos que será un
contador descendente. Después se guarda en cierta localidad de memoria, que
para este caso es la primera localidad de la dirección de la tabla, y por
último se incrementa el índice de la tabla, por lo tanto cambia de dirección
después de haber guardado el valor, y posteriormente decrementamos 1 al valor
inicial provocando que este vaya contando descendentemente, y como dije
anteriormente guardando los datos, generando una tabla de 255 datos.
Instrucciones de
comparaciones:
Estas instrucciones se
utilizan para hacer una prueba a un registro o a una localidad de memoria, la
manera de comparar es haciendo una resta entre lo que se dece comparar, pero a
diferencia de las instrucciones de resta en esta resta que se realiza en la
comparación no se genera resultado alguno, solo se afectan las banderas del
CCR. Estas instrucciones son usualmente usadas para establecer las condiciones
de para las instrucciones de bifurcación.
Como ejemplo de esto, se realiza
una comparación un cero de un registro, para esto se usa la instrucción de
TSTA, la cual compara con cero la localidad de memoria A, esto con el fin de
activar la bandera Z, en caso de que sea igual a cero lo que se encuentre
cargado en el acumulador A. se hace una bifurcación o salta a otra sección de
programa.
Operaciones lógicas.
Para las operaciones lógicas
booleanas se realizan operaciones entre acumuladores, memoria e incluso el CCR.
Las operaciones lógicas que se realizan son AND, OR y OR exclusiva.
A continuación se mostrara
la tabla de las distintas instrucciones booleanas que se pueden usar.
Como ejemplo de esto, se
realiza una operación entre el acumulador A y una localidad de memoria (en modo
inmediato) de la cual se realizara la operación booleana AND, donde el
resultado se quedara cargado en el registro A, notemos que esta instrucción se
puede usar como enmascaramiento de bits,de manera que solo los bits que sean
1’s tanto en la memoria como en el registro son los que se mantendrán iguales
en el resultado como se muestra en la tabla de verdad de AND.
Ahora, para demostrar la
compuerta OR, se carga otro valor en modo inmediato y el resultado de igual
manera se mantiene en A, pero ahora en donde sea que haya 1’s tanto en A como
en memoria se mantendrá en 1, no importando si en A o memoria había un cero
como se muestra en la tabla de la verdad de OR.
Y por último se le aplica la
instrucción XOR, para que los bits que sean diferentes se mantengan en 1’s y
los bits que son iguales se hagan 0’s, como se muestra en la tabla de verdad de
XOR.
Limpiar, complementar y
negar.
Las instrucciones de limpieza
sirven para poner en cero localidades de memoria , acumuladores y algunos bits
del CCR. Como por ejemplo CLC que consiste en mandar un 0 a bit de acarreo (C)
del CCR, el CLR hace lo mismo pero para una localidad e memoria y el CLRA para el acumulador A.
Las instrucciones de
complemento, dan como resultado el valor que falta para completar el valor
máximo de un acumulador o memoria, es decir si es de 8 bits (FF) se realiza una
resta entre ese valor y lo que se tiene en el Acumulador o localidad de
memoria, entonces el resultado es lo que falta para obtener valor del byte.
Un ejemplo sencillo es: el complemento
de 0, si este es de 8 bits, entonces el valor máximo es FF, lo que se hace es
una resta FF-0 el resultado es FF, y ese es el complemento de 0, es decir lo
que le falta para llegar a su valor máximo.
La negación es el
complemento de 2, algo muy similar a lo realizado anteriormente, al diferencia
está en que se le suma 1 después de haber complementado A continuación se
mostrara la tabla de las instrucciones:
Para ejemplificar lo
anterior dicho se hace un programa muy sencillo.
Primero se borra lo que está
en B con la instrucción de limpiar, después se complementa y el resultado es FF
(como se explicó anteriormente), y por último se hace la negación que es el
complemento de 2, el cual consiste en obtener el complemento y después sumarle
1 como se muestra a continuación.
Multiplicación y división.
Dentro de las instrucciones
de multiplicaciones y división, hay operaciones con signo y sin signo. Las
operaciones de 8 bits tienen un producto de 16 bits y las multiplicaciones de
16 bits tienen productos de 32 bits. Para las divisiones, ocurre algo similar,
pero inverso, ya que si se tiene un dividendo de 16 bits y un divisor de 8 bits y se produce un
consiente y residuo de 8 bits cada uno, pero también hay divisiones con un
dividendo de 32 bits y un divisor de 16 bits y estos tiene un cociente y
residuo de 16 bits cada uno. Para ver esto más claro se mostrara la tabla de
instrucciones y se podrá apreciar que registros se concatenan para formas 32
bits tanto en multiplicaciones como en divisiones.
Como se puede apreciar en la
tabla, para hacer uso de multiplicaciones de 32 bits se usa como producto el
registro Y y D para formar un producto de 32 bits, de tal manera que en el Y
queda la parte alta del producto y en D la parte baja del producto. Para el
dividendo de las divisiones ocurre exactamente igual, se usa el registro Y para
la parte más alta y el registro D para la parte más baja. A continuación se
verá un ejemplo para tener esto más claro.
Para la multiplicación con
signo ocurre exactamente lo mismo, solo hay que tomar en cuenta que el ultimo
bit es quien definirá el signo del producto. Ahora, como se comentó
anteriormente para la división y división con signo y división fraccionaria se hace algo similar con lo que sucedió con el
producto de la multiplicación, solo que en esta ocasión ocurre eso para los
dividendos, lo cual es concatenar 2 registros de 16 bits para crear un
dividendo de 32 bits como se muestra a continuación.
Instrucciones de
corrimientos y rotaciones.
En estas instrucciones hay corrimientos
para todos los registros y acumuladores, y también para memoria. Para todos los
desplazamientos y rotaciones pasan a través del bit de acarreo (C) del CCR,
pero la diferencia es que para los corrimientos los bits recorridos se
remplazan por ceros, en cambio en rotación los bits recorridos se remplazan por
los lo bits que van saliendo por el bit de acarreo (C), claro tomando en cuenta
que el primer bit rotado es el bit de acarreo, pero no hay que olvidar que el
ultimo bit rotado se queda en el bit de acarreo (C).
Como ejemplo de esto tenemos
un $3C y corremos a la derecha el valor, entonces cada vez que se corra se
rellenaran con ceros los bits que se recorrieron. En cambio sí se rota a la
derecha el bit de acarreo, aunque no haya habido nada en ese acumulador si se
le asigna un 1 al bit de acarreo cada vez que se haga una rotación se llena de
1’s el acumulador.
Este pequeño programa recorre el bit hacia la derecha 8
veces dejando en cero lo que hay en el acumulador a.
En este programa ocurre lo contrario rotando el bit de
acarreo asignándole siempre 1 al bit de acarreo antes de rotarlo hacia la
izquierda dejando puros el valor final del registro en 1’s.
Conclusiones:
Durante la práctica se aprendió
en funcionamiento de cada una de las instrucciones del HCS12, además de ver los
diferentes modos de direccionamiento que se utilizan en cada una de las
instrucciones haciendo sencillos programas demostrativos.
Bibliografía:
ü El Microcontrolador HCS12
TutorialHC12:http://caos.uab.es/~dlugones/courses_archivos/HC12tutorial.pdf
ü HCS12_CPU
www.freescale.com ó http://michelletorres.mx/modos-de-direccionamiento/#.UwbKDPl5O1U
ü Apuntes vistos en clase
Escritos por alumno de ingeniería en electrónica : Juan Daniel Flores
Gutiérrez
Hola, tengo que realizar un programa que agarre 2 datos de 8 bits almacenados en memoria, luego
ResponderEliminartome la parte más significativa de uno y la menos significativa del otro y las guarde
como resultado, ¿cuales son los comandos que deberia de utilizar?
Puedes usar el registro D, en dicho registro está dividido en 2 secciones de 8 bits, en A y B
ResponderEliminar