usar studio programar programacion pasar mega ensamblador como codigo atmega328p atmega328 assembler asm assembly arduino avr-gcc

assembly - studio - Pasando por el código de ensamblador AVR "hello world"



programar atmega328p en ensamblador (2)

El punto / punto se usa como un atajo para indicar la dirección o ubicación de esta instrucción o algo relacionado con eso. . + 8 significa desde aquí más 8. Debe explicar los matices del conjunto de instrucciones y / o del ensamblador en relación con el conjunto de instrucciones. Como indica la información adicional del ensamblador, do_clear_bss_loop -8 va a do_clear_bss_loop que tiene ocho bytes, incluidos los dos bytes para la instrucción en sí. El código original probablemente solo tenía la etiqueta allí, brne do_clear_bss_loop .

Es probable que se copie el segmento de datos; .text es básicamente de solo lectura. Es su código y quiere vivir en flash en esta plataforma. .data , sin embargo, es de lectura / escritura y generalmente se inicializa a valores distintos de cero. Entonces, con el apagado, sus valores iniciales deben conservarse en algún lugar, por ejemplo en flash, pero antes de comenzar su programa real, el programa de arranque deberá copiar los valores iniciales del segmento .data del flash a su hogar real en la RAM . Luego, cuando el programa se ejecuta, puede leer y / o modificar esos valores como desee.

Por ejemplo:

int x = 5; main () { x = x + 1; }

Ese valor 5 tiene que estar en flash para comenzar desde el encendido solo con flash para mantener la información no volátil. Pero antes de poder leer / escribir la ubicación de la memoria para x lo necesita en la memoria RAM, por lo que algunos códigos de inicio copian todos los elementos del documento de datos de la memoria flash a la memoria RAM.

Perdón por la larga explicación de algo que solo es una suposición al mirar tu pregunta.

.bss son variables en su programa que se inicializan a cero. Con el segmento .data , si tuviéramos 100 elementos necesitaríamos 100 cosas en flash. Pero con .bss si tenemos 100 elementos, solo necesitamos decirle a alguien que hay 100 elementos. No necesitamos 100 ceros en flash, simplemente compilar / ensamblarlo en el código.

Asi que

int x = 5; int y; int main () { while(1) { y = y + x + 1; } }

x está en .data y el 5 necesita estar en un almacenamiento no volátil. El y está en .bss y solo necesita ponerse a cero antes de llamar a main para cumplir con el estándar de C.

De acuerdo, es posible que usted no esté usando variables globales, pero puede haber otros datos que de alguna manera usen los segmentos .data y / o .bss y, como resultado, el código bootstrap prepara los segmentos .data y .bss antes de llamar a main() para que su experiencia de programación C sea la esperada.

Intento escribir algún lenguaje ensamblador para Arduino Duemilanove (AVR ATmega328P ). Aprendiendo el lenguaje ensamblador en paralelo con la compilación y el desensamblaje del código C, tengo esto:

(Compilado con AVR_GCC )

int main() { volatile int a = 0; while (1) { ++a; } return 0; }

Que se convierte en

