Sexta Experiencia. Laboratorio de Estructuras de Computadores 02/2001 Simulador 8031. Para aprender a emplear el simulador, se propone compilar una serie de programas en lenguaje simbólico de máquina. En ellos se puede observar las formas empleadas para definir variables, y además algunos de los mnemónicos de las instrucciones para el procesador 8051. Uno de los objetivos de la experiencia es analizar, empleando el simulador, algunos segmentos de código assembler 8031, que tienen relación con el direccionamiento de variables. También se analiza la programación de condiciones y lazos de repetición. Otro objetivo es describir la misma situación que el programa assembler, pero empleando el lenguaje C. Luego se da el texto assembler de un programa que manipula variables y que implementa estructuras alternativas y de repetición. Para poder visualizar los cambios en cada una de las variables, debe ejecutarse el simulador. Luego se debe cargar el texto del programa, el cual debe estar escrito en un archivo de texto con extensión *.a51. Una vez cargado, en el menú debug, marcando la opción Start se puede empezar la simulación. Las casillas de verificación deben estar seteadas indicando que se va a efectuar una simulación en un procesador de tipo 8051 (virtual machine). Luego de realizar los pasos anteriormente expuestos, se observa que aparecen en pantalla dos ventanas adicionales; una nos muestra el código del programa, mientras la otra que se titula Main Registers despliega el estado actual del acumulador, PC, DPTR, entre otros. Para ejecutar el programa se debe presionar el botón GO de la barra de herramientas, pudiendo observarse el progreso de éste al activar la opción animate de la misma forma. También es posible variar la velocidad de ejecución del programa, deslizando el control ubicado en la barra de herramientas hacia la derecha para hacerlo más rápido o a la izquierda para lograr el efecto contrario. También existe la posibilidad de ejecutar paso a paso y colocar breakpoints. Si se quiere observar cualquier variable definida, basta con seleccionar en el menú View la opción Data Dump la que es capaz de mostrar completamente una zona de datos, la cual debe ser elegida desde el menú que aparece a continuación: XRAM = RAM externa (Se observan las direcciones desde 0x0000 hasta 0xFFFF) DATA = RAM interna desde la dirección 0x00 hasta 0x7F . SFR = RAM interna desde la dirección 0x80 hasta 0xFF. Bit = RAM interna en la zona de bits, entre la dirección 0x20 y 0x2F, aunque se lista desde 0x00 y 0xff , pero en bytes, donde 0x00 corresponde al primer bit del byte 0x20, y así sucesivamente. El procedimiento para agregar un watch es el siguiente: En el menú view se selecciona la opción symbols, desplegándose una lista con todas las variables que se están usando, tanto las definidas en Ram interna como externa del programa (esta lista puede ser ordenada tanto por tamaño como por nombre). Laboratorio de Estructuras de Computadores. Lab06 05-09-2001 1 Con las opciones que se muestran en la misma ventana es posible elegir una zona, siendo las alternativas similares a las ofrecidas por el menú data dump. Con el botón izquierdo del mouse se deben marcar las variables que se quieren observar, para luego presionar la opción add watch de la misma ventana. Para efectuar la traza de una variable, se marca la casilla de verificación trace en la ventana watch en la variable que deseamos seguir. Luego en el menú options se escoge trace, desplegándose una casilla de diálogo donde puede escogerse: - On changes: Para observar sólo los cambios. - Display relative time : Para observar el tiempo. - Reset trace before to run : Para resetear la traza antes de empezar a ejecutar. Entonces, en el menú view marcamos trace; apareciendo una ventana que nos muestra el tiempo, el valor de PC, la instrucción realizada y el progreso de la o las variables configuradas anteriormente. En caso de necesitar ejecutar el programa instrucción por instrucción (paso a paso), basta con presionar desde el teclado F7 ; o en su defecto , usar el botón step in de la barra de herramientas. Si se requiere detener la ejecución del programa en una instrucción determinada, agregamos un breakpoint; esto es, posicionarse en la línea de código correspondiente para presionar desde el teclado F5, o en su defecto con el botón derecho del mouse sobre la misma línea de programa correspondiente las opciones toogle flag... toogle breakpoint. Notar que de la misma forma puede detenerse el registro de la traza si seleccionamos toogle flag ... toogle trace (o F4). Efectuar programa para: a) Definir dos contantes, c1 y c2, en EEPROM y formar la suma lógica(or) de c1 y c2 en el acumulador. Definir dos variables, v1 y v2, en RAM externa, en direcciones 0100h y 0101h. Efectuar programa, que escriba 5 y 10 en v1 y v2; y luego formar la suma de v1 y v2 en el acumulador. Usar símbolos para las variables. Solución: programa ramexterna SEGMENT CODE SEGMENT XDATA RSEG programa org 0 jmp start ;define segmento programa ; segmento para XDATA RAM ; se cambia a segmento de código. ; define la dirección de la primera instrucción. ; org es una orden al compilador, no al procesador. ; se va a la primera instrucción. ;DEFINICIONES DE DATOS EN RAM EXTERNA RSEG ramexterna ; se cambia al segmento de dato externo org 100H ; define la primera dirección de memoria que se ; empleará para almacenar los datos (RAM externa). Laboratorio de Estructuras de Computadores. Lab06 05-09-2001 2 V1: V2: DS DS 1 1 ; definición e inicialización de variables. RSEG programa org 40h ; se vuelve a segmento texto . ; define la primera dirección que se empleará para ; almacenar datos en ROM. ;Las constantes en rom pueden ir antes del código, como en Pascal c1: db 01h ;define constante ;la constante c2 se define al final. start: ************** a = c1 or c2 mov dptr, #c1 ; dptr = &c1 clr a ; acumulador = 0 (offset cero). movc a, @a+dptr ; a = *(dptr+a) Se emplea movc mov r0, a ; r0 = c1 mov dptr, #c2 clr a movc a,@a+dptr ; a = c2 . orl a,r0 ; a = c2 | c1 nop ; Indica no operación. (no hace nada). ; ; ******************V1 =5; V2 = 10; a = V1+ V2. Variables en RAM mov dptr, #V1 ; dptr = &V1 mov a, #5 ; a = 5 Inmediata movx @dptr, a ; *dptr = a Se emplea movx. V1 = 5 inc dptr ; dptr++ Apunta a V2, ya que es adyacente a V1. mov a, #10 ; a = 10. movx @dptr, a ; V2 = 10. en este momento dptr apunta a V2. Y a tiene el valor de V2. mov dptr, #V2 ; dptr toma la dirección de v2. movx a, @dptr ; Ahora trae v2 desde la RAM EXTERNA al acum. mov r0, a ; Salva V2 en registro temporal mov dptr, #V1 ; dptr vuelve a tomar la dirección de v1. movx a, @dptr ; a = V1 add a, r0 ; a = V1 + V2 b) Definir dos bits, b1 y b2, en RAM interna. Efectuar programa, que intercambie los valores almacenados en b1 y b2. Solución: ;********************************** ;sea el byte 20h que está en la zona de bits (20h a 2fh). Sean: b1 = 20h.0 y b2 = 20h.1 ;se efectúa swap(20h.0 con 20h.1) se asume 21h.0 como temporal. ,En esta parte se van a definir 2 bits en la RAM interna, uno a continuación del otro, en el ;mismo byte, más un bit (en la misma memoria interna, pero en el byte siguiente ) que ;servirá de bit temporal. Ahora se ocupará el carry en vez del acumulador por estar dentro ;de la zona de 20-2f byte en la memoria. Laboratorio de Estructuras de Computadores. Lab06 05-09-2001 3 clr setb mov 20h.0 20h.1 c, 20h.0 mov mov mov mov mov 21h.0, c c, 20h.1 20h.0, c c, 21h.0 20h.1, c ; b0 = 0 . ; b1 = 1 ; El movimiento de bit al carry. c = b0 ; El carry pertenece a PSW. Program status word. ; temp = c ; c = b1 ; b0 = b1 ; c = temp ; b1 = c ; Otra forma. La diferencia con el anterior es que asigna símbolos(nombres) a los bits . b1 equ 20h.0 ; Con esta instrucción le asigna nombre al bit ; 20h.0. En este caso b1 representará a 20h.0. b2 tmp equ 20h.1 equ 21h.0 clr b1 setb b2 ; Ahora se hace lo mismo que la 1ª forma, pero con los nuevos nombres. Esta forma es más ; simple de manejar, pues se asocian las variables por sus nombres. mov c, b1 mov tmp, c mov c, b2 mov b1, c mov c, tmp mov b2, c c) Definir dos variables, v1 y v2, en RAM interna. Efectuar programa, que escriba 5 y 10 en v1 y v2; y luego formar la resta de v1 y v2 en el acumulador. Usar assembler simbólico. c1) En la zona 00h a 1Fh Zona de registros c2) En la zona 20h a 2Fh Zona de bits c3) En la zona 30h a 7Fh Zona ram interna (direccioanamiento directo) Solución: ;la zona de 00h a 1fh son los registros (32 registros divididos en cuatro grupos de ocho registros cada uno. Se puede emplear un grupo a la vez). ;sea v1 en r0, v2 en r1 mov r0, #5 ; coloca valor inmediato 5 en r0. mov r1, #10 ; r1= 10. mov a, r0 ; a = r0 subb a, r1 ; a = r0 – r1 ;la zona de bits de 20h a 27h se direcciona en forma directa v12 equ 20h ; asigna a v12 el byte 20h de la zona de bits. (se utiliza un byte Laboratorio de Estructuras de Computadores. Lab06 05-09-2001 4 ; completo, a pesar de que esta zona permite manipular bit por bit). 21h mov v12, #5 ; asigna valor 5 a v12. mov v22, #10 ;asigna valor 10 a v22. mov a, v12 clr c ; esta modificación la implementamos para obtener el resultado correcto de la operación de resta. El resultado es un número negativo, por ello el bit carry del PSW queda con valor uno desde la anterior operación que haya entregado un resultado semejante y siempre que no sea reseteado. subb a,v22 ; hace la resta v12 – v22. Y deja el resultado en ACC. ;la zona de borrador scratch pad, también puede direccionarse en forma directa v13 equ 30h ; Se definen variables en la zona de direccionamiento directo; indirecto. En este caso, se accede a las variables en forma directa. v23 equ 31h mov v13, #5 mov v23, #10 mov a, v13 clr c ; clear c subb a,v23 v22 equ **************************** d) Programar: while ( R2 >= R4 ) { if (R5<R6) R4++; else R2= R1-1; R2--; } ;************************Programación del while. mov r2, #2 ;se asigna valores, para probar funcionamiento. mov r4, #3 mov r1, #3 mov r5, #5 mov r6, #6 clr c while: mov a, r2 ; puesto que en r2 hay un valor, lo traspasa al acumulador, subb a, r4 ; a = r2 – r4 > 0 si r2 >=r4 y el bit carry de la palabra de estado es cero. Si el resultado es menor que cero, el bit mencionado es uno. jc fuera ; si r2>= r4 no hay c. Si r2 es mayor que r4, carry es cero y na hay bifurcación. ; Jc jump si carry es uno. Jnc jump si carry es cero. ;bloque de repetición mov a, r5 subb a, r6 ; a = r5 – r6 jnc els ; r5>=r6 no hay c, entonces r5<r6 carry Laboratorio de Estructuras de Computadores. Lab06 05-09-2001 5 inc jmp mov dec mov dec jmp els: endfi: r4 fi a, r1 a r2, a r2 while ;incrementa r4 en uno. ; termina el if. ; a-- ; repete el lazo. fuera: Hasta aquí, la forma de programación simbólica de la maquina 8051 es similar a como se programaba para MIPS, en cuanto a las etiquetas, saltos, difiriendo en aspectos como las operaciones de suma, resta y los direccionamientos y forma de acceder a los datos. ;********************************** forever: jmp forever ; es un salto sobre sí mismo. Se repite indefinidamente ;deja en estado de halt (pero en ejecución) al procesador ;no existe instrucción que detenga al 8051 ;las constantes pueden ir después del código, como en C. c2: db 10h ;***************************************************** end Mostrar en el simulador las variables, y que se efectúan las operaciones programadas. Si la casilla Options- L51 – Linker – Intel hex está marcada se genera código Intel hexadecimal que puede cargarse en la EPROM que contiene el texto. e) Compilar el siguiente programa y efectuar su simulación, viendo la puerta uno. Observando como cambian de estado los bits de la puerta. #include <reg51.h> void main (void) { for(; ; ) { P1= 0x0; P1 = 0xFF;} } Lo mismo puede lograrse en assembler con PROG SEGMENT CODE RSEG PROG start: mov P1,#00 mov P1,#255 jmp start END Laboratorio de Estructuras de Computadores. Lab06 05-09-2001 6