Ir por debajo de la parte inferior de la pila en ATmega328P

Estoy trabajando con un proyecto basado en AVR y solo tengo una curiosidad.

El ATmega328P tiene un total de 2kB de SRAM. La dirección más baja de la pila puede ser 0x8FF. Ahora suponga que el puntero de la pila está en 0x8FF. ¿Qué sucedería si diera una instrucción RETI en este punto o una instrucción POP varias veces?

Se supone que RETI y POP toman el valor en la parte superior de la pila e incrementan el puntero de la pila (incrementar el puntero de la pila significaría bajar la pila).

Probé en Microchip Studio (anterior estudio AVR).

Allí simplemente incrementa el puntero de la pila de 0x08FF a 0x0900 a 0x0901 y así sucesivamente. En realidad, esto podría ser posible porque el puntero de la pila es un registro de 16 bits (2 registros SPL y SPH de 8 bits cada uno).

Ahora supongamos que llevo mi SP a 0x0905 y hago un PUSH, y luego hago un pop. En el simulador, aparece el valor correcto (que se introdujo) en mi registro de salida. Sin embargo, en un ATmega328P real eso no sería posible (ya que no hay lugar para almacenar la siguiente dirección 0x8FF).

¿Cómo reaccionaría una unidad de microprocesador real ante tal escenario?

El código que usé fue:

LDI R16, 0x88 ;load a random value
POP R0        ;increase SP to 0x900
POP R1        ;increase SP to 0x901
POP R2        ;increase SP to 0x902
POP R3        ;increase SP to 0x903
PUSH R16      ;decrease SP to 0x902
PUSH R16      ;decrease SP to 0x901
POP R4        ;increase SP to 0x902 and store 0x88 in R4

En los comentarios he escrito todo lo que observé en el simulador, quiero saber cómo reaccionaría un procesador real.

La ram es de solo 2KBytes. ¿De dónde sacaste 23kb?
0x8ff es el TOP de la pila. La pila crece hacia abajo, es decir, hacia 0. Más allá de 0x8ff hay aire fresco. Puedes empujar, pero lo que hagas explotar no será nada útil.
¿AVR no usa pilas de conteo regresivo o cambió a conteo ascendente después de la fusión de Microchip? :) Creo que PIC son los únicos que usan pilas de conteo progresivo.
sí, avr implementa una pila de conteo regresivo (0x08FF es el "TOP") pero cuando crece, disminuye el puntero de la pila (eso es lo que quería decir). @Kartman sí, el mcu tiene 2Kb SRAM. Escribí el número equivocado.
No tiene garantizado 16 bits para SP, la hoja de datos dice que la cantidad de bits depende del espacio de direcciones, por lo que 11 bits para 328p. (Las MCU más pequeñas ni siquiera tienen SPH). Lo que realmente hay en el hardware, aunque no tengo idea. Pero no se sorprendería si simplemente llegara a cero.

Respuestas (1)

No sé específicamente sobre AVR, pero en el caso general, la MCU continúa y escribe fuera de los límites. Este es un desbordamiento/subdesbordamiento de pila. (El subdesbordamiento de la pila solo puede ocurrir en ensamblador, no en C puro). Por lo general, solo el enlazador sabe dónde comienza y termina su pila: ni el compilador ni la propia MCU lo saben ni les importa.

Por lo general, las MCU de gama baja solo ofrecen acceso a la memoria física, por lo que no hay una MMU que se golpee los dedos si toca una memoria que no debería tocar. O si hay una MMU, a menudo es simplista. Las piezas de gama alta generarían excepciones de hardware.

Por lo tanto, los programadores de sistemas integrados endurecidos se aseguran de mapear siempre su pila para que se desborde en una memoria inofensiva. Como direcciones donde no se asigna nada, o direcciones donde no hay nada más que flash no programado. Un puntero de pila que termina allí muy pronto conducirá a un código de ejecución o similar, a menudo tratando de ejecutar el código de operación 0xFF. A partir de ahí, normalmente puede detectar interrupciones de código de operación ilegales. O en el peor de los casos, con suerte, el perro guardián detendrá el programa.

Si no coloca su pila con tanto cuidado, o en caso de que use algún diseño de memoria predeterminado provisto por el fabricante y/o los monos, podría terminar desbordando la pila en su mapa de registro de hardware o algún segmento de RAM .data/.bss , que es un desastre.

Otra técnica algo tosca que puede usar, a menudo realizada por compiladores de sistemas de alto nivel, es usar un "control canario de pila". Haga un cálculo del uso esperado de la pila en el peor de los casos. Luego configure toda la pila en un valor conocido al inicio (todo 0x00 o todo 0xFF). Luego, más allá de su peor escenario de pila estimado, escriba un valor diferente (0xAA o lo que sea) en varias ubicaciones fijas. Luego, puede verificar repetidamente estas ubicaciones desde el ciclo principal para ver que aún tienen el valor fijo; si no, entonces tiene un desbordamiento de pila. Esto no es 100% seguro, pero detecta la mayoría de los desbordamientos de pila.