00000000 <__vectors>: 0: 0c 94 34 00 jmp 0x68 ; 0x68 <__ctors_end> 4: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt> ... 64: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt> 00000068 <__ctors_end>: 68: 11 24 eor r1, r1 6a: 1f be out 0x3f, r1 ; 63 6c: cf ef ldi r28, 0xFF ; 255 6e: d8 e0 ldi r29, 0x08 ; 8 70: de bf out 0x3e, r29 ; 62 72: cd bf out 0x3d, r28 ; 61 00000074 <__do_copy_data>: 74: 11 e0 ldi r17, 0x01 ; 1 76: a0 e0 ldi r26, 0x00 ; 0 78: b1 e0 ldi r27, 0x01 ; 1 7a: e4 ec ldi r30, 0xC4 ; 196 7c: f0 e0 ldi r31, 0x00 ; 0 7e: 02 c0 rjmp .+4 ; 0x84 <__do_copy_data+0x10> 80: 05 90 lpm r0, Z+ 82: 0d 92 st X+, r0 84: a0 30 cpi r26, 0x00 ; 0 86: b1 07 cpc r27, r17 88: d9 f7 brne .-10 ; 0x80 <__do_copy_data+0xc> 0000008a <__do_clear_bss>: 8a: 11 e0 ldi r17, 0x01 ; 1 8c: a0 e0 ldi r26, 0x00 ; 0 8e: b1 e0 ldi r27, 0x01 ; 1 90: 01 c0 rjmp .+2 ; 0x94 <.do_clear_bss_start> 00000092 <.do_clear_bss_loop>: 92: 1d 92 st X+, r1 00000094 <.do_clear_bss_start>: 94: a0 30 cpi r26, 0x00 ; 0 96: b1 07 cpc r27, r17 98: e1 f7 brne .-8 ; 0x92 <.do_clear_bss_loop> 9a: 0e 94 53 00 call 0xa6 ; 0xa6 <main> 9e: 0c 94 60 00 jmp 0xc0 ; 0xc0 <_exit> 000000a2 <__bad_interrupt>: a2: 0c 94 00 00 jmp 0 ; 0x0 <__vectors> 000000a6 <main>: a6: cf 93 push r28 a8: df 93 push r29 aa: 00 d0 rcall .+0 ; 0xac <main+0x6> ac: cd b7 in r28, 0x3d ; 61 ae: de b7 in r29, 0x3e ; 62 b0: 1a 82 std Y+2, r1 ; 0x02 b2: 19 82 std Y+1, r1 ; 0x01 b4: 89 81 ldd r24, Y+1 ; 0x01 b6: 9a 81 ldd r25, Y+2 ; 0x02 b8: 01 96 adiw r24, 0x01 ; 1 ba: 9a 83 std Y+2, r25 ; 0x02 bc: 89 83 std Y+1, r24 ; 0x01 be: fa cf rjmp .-12 ; 0xb4 <main+0xe> 000000c0 <_exit>: c0: f8 94 cli 000000c2 <__stop_program>: c2: ff cf rjmp .-2 ; 0xc2 <__stop_program>

Traté de entender algunas cosas:

  1. ¿Cuál es la sintaxis .8 o similar? (dirección 0x98 o 0xAA, por ejemplo)
  2. Alrededor de las líneas con la dirección 80 a 88 (final de __do_copy_data) hay algunas cosas divertidas. Me parece que esto carga todo el código del programa en la RAM , desde la dirección 0xC4. ¿Por qué?
  3. En __do_clear_bss_start / loop, borramos todo el trabajo que acabamos de hacer al establecer bytes en la RAM a 0 (valor de r1). ¿Por qué? Todo esto para finalmente llamar a main . ¿Alguna explicación general?
  4. ¿Por qué no desmotivamiento muestra .bss, .rodata u otras secciones?
  5. Línea 6a, ¿por qué se borra el SREG? ¿No está configurado para lo que debería ser después de cada instrucción?
  6. Líneas 6c y 6e: ¿a qué corresponden 0xFF y 0x08? r28 y r29 son el puntero de pila bajo y alto.
  7. Jugué un poco y agregué una variable global estática. ¿Por qué almacenamos en RAM comenzando desde 0x0100 y no desde 0x0000?
  8. En la línea 8a, ¿ ldi r17, 1 qué ldi r17, 1 ? Lo hicimos antes (solo un comentario estúpido). ¿O puede algo más alterar r17?
  9. Comenzamos a copiar el programa en flash a la RAM, comenzando en 0xC4 (.bss y otras secciones, supongo), pero el cpi / cpc de X con respecto a 1 hará que TODO el flash se copie en toda la RAM. ¿Es solo por la pereza del compilador no detener la copia cuando las secciones .bss están listas para copiarse?

Me doy cuenta de que esta es una respuesta tardía. Sin embargo, todavía creo que puede ser interesante tener una respuesta detallada punto por punto para todas las preguntas.

  1. ¿Cuál es la sintaxis .8 o similar? (dirección 0x98 o 0xAA, por ejemplo)

