Diferencia entre revisiones de «La pila en MC9S08Q128 y su uso»

De Wikitronica
Saltar a: navegación, buscar
(Advertencias al momento de usar la pila)
(Advertencias al momento de usar la pila)
Línea 112: Línea 112:
  
 
<p align="justify">
 
<p align="justify">
Si inicializamos el Stack Pointer en 0x17FF, al ejecutar una vez la rutina éste terminará en 0x17FC. La segunda vez que se ejecute la rutina, SP pasará de 0x17FC a 0x17F9. Observamos entonces que se van ocupando cada vez más posiciones de memoria, y si se ejecutara muchas veces la misma rutina, la memoría de la pila se sobrelapará con la memoría del inicio de la RAM. Al no limpiarse las variables temporales (Aquellas introducidas por la operación PSHA), tarde o temprano ocurrirá el "Overflow" o desborde, al no poder agregar más elementos en la pila.
+
Si inicializamos el Stack Pointer en 0x17FF, al ejecutar una vez la rutina SP apuntará a 0x17FC. La segunda vez que se ejecute la rutina, SP dejará de apuntar a  0x17FC y apuntará a 0x17F9. Observamos entonces que se van ocupando cada vez más posiciones de memoria, y si se ejecutara muchas veces la misma rutina, tarde o temprano la memoria de la pila se sobrelapará con la memoria del inicio de la RAM. Al no limpiarse las variables temporales (Aquellas introducidas por la operación PSHA), tarde o temprano ocurrirá el "Overflow" o desborde, al no poder agregar más elementos en la pila.
  
 
</p>
 
</p>
 
<p align="justify">
 
<p align="justify">
  
Para balancear la pila, es necesario limpiar las variables temporales al haber terminado la rutina. Es decir, '''debe haber tantas operaciones de PULL como PUSH''' se hayan realizado
+
Para balancear la pila, es necesario limpiar las variables temporales al haber terminado la rutina. Es decir, '''debe haber tantas operaciones de PULL como operaciones de PUSH''' se hayan realizado
  
 
</p>
 
</p>
Línea 177: Línea 177:
  
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
 +
* Es extremadamente importante realizar el mismo balanceo de pila al entrar en subrutinas e interrupciones, pues al acceder a alguna de las dos la posición del PC (En este caso, la posición donde se ejecutará la siguiente instrucción tras salir de la subrutina o interrupción) se guarda dentro de la pila, y '''al tratar de salir de la subrutina o interrupción, el microcontrolador siempre asume que SP está apuntando a donde se encuentra la dirección de la próxima instrucción fuera de la subrutina '''. Si no se balancea la pila, es prácticamente seguro que ocurrirá un error al tratar de regresar al programa principal. Como ejemplo:
 +
 +
 +
<syntaxhighlight lang="ASM">
 +
mainLoop:
 +
            ; Insert your code here
 +
            NOP
 +
         
 +
            BSR Subrutina  ;Al llegar aca, PC = 0x2086. Procedemos a la subrutina
 +
         
 +
         
 +
         
 +
            CLRA            ;PC=0x2088 
 +
            BRA    mainLoop
 +
         
 +
         
 +
         
 +
  Subrutina: 
 +
 +
              ;Al entrar en esta subrutina, automaticamente se guarda el valor de la dirección de la próxima instrucción
 +
              ;dentro de la pila, 0x2088. Al terminar la subrutina, PC debería apuntar a dicha dirección
 +
 
 +
            LDA #5
 +
            PSHA 
 +
            PSHA
 +
            PSHA
 +
         
 +
            CLRA
 +
            ADD 1,SP
 +
            ADD 2,SP
 +
            ADD 3,SP
 +
         
 +
            TAX
 +
         
 +
            PULA
 +
            PULA
 +
 +
              ;Quedan tres valores en pila, 0x05, 0x20, 0x88
 +
              ;Como SP está apuntando a la dirección de 0x05
 +
              ;Al tratar de salir de la subrutina, se tomará el byte más significativo de PC como 0x05
 +
              ;y el menos significativo como 0x20 , por lo que PC apuntará a 0x0520
 +
              ;En lugar de apuntar a donde debería, 0x2088
 +
         
 +
            RTS
 +
 +
</syntaxhighlight>
 +
 +
 +
Si se balancea la pila en el código anterior, solamente quedarán dos valores almacenados en pila, 0x20 y 0x88, los cuales representan la dirección correcta hacia la proxima instrucción despues de la subrutina.
  
 
==Ejemplos de códigos que emplean la pila==
 
