microcontroladores AVR, ¿quién inicia el segmento de 'datos' del ensamblaje y cuál es el propósito de tener esta directiva?

3

Soy nuevo en ensambladores y microcontroladores y estoy tratando de descubrir cómo funcionan.

Ahora, he leído mucho sobre cómo en el ensamblaje los segmentos text y data son para almacenar el código del programa y los datos iniciales del mismo. En todas partes, la gente dice [ 1 , < a href="http://jaxcoder.com/Projects.aspx?id=912541054#captcha"> 2 , 3 ] (si dicen algo) data segment almacena valores preinicializados para el programa.

Pero en AVR, según entiendo, data significa SRAM . Y para que se inicialice, debe indicar a su microcontrolador que ponga algunos valores reales allí. Solo tener instrucciones bajo .dseg en algún lugar de su código no pone mágicamente los valores en SRAM . El microcontrolador tiene que alcanzar las instrucciones de inicialización siguiendo su ritmo, siguiendo el programa de manera habitual: comienza en 0x0 del segmento program , que es flash en AVR, y sigue las instrucciones.

Por ejemplo, en este question el tipo examina el código, producido por avr-gcc desde C , y encuentra las rutinas que inicializan SRAM desde flash , es decir, el segmento program del código.

Si es así, ¿cuál es el propósito de tener .dseg ?

Tal vez sea para diferentes ensambladores u otras herramientas (como avr-gcc en la referenciada question , o avrstudio en el enlace 1 ), que agregaría las instrucciones de inicialización necesarias al procesar el código con .dseg ?

Pero si trabajas con "huesos desnudos", el microcontrolador comienza desde 0x0 (o en algún otro lugar, de acuerdo con la hoja de datos), aquí es donde comienza tu programa y no hay nada más, ¿verdad? (Por supuesto, coloca una tabla de vectores para las interrupciones, si quieres manejarlas. Y 0x0 es la dirección a la que RESET trae el microcontrolador. Pero no es esencial).

PS

Pensé que .dseg / cseg podría implicar diferentes espacios de direcciones: cuando escribes una dirección en .dseg es para SRAM , en .cseg - para flash . Pero el direccionamiento de las costuras depende únicamente de la definición de la instrucción: ADD a1, a2 - a# son registros, RJMP a - a es flash (es decir, program ), se accede indirectamente a SRAM a través de los registros - - LDS R1, 0x0060 .

De nuevo, puede ser así, que el código bajo la etiqueta .dseg como en 1 :

 .DSEG                        ; Start data segment
 var1:  .BYTE 1               ; reserve 1 byte to var1

sustituye el acceso indirecto a SRAM a través de registros? Probablemente esta información debería buscarse en la documentación del ensamblador en particular. De nuevo, ¿el conjunto de instrucciones AVR de "hueso desnudo" no proporciona nada de eso?

    
pregunta xealits

2 respuestas

2

Estos segmentos son simplemente metadatos, no tienen ningún significado para la CPU AVR ni para su código. Son instrucciones para el enlazador.

Cuando compilas un programa en C con avr-gcc, agrega lo que se llama un 'stub'. Este código contiene los vectores de interrupción y el vector de reinicio. Cuando se inicia la CPU, no ejecuta de inmediato su método principal, sino que comienza a ejecutarse en el vector de reinicio. El vector de reinicio apunta al código de inicio en el código auxiliar de ensamblado. Este código inicializa el puntero de pila y los segmentos de datos. Una vez finalizado esto, salta a su método principal. Si escribes en un ensamblaje puro sobre metal desnudo, nada de esto se hace por ti a menos que lo hagas tú mismo.

Los diferentes segmentos son utilizados principalmente por el compilador, el ensamblador y el enlazador para juntar las partes de su programa de manera inteligente y asegurarse de que cada variable estática tenga su propio espacio de direcciones. Cuando las piezas se juntan, los punteros de dirección y las compensaciones se sustituyen en el código del programa en las ubicaciones apropiadas. Después de compilar y vincular el programa, los segmentos ya no existen realmente en el archivo bin / hex de salida. En realidad, ninguno de los segmentos de datos termina en el archivo hexadecimal, solo una copia de los datos de inicialización para el segmento inicializado en una ubicación que ha sido sustituida en el código de inicio. Por ejemplo, no hay diferencia desde el punto de vista del microcontrolador entre los datos inicializados y no inicializados. Sin embargo, el código de inicio desearía que todos los datos inicializados estuvieran en un bloque contiguo, de modo que pueda circular en un solo bucle. Además, el código de inicio necesita saber dónde está ubicado el segmento y qué tan grande es. El enlazador combina los segmentos de los archivos de objetos individuales en un segmento grande, luego sustituye las direcciones en el código de inicio después de que haya descubierto dónde colocar todo.

Además, hay una diferencia bastante importante entre un microcontrolador AVR y una PC estándar: en el AVR, las instrucciones y los datos tienen espacios de direcciones completamente separados. Esto significa que necesita saber a qué espacio de direcciones se refiere cuando realiza un acceso a la memoria. El ensamblador puede ayudarlo con esto si es lo suficientemente inteligente.

    
respondido por el alex.forencich
3

No importa qué instrucciones se vayan a utilizar, el procesador puede obtener todas las partes de SRAM y memoria Flash. Así que ignora los registros e instrucciones por ahora.

Las variables inicializadas deben colocarse en SRAM, o no pueden usarse como variables, es decir, el programa no puede actualizar su valor.

Sus valores iniciales deben almacenarse en flash, de lo contrario, los valores iniciales se perderían cuando se retira la alimentación.

El procesador copia los valores de Flash a SRAM para inicializar los valores de todas las variables inicializadas (normalmente se almacenan uno al lado del otro en SRAM, y antes de las variables sin inicializar en SRAM). El procesador ejecuta un bucle que copia un área de Flash a SRAM. Ese bucle es una parte temprana del programa que inicializa el estado del programa. En C, toda esa inicialización se ejecuta antes de llamar a main() .

Las variables se almacenan en la SRAM cuando el programa se está ejecutando, y el ensamblador lee las directivas .dseg del programa que contienen .BYTE para reservar el espacio. Sus valores iniciales se almacenan en Flash, en un .CSEG, y los valores literales se almacenan dentro del .CSEG utilizando .DB o .DW.

Si todas las variables inicializadas están una al lado de la otra, entonces el programa necesita saber la dirección de inicio de las variables de SRAM para inicializar, y la dirección de inicio de Flash que contiene sus valores iniciales. También necesita la longitud del área de variables inicializadas.

En casi C sería:

unsigned char* flash_values = flash_address_of_initial_values_of_initialised_variables;
unsigned char* SRAM_initialised_vars = SRAM_address_of_initialised_variables;
for (int i=0; i<length_of_initialised_variables; ++i) {
    SRAM_initialised_vars[i] = PROGRAM_MEMORY(flash_values[i]);
}

Editar: PROGRAM_MEMORY(...) recupera el valor de la memoria Flash.

    
respondido por el gbulmer

Lea otras preguntas en las etiquetas