Significa: "saltar 8 bytes desde aquí". Tenga en cuenta que el contador del programa ya se ha incrementado por la longitud de la instrucción (2 bytes), por lo que brne .-8 lo moverá 6 bytes (no 8) antes de la instrucción brne en sí. En la misma línea, rcall .+0 empujará el contador del programa a la pila sin alterar el flujo del programa. Este es un truco solo destinado a reservar dos bytes de espacio de pila en una sola instrucción.

  1. Alrededor de las líneas con la dirección 80 a 88 (final de __do_copy_data) hay algunas cosas divertidas. Me parece que esto carga todo el código del programa en la RAM, desde la dirección 0xC4. ¿Por qué?

No, nada se copia, este es un bucle vacío. En las líneas 84 a 88 hay una prueba que sale del circuito cuando el puntero X (r27: r26) es igual a 0x0100. Dado que X se inicializa en 0x0100, esto no funcionará en absoluto.

Este ciclo está destinado a copiar la sección de datos de flash a RAM. Básicamente, algo como esto:

X = DATA_START; // RAM address Z = 0x00C4; // Flash address while (X != DATA_START + DATA_SIZE) ram[X++] = flash[Z++];

pero su programa tiene una sección de datos vacía ( DATA_SIZE == 0 en el pseudo-código anterior).

Además, debe tener en cuenta que su programa termina en la dirección 0x00c3, por lo que el puntero Z se inicializa para señalar justo después del código del programa. Aquí es donde se supone que son los valores iniciales de las variables inicializadas.

  1. En __do_clear_bss_start / loop, borramos todo el trabajo que acabamos de hacer al establecer bytes en la RAM a 0 (valor de r1). ¿Por qué? Todo esto para finalmente llamar a main . ¿Alguna explicación general?

No, nada será sobrescrito. Este ciclo borra el BSS, que normalmente viene justo después de la sección de datos, sin superposición. Pseudocódigo:

X = BSS_START; while (X != BSS_START + BSS_SIZE) ram[X++] = 0;

donde BSS_START == DATA_START + DATA_SIZE . Esto también es un bucle vacío en su programa porque tiene un bss vacío.

  1. ¿Por qué no desmotivamiento muestra .bss, .rodata u otras secciones?

Porque objdump -d solo desensambla las secciones que se espera que contengan código.

  1. Línea 6a, ¿por qué se borra el SREG? ¿No está configurado para lo que debería ser después de cada instrucción?

La mayoría de las instrucciones solo alteran algunos bits de SREG. Además, esto borra el bit de habilitación de interrupción global.

  1. Líneas 6c y 6e: ¿a qué corresponden 0xFF y 0x08? r28 y r29 son el puntero de pila bajo y alto.

El puntero de pila se carga con 0x08ff, que es la última ubicación de RAM en el ATmega328P. La pila crecerá hacia abajo desde allí.

  1. Jugué un poco y agregué una variable global estática. ¿Por qué almacenamos en RAM comenzando desde 0x0100 y no desde 0x0000?

RAM está en 0x0100-0x08ff en el 328P. Debajo de esta dirección, tiene algunos registros mapeados en la memoria (los registros de la CPU y los registros de E / S). Consulte la hoja de datos para obtener más información, sección "8.3 Memoria de datos SRAM".

  1. En la línea 8a, ¿ ldi r17, 1 qué ldi r17, 1 ? Lo hicimos antes (solo un comentario estúpido). ¿O puede algo más alterar r17?

La línea 8a es inútil. Está aquí por la forma en que el vinculador construye el programa pegando piezas diferentes: __do_copy_data y __do_clear_bss son rutinas independientes, no dependen de lo que quede del otro en los registros.

  1. Comenzamos a copiar el programa en flash a la RAM, comenzando en 0xC4 (.bss y otras secciones, supongo), pero el cpi / cpc de X con respecto a 1 hará que TODO el flash se copie en toda la RAM. ¿Es solo por la pereza del compilador no detener la copia cuando las secciones .bss están listas para copiarse?

Usted malentendió esta parte del código. Las instrucciones cpi, cpc y brne girarán solo mientras X sea diferente de r17: 0x00 (es decir, 0x0100, ya que r17 = 1). Cf los pseudo-códigos de arriba.