==Ejemplos de códigos que emplean la pila==
 
En construcción
 
En construcción

Revisión del 16:10 29 mar 2013

Este artículo está incompleto. Necesita trabajo adicional. Revisar la discusión.


El microcontrolador MC9S08QE128 incluye un registro denominado "Stack pointer" o "Apuntador a pila", el cual sirve para controlar la función de pila que incluye éste. La pila cumple un papel extremadamente importante para la programación dentro del microcontrolador, pues permite guardar direcciones de memoria al momento de entrar en interrupciones, y permite guardar variables temporales o locales. Su buen uso es vital para poder crear códigos bien estructurados y sin tener que declarar variables globales una y otra vez. El uso de la pila puede hacer la diferencia entre un código ordenado y un completo desastre en programas con muchas subrutinas, pues esta sirve como una especie de "registro temporal" donde se pueden declarar un grupo de variables temporales que pueden ser limpiadas y utilizadas posteriormente para declarar otro grupo de variables.

¿Qué es la pila?:

La pila (Conocida en inglés como Stack) es un tipo de dato abstracto, donde predominan dos operaciones, insertar (Push) y retirar (Pop). La pila sigue el principio LIFO (Acrónimo para last in, first out) en el cual el último dato insertado es el primero que se puede retirar. Se puede representar de la siguiente manera: Cada dato es una hoja de papel, y se van acumulando los datos uno sobre otro. Solamente se puede retirar la hoja de papel que se encuentra en el tope de la pila, es decir, el dato que se insertó de ultimo.

El registro SP y su inicialización

Ver: Registro SP

Instrucciones del HCS08 relacionadas a la pila

Instrucción Descripción
1 PSHA / PSHH / PSHX

Toma el dato guardado en acumulador (A), en el registro H (H) o en el registro X (X) y lo guarda en la dirección apuntada por el Stack Pointer. Posteriormente, decrementa el valor del registro SP en uno

2 PULA / PULH / PULX

Se incrementa el valor del registro SP en uno, y posteriormente se guarda el dato guardado en la dirección de memoria a la cual apunta SP en el acumulador (A), en el registro H (H) o en el registro X (X). Finalmente, la dirección de memoria de donde se tomó el dato se define como espacio sin declarar.

3 LDA 'operando',SP

Se carga el valor de la dirección de memoria "operando + SP". Muy util para poder movernos a traves de cada una de las variables temporales definidas en pila sin tener que hacer varias operaciones de Pull.

4 STA 'operando',SP

Se guarda el dato almacenado en acumulador en la dirección de memoria "operando + SP". Al igual que su contraparte LDA, es muy util para modificar variables almacenadas en pila sin realizar Pull y Push varias veces

5 AIS #


Suma un valor # inmediato al registro SP, permitiendo desplazar el apuntador a la pila hacia arriba o hacia abajo y limpiar un gran grupo de variables rapidamente

6 TSX

Transfiere el contenido del registro SP al registro HX. Es muy util a la hora de guardar la dirección de una cierta variable y mover el apuntador a pila a la vez.


7 TXS

Transfiere el contenido del registro HX al registro SP


8 RSP

Escribe 0xFF sobre el registro bajo de SP. Si se inicializa el registro SP en 0x17FF y no se insertan más de 255 variables se puede utilizar esta instrucción para resetear el apuntador a su posición inicial (Pasamos de 0x17XX a 0x17FF)


Advertencias al momento de usar la pila

  • Es obligatorio inicializar el Stack Pointer al comienzo del programa. Así no se utilice para guardar variables temporales propias, este se utiliza para guardar la dirección del Program Counter al realizar un branch a una subrutina o realizar una interrupción
  • Se debe tener cuidado con la posición de memoria donde se inicializa el Stack Pointer, pues podría sobrelaparse y producir errores. Se recomienda siempre inicializarlo en la dirección 0x1800
  • Es muy importante siempre balancear la pila al momento de usarla. Balancear la pila se refiere a que al momento de declarar variables temporales y dejar de usarlas se deben limpiar dichas variables para poder usar el mismo espacio de memoria nuevamente

Como ejemplo a este punto, vease el siguiente código:

        
Rutina:
 
            PSHA   ;Hacemos Push tres veces del contenido del acumulador en pila
            PSHA
            PSHA

            CLRA   ;Limpiamos acumulador
            ADD 1,SP   ;Sumamos tres veces el acumulador con el contenido que tenía antes de hacer CLR.
            ADD 2,SP  
            ADD 3,SP

            STA Resultado  ;Guardamos el contenido en resultado

      
            CMPA #255
            BNE Rutina  ;Si el resultado no es 255, volvemos a ejecutar la rutina

