martes, 15 de abril de 2014

Manejo de instrucciones básicas del procesador HCS12 de Freescale

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.

Intercambio de datos:



: 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