Si inicializamos el Stack Pointer en 0x17FF, al ejecutar una vez la rutina SP apuntará a 0x17FC. La segunda vez que se ejecute la rutina, SP dejará de apuntar a 0x17FC y apuntará a 0x17F9. Observamos entonces que se van ocupando cada vez más posiciones de memoria, y si se ejecutara muchas veces la misma rutina, tarde o temprano la memoria de la pila se sobrelapará con la memoria del inicio de la RAM. Al no limpiarse las variables temporales (Aquellas introducidas por la operación PSHA), tarde o temprano ocurrirá el "Overflow" o desborde, al no poder agregar más elementos en la pila.

Para balancear la pila, es necesario limpiar las variables temporales al haber terminado la rutina. Es decir, debe haber tantas operaciones de PULL como operaciones de PUSH se hayan realizado


Rutina:
 


            PSHA   ;Hacemos Push tres veces del contenido del acumulador en pila
            PSHA
            PSHA

            CLRA   ;Limpiamos acumulador
            ADD 1,SP   ;Sumamos tres veces el acumulador con el contenido que tenía antes de hacer CLR, SP=0x17FE
            ADD 2,SP   ;SP=0x17FD
            ADD 3,SP   ;SP=0x17FC

            STA Resultado  ;Guardamos el contenido en resultado

            PULA           ;Pull 3 veces para balancear pila, SP=0x17FD
            PULA           ;SP=0x17FE
            PULA           ;SP=0x17FF
            LDA Resultado  ;Recuperamos resultado para realizar comparación

      
            CMPA #255
            BNE Rutina  ;Si el resultado no es 255, volvemos a ejecutar la rutina


Otra alternativa es emplear la instrucción AIS


Rutina:
 


            PSHA   ;Hacemos Push tres veces del contenido del acumulador en pila
            PSHA
            PSHA

            CLRA   ;Limpiamos acumulador
            ADD 1,SP   ;Sumamos tres veces el acumulador con el contenido que tenía antes de hacer CLR
            ADD 2,SP
            ADD 3,SP   ;SP=0x17FC

            STA Resultado  ;Guardamos el contenido en resultado

            AIS #3         ;Reseteamos pila a su posición original, SP=0x17FC + 0x0003 = 0x17FF
      
            CMPA #255
            BNE Rutina  ;Si el resultado no es 255, volvemos a ejecutar la rutina


  • Es extremadamente importante realizar el mismo balanceo de pila al entrar en subrutinas e interrupciones, pues al acceder a alguna de las dos la posición del PC (En este caso, la posición donde se ejecutará la siguiente instrucción tras salir de la subrutina o interrupción) se guarda dentro de la pila, y al tratar de salir de la subrutina o interrupción, el microcontrolador siempre asume que SP está apuntando a donde se encuentra la dirección de la próxima instrucción fuera de la subrutina . Si no se balancea la pila, es prácticamente seguro que ocurrirá un error al tratar de regresar al programa principal. Como ejemplo:


mainLoop:
            ; Insert your code here
            NOP
           
            BSR Subrutina   ;Al llegar aca, PC = 0x2086. Procedemos a la subrutina
           
           
           
            CLRA            ;PC=0x2088   
            BRA    mainLoop
           
           
           
   Subrutina:   

               ;Al entrar en esta subrutina, automaticamente se guarda el valor de la dirección de la próxima instrucción
               ;dentro de la pila, 0x2088. Al terminar la subrutina, PC debería apuntar a dicha dirección
  
            LDA #5
            PSHA   
            PSHA
            PSHA
           
            CLRA
            ADD 1,SP
            ADD 2,SP
            ADD 3,SP
           
            TAX
           
            PULA
            PULA

               ;Quedan tres valores en pila, 0x05, 0x20, 0x88
               ;Como SP está apuntando a la dirección de 0x05
               ;Al tratar de salir de la subrutina, se tomará el byte más significativo de PC como 0x05
               ;y el menos significativo como 0x20 , por lo que PC apuntará a 0x0520
               ;En lugar de apuntar a donde debería, 0x2088
           
            RTS


Si se balancea la pila en el código anterior, solamente quedarán dos valores almacenados en pila, 0x20 y 0x88, los cuales representan la dirección correcta hacia la proxima instrucción despues de la subrutina.

Ejemplos de códigos que emplean la pila

En construcción