Voir le code assembleur

Bonjour,

par curiosité avant tout, mais avec un souci d'optimisation en arrière pensée je cherche a comprendre comment "marchent" les programmes arduino.

De ce que j'ai compris entre le code arduino qu'on écrit dans l'IDE et le .hex qui fini dans le micro contrôleur il y'a au moins 3/4 étapes intermédiaires quand le clic sur le bouton pour transférer le code dans mon arduino.

D'abord une première moulinette qui rajout plein d'includes divers pour les fonctions de base de l'arduino et qui ponds un code en C plus complet
Ensuite une 2eme moulinette qui converti le C en question en assembleur
puis un machin qui fait un .hex a partir du code en assembleur
et enfin un autre machin qui transfert le .hex dans la puce.

  • Ai je bien compris ? il y'a t'il d'autres étapes ?
  • Comment "voir" les fichiers intermédiaires ?

Je serais curieux de voir comment en modifiant quelques lignes de mon programme arduino ce qui change dans le code assembleur.

En fait j'ai une fonction que j’appelle a intervalles réguliers (via la librairie timer2ms), et je voudrais que mon arduino passe le moins de temps possible dedans.
Je voudrais optimiser l'ordre et l'imbrication des conditions qu'il y'a dedans au mieux.
(même si au départ mon truc tournait sur un pic beaucoup plus lent que mon arduino, et que les perfs n'etait pas si mal que ca. Tant que je peut faire mieux, c'est mieux.)

Je dirais :

  1. construction du fichier "main.cpp" ou "x.cpp" d'après le "prototype" main.cpp ce situant dans le core arduino
#include <WProgram.h>

int main(void)
{
	init();

	setup();
    
	for (;;)
		loop();
        
	return 0;
}
  1. compilation de ce "main.cpp" vers fichier .hex (assembleur)
  2. upload du code binaire construit dans le fichier .hex

Enfin je pense que ça doit être quelque chose comme ça ?
Par contre je me demande également où ce situe ses fichiers construits, surtout le "main.cpp" ou "x.cpp" final ?
J'ai déjà essayé de naviguer dans les sources de l'ide et à travers les différents makefile sans grand résultats. :drooling_face:

Salut,

De base il n'est pas possible d'avoir le code assembleur car l'ide arduino ne fourni pas les arguments qui vont bien au compilateur (il demande juste la compilation .c -> .o rien de plus, il ne demande pas à gcc de générer les fichiers .S et .lst).

osaka:
Par contre je me demande également où ce situe ses fichiers construits, surtout le "main.cpp" ou "x.cpp" final ?

Sous windows : C:\Users<nom d'utilisateur>\AppData\Local\Temp\Buildxxxxxxxxxxx

skywodd:
Sous windows : C:\Users<nom d'utilisateur>\AppData\Local\Temp\Buildxxxxxxxxxxx

Et OSX ? :grin:

osaka:
Et OSX ? :grin:

OS quoi ? OSx, c'est un OS avec du pr0n dedans ? :grin:

Regarde dans /tmp :wink:

skywodd:
OS quoi ? OSx, c'est un OS avec du pr0n dedans ? :grin:

Imagine ma déception quand j'ai découvert que non. :grin:

skywodd:
Regarde dans /tmp :wink:

Je ne trouve rien, c'est pour ça que j'aurais bien voulu trouver un makefile ou Ant qui me permettrait de suivre la compil en détail (et même de passer par un autre ide facilement), mais je trouve rien. :frowning:

Yep!

Dans l'ide arduino, tu ouvres ton code puis :

Shift+verify

Sous linux, cà donne dans l'output sous ton code (blink.pde) :

avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/usr/share/arduino/hardware/arduino/cores/arduino /tmp/build4594399183737056674.tmp/Blink.cpp -o/tmp/build4594399183737056674.tmp/Blink.cpp.o
avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/usr/share/arduino/hardware/arduino/cores/arduino /usr/share/arduino/hardware/arduino/cores/arduino/wiring_shift.c -o/tmp/build4594399183737056674.tmp/wiring_shift.c.o
avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/usr/share/arduino/hardware/arduino/cores/arduino /usr/share/arduino/hardware/arduino/cores/arduino/pins_arduino.c -o/tmp/build4594399183737056674.tmp/pins_arduino.c.o
avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/usr/share/arduino/hardware/arduino/cores/arduino /usr/share/arduino/hardware/arduino/cores/arduino/wiring_pulse.c -o/tmp/build4594399183737056674.tmp/wiring_pulse.c.o
avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/usr/share/arduino/hardware/arduino/cores/arduino /usr/share/arduino/hardware/arduino/cores/arduino/wiring_digital.c -o/tmp/build4594399183737056674.tmp/wiring_digital.c.o
avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/usr/share/arduino/hardware/arduino/cores/arduino /usr/share/arduino/hardware/arduino/cores/arduino/WInterrupts.c -o/tmp/build4594399183737056674.tmp/WInterrupts.c.o
avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/usr/share/arduino/hardware/arduino/cores/arduino /usr/share/arduino/hardware/arduino/cores/arduino/wiring.c -o/tmp/build4594399183737056674.tmp/wiring.c.o
avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/usr/share/arduino/hardware/arduino/cores/arduino /usr/share/arduino/hardware/arduino/cores/arduino/wiring_analog.c -o/tmp/build4594399183737056674.tmp/wiring_analog.c.o
avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/usr/share/arduino/hardware/arduino/cores/arduino /usr/share/arduino/hardware/arduino/cores/arduino/main.cpp -o/tmp/build4594399183737056674.tmp/main.cpp.o
avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/usr/share/arduino/hardware/arduino/cores/arduino /usr/share/arduino/hardware/arduino/cores/arduino/WMath.cpp -o/tmp/build4594399183737056674.tmp/WMath.cpp.o
avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/usr/share/arduino/hardware/arduino/cores/arduino /usr/share/arduino/hardware/arduino/cores/arduino/WString.cpp -o/tmp/build4594399183737056674.tmp/WString.cpp.o
avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/usr/share/arduino/hardware/arduino/cores/arduino /usr/share/arduino/hardware/arduino/cores/arduino/Print.cpp -o/tmp/build4594399183737056674.tmp/Print.cpp.o
avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/usr/share/arduino/hardware/arduino/cores/arduino /usr/share/arduino/hardware/arduino/cores/arduino/HardwareSerial.cpp -o/tmp/build4594399183737056674.tmp/HardwareSerial.cpp.o
avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/usr/share/arduino/hardware/arduino/cores/arduino /usr/share/arduino/hardware/arduino/cores/arduino/Tone.cpp -o/tmp/build4594399183737056674.tmp/Tone.cpp.o
avr-ar rcs /tmp/build4594399183737056674.tmp/core.a /tmp/build4594399183737056674.tmp/wiring_shift.c.o
avr-ar rcs /tmp/build4594399183737056674.tmp/core.a /tmp/build4594399183737056674.tmp/pins_arduino.c.o
avr-ar rcs /tmp/build4594399183737056674.tmp/core.a /tmp/build4594399183737056674.tmp/wiring_pulse.c.o
avr-ar rcs /tmp/build4594399183737056674.tmp/core.a /tmp/build4594399183737056674.tmp/wiring_digital.c.o
avr-ar rcs /tmp/build4594399183737056674.tmp/core.a /tmp/build4594399183737056674.tmp/WInterrupts.c.o
avr-ar rcs /tmp/build4594399183737056674.tmp/core.a /tmp/build4594399183737056674.tmp/wiring.c.o
avr-ar rcs /tmp/build4594399183737056674.tmp/core.a /tmp/build4594399183737056674.tmp/wiring_analog.c.o
avr-ar rcs /tmp/build4594399183737056674.tmp/core.a /tmp/build4594399183737056674.tmp/main.cpp.o
avr-ar rcs /tmp/build4594399183737056674.tmp/core.a /tmp/build4594399183737056674.tmp/WMath.cpp.o
avr-ar rcs /tmp/build4594399183737056674.tmp/core.a /tmp/build4594399183737056674.tmp/WString.cpp.o
avr-ar rcs /tmp/build4594399183737056674.tmp/core.a /tmp/build4594399183737056674.tmp/Print.cpp.o
avr-ar rcs /tmp/build4594399183737056674.tmp/core.a /tmp/build4594399183737056674.tmp/HardwareSerial.cpp.o
avr-ar rcs /tmp/build4594399183737056674.tmp/core.a /tmp/build4594399183737056674.tmp/Tone.cpp.o
avr-gcc -Os -Wl,--gc-sections -mmcu=atmega328p -o /tmp/build4594399183737056674.tmp/Blink.cpp.elf /tmp/build4594399183737056674.tmp/Blink.cpp.o /tmp/build4594399183737056674.tmp/core.a -L/tmp/build4594399183737056674.tmp -lm
avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 /tmp/build4594399183737056674.tmp/Blink.cpp.elf /tmp/build4594399183737056674.tmp/Blink.cpp.eep
avr-objcopy -O ihex -R .eeprom /tmp/build4594399183737056674.tmp/Blink.cpp.elf /tmp/build4594399183737056674.tmp/Blink.cpp.hex
Binary sketch size: 990 bytes (of a 30720 byte maximum)

L'avant dernière ligne, te renvoie la localisation de l'hex.

A la fermeture de l'ide, tous les fichiers temporaires sont détruits.

@+

Zoroastre.

Cool je ne savais pas pour shift+ctrl qu'il faut maintenir au moment de lancé la compil. :open_mouth:
Resultat:

/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -DARDUINO=22 -I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino /var/folders/Op/OpN3xsO3HE8DcJNVjRs3n++++TI/-Tmp-/build3915765468112803808.tmp/Blink.cpp -o/var/folders/Op/OpN3xsO3HE8DcJNVjRs3n++++TI/-Tmp-/build3915765468112803808.tmp/Blink.cpp.o 
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -DARDUINO=22 -I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino /Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino/pins_arduino.c -o/var/folders/Op/OpN3xsO3HE8DcJNVjRs3n++++TI/-Tmp-/build3915765468112803808.tmp/pins_arduino.c.o 
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L 
.
.
.
/Op/OpN3xsO3HE8DcJNVjRs3n++++TI/-Tmp-/build3915765468112803808.tmp -lm 
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 /var/folders/Op/OpN3xsO3HE8DcJNVjRs3n++++TI/-Tmp-/build3915765468112803808.tmp/Blink.cpp.elf /var/folders/Op/OpN3xsO3HE8DcJNVjRs3n++++TI/-Tmp-/build3915765468112803808.tmp/Blink.cpp.eep 
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-objcopy -O ihex -R .eeprom /var/folders/Op/OpN3xsO3HE8DcJNVjRs3n++++TI/-Tmp-/build3915765468112803808.tmp/Blink.cpp.elf /var/folders/Op/OpN3xsO3HE8DcJNVjRs3n++++TI/-Tmp-/build3915765468112803808.tmp/Blink.cpp.hex 
Binary sketch size: 1018 bytes (of a 14336 byte maximum)

Ce qui me pertmet de trouver ça en début de compil.

/var/folders/Op/OpN3xsO3HE8DcJNVjRs3n++++TI/-Tmp-/build3915765468112803808.tmp/Blink.cpp

Merci zozo et sky.

Par contre ce fichier me donne un simple fichier .cpp avec les fonctions setup et loop bien formé (déclaration) qui seront appelé dans le main:

/*
  Blink
  Turns on an LED on for one second, then off for one second, repeatedly.
 
  This example code is in the public domain.
 */

#include "WProgram.h"
void setup();
void loop();
void setup() {                
  // initialize the digital pin as an output.
  // Pin 13 has an LED connected on most Arduino boards:
  pinMode(13, OUTPUT);     
}

void loop() {
  digitalWrite(13, HIGH);   // set the LED on
  delay(1000);              // wait for a second
  digitalWrite(13, LOW);    // set the LED off
  delay(1000);              // wait for a second
}

J'aurais bien voulus voir le main.cpp voir s'il y a une différence, mais il ne donne que le fichier binaire de celui ci.
A noter qu'il compile également tout ce qui ce trouve dans le cores (même HardwareSerial alors que j'ai supprimer l'inclusion dans WProgram.h), que ce soit utilisé ou non apparement.
Une idée pour un makefile ou ant ou tout ce passe dans le code java de l'ide ?

En effet le shift+verify me permet de trouver pleins de fichiers temporaires dans /var/machin/truc (oui, je suis sur mac moi aussi :slight_smile: )

mais pas la moindre ligne d'assembleur la dedans, que mon fichier .cpp de départ tel quel et le reste c'est des fichiers binaires directement :cry:

Au moins j'ai compris quelques rouages de l'IDE et du compilateur, mais ca ne m'aide pas beaucoup pour optimiser mon code.

Peut etre qu'en bidouillant les fichiers de config de l'IDE y'a moyen de creuser d'avantage ?

En utilisant avrgcc "a la main" sinon ?

Yep!

Si je reprends l'exemple d'Osaka (qui apparement est sur mac aussi :astonished:).

.../var/folders/Op/OpN3xsO3HE8DcJNVjRs3n++++TI/-Tmp-/build3915765468112803808.tmp/Blink.cpp.hex

Blink.cpp.hex à la toute fin, c'est l'hexa envoyé à l'arduino...
(Heu !!! à tout hasard, faut le lire avec un éditeur hexa, c'est mieux :wink: )

@+

Zoroastre.

EDIT :

hexdump /tmp/build4594399183737056674.tmp/Blink.cpp.hex
0000000 313a 3030 3030 3030 3030 3943 3634 3031
0000010 3030 3943 3734 3033 3030 3943 3734 3033
0000020 3030 3943 3734 3033 4230 0d36 3a0a 3031
0000030 3030 3031 3030 4330 3439 3337 3030 4330
0000040 3439 3337 3030 4330 3439 3337 3030 4330
0000050 3439 3337 3030 3439 0a0d 313a 3030 3230
0000060 3030 3030 3943 3734 3033 3030 3943 3734
0000070 3033 3030 3943 3734 3033 3030 3943 3734
0000080 3033 3830 0d34 3a0a 3031 3030 3033 3030
0000090 4330 3439 3337 3030 4330 3439 3337 3030
*
00000b0 3437 0a0d 313a 3030 3430 3030 3030 3943
00000c0 3134 3037 3031 3943 3734 3033 3030 3943
00000d0 3734 3033 3030 3943 3734 3033 4230 0d46
00000e0 3a0a 3031 3030 3035 3030 4330 3439 3337
00000f0 3030 4330 3439 3337 3030 4330 3439 3337
0000100 3030 4330 3439 3337 3030 3435 0a0d 313a
0000110 3030 3630 3030 3030 3943 3734 3033 3030
0000120 3943 3734 3033 3030 3030 3030 3030 3230
0000130 3034 3230 3037 3130 0d46 3a0a 3031 3030
0000140 3037 3030 4132 3030 3030 3030 3030 3030
0000150 3532 3030 3832 3030 4232 3030 3030 3030
0000160 3030 3030 4544 0a0d 313a 3030 3830 3030
0000170 3230 3033 3230 3036 3230 3039 3030 3034
0000180 3034 3034 3034 3034 3034 3034 3034 3032
0000190 4432 0d41 3a0a 3031 3030 3039 3030 3230
00001a0 3230 3230 3230 3330 3330 3330 3330 3330
00001b0 3330 3130 3230 3430 3830 3031 3032 3730
00001c0 0a0d 313a 3030 4130 3030 3430 3830 3030
00001d0 3031 3032 3034 3138 3230 3030 3031 3032
00001e0 3034 3138 3230 3030 3030 3130 0d32 3a0a
00001f0 3031 3030 3042 3030 3030 3730 3030 3230
0000200 3130 3030 3030 3330 3430 3630 3030 3030
0000210 3030 3030 3030 3030 3932 0a0d 313a 3030
0000220 4330 3030 3030 3030 3130 3231 3134 4246
0000230 4345 4546 4446 4538 4430 4245 4346 4244
0000240 3146 4531 3830 0d45 3a0a 3031 3030 3044
0000250 3030 3041 3045 3142 3045 3130 3043 4431
0000260 3239 3941 3033 3142 3730 3145 3746 4530
0000270 3439 3439 0a0d 313a 3030 4530 3030 4530
0000280 3036 3031 3943 4534 3044 3031 3943 3034
0000290 3030 3830 4544 3630 4531 3030 3945 4134
00002a0 0d42 3a0a 3031 3030 3046 3030 3245 3030
00002b0 3836 4545 3337 3045 3038 3045 3039 3045
00002c0 4530 3439 3538 3130 4438 3045 3031 0a0d
00002d0 313a 3030 3031 3030 3630 4530 3030 3945
00002e0 4534 3032 3630 4538 3745 4533 3830 4530
00002f0 3930 4530 3030 3945 3134 0d30 3a0a 3031
0000300 3130 3031 3030 3538 3130 3830 3539 4438
0000310 3045 3136 3045 4530 3439 4638 3030 3830
0000320 3539 3834 4632 3943 0a0d 313a 3030 3231
0000330 3030 3530 4530 4330 3041 3831 3536 3936
0000340 3446 4646 3043 3231 3934 3431 3541 3537
0000350 3446 3046 0d39 3a0a 3031 3130 3033 3030
0000360 4146 3130 3438 3139 3838 3332 3143 3046
0000370 3845 4632 3046 3045 4545 4630 4646 4631
0000380 3135 0a0d 313a 3030 3431 3030 4530 3538
0000390 4639 3446 4146 3935 4231 3934 3631 3236
00003a0 3433 4631 3934 4246 4637 3938 3034 0d35
00003b0 3a0a 3031 3130 3035 3030 4338 3139 3032
00003c0 3539 3238 3332 4338 3339 4639 4642 3830
00003d0 3539 4639 3742 3846 3439 4332 0a0d 313a
00003e0 3030 3631 3030 3830 3943 3831 3232 3842
00003f0 3943 3933 4246 3046 3938 3835 3333 3730
0000400 4631 3830 3334 4530 0d33 3a0a 3031 3130
0000410 3037 3030 3832 3446 3138 3033 3141 3046
0000420 3238 3033 3132 3546 3431 3043 3638 3033
0000430 3142 3046 4532 0a0d 313a 3030 3831 3030
0000440 3830 3337 4430 4631 3830 3334 4530 4639
0000450 3034 4334 3830 3930 3831 3030 3830 3746
0000460 3037 0d42 3a0a 3031 3130 3039 3030 3330
0000470 3043 3038 3139 3038 3030 4638 4437 3038
0000480 3339 3038 3030 3830 3539 3438 3542 3639
0000490 0a0d 313a 3030 4131 3030 3830 3746 3037
00004a0 4332 3830 4234 3835 3746 3844 4234 3044
00004b0 3938 3835 3930 4231 3030 4130 0d33 3a0a
00004c0 3031 3130 3042 3030 4638 3737 3038 3339
00004d0 3042 3030 3830 3539 3038 3139 3042 3030
00004e0 4638 4437 3038 3339 3946 0a0d 313a 3030
00004f0 4331 3030 4230 3030 3030 3938 4635 3946
0000500 3032 3946 3133 3946 4633 3236 3445 3238
0000510 3546 4530 3330 0d32 3a0a 3031 3130 3044
0000520 3030 4143 3130 3238 3535 4639 4634 4346
0000530 3130 3432 3139 4143 3130 3638 3635 4639
0000540 4634 3834 0a0d 313a 3030 4531 3030 4630
0000550 3043 3131 3934 3431 3541 3537 3446 4646
0000560 3041 3031 3934 3031 3230 4433 4639 4130
0000570 0d32 3a0a 3031 3130 3046 3030 3232 3332
0000580 3931 3046 3238 4632 4530 3439 3542 3030
0000590 3045 4632 3046 3045 4545 4630 4443 0a0d
00005a0 313a 3030 3032 3030 4630 3146 4546 3545
00005b0 4638 3446 4146 3935 4231 3934 4631 3246
00005c0 3330 4631 3934 4246 3237 0d37 3a0a 3031
00005d0 3230 3031 3030 3846 3439 4338 3139 3031
00005e0 3539 3138 3332 3430 3043 4639 3742 3846
00005f0 3439 4338 3139 3932 0a0d 313a 3030 3232
0000600 3030 3830 3231 3842 3943 3933 4246 3146
0000610 3946 3031 3946 4631 3946 3030 3938 3135
0000620 3946 3732 0d38 3a0a 3031 3230 3033 3030
0000630 4630 3239 4630 3642 4630 3239 3131 3432
0000640 4632 3339 4633 3339 4638 3339 4639 3339
0000650 4139 0a0d 313a 3030 3432 3030 4130 3946
0000660 4233 3946 3833 3930 3031 3034 3931 3930
0000670 3031 3035 4131 3930 3031 3036 4131 0d35
0000680 3a0a 3031 3230 3035 3030 3042 3139 3730
0000690 3130 3033 3139 3830 3130 3130 3639 3141
00006a0 4431 3142 4431 3332 4632 3631 0a0d 313a
00006b0 3030 3632 3030 3230 3544 3246 3344 3237
00006c0 4630 3230 3544 3037 3931 4136 3131 4244
00006d0 3131 3244 3930 3333 0d34 3a0a 3031 3230
00006e0 3037 3030 3830 3130 3038 3339 3430 3130
00006f0 3039 3339 3530 3130 3041 3339 3630 3130
0000700 3042 3339 3742 0a0d 313a 3030 3832 3030
0000710 3030 3037 3831 3930 3031 3030 3931 3930
0000720 3031 3031 4131 3930 3031 3032 4231 3930
0000730 4231 0d43 3a0a 3031 3230 3039 3030 3330
0000740 3130 3130 3639 3141 4431 3142 4431 3038
0000750 3339 3030 3130 3039 3339 3130 3130 4546
0000760 0a0d 313a 3030 4132 3030 4130 3930 3033
0000770 3032 4231 3930 3033 3033 4231 3946 4131
0000780 3946 3931 3946 3831 3946 4631 0d31 3a0a
0000790 3031 3230 3042 3030 4633 3139 4632 3139
00007a0 4630 3039 4630 4542 4630 3039 4631 3039
00007b0 3831 3539 4639 3742 3146 0a0d 313a 3030
00007c0 4332 3030 4630 3938 3234 3930 3031 3030
00007d0 3331 3930 3031 3031 3431 3930 3031 3032
00007e0 3531 3930 3731 0d38 3a0a 3031 3230 3044
00007f0 3030 3330 3130 3638 3542 3841 4239 3630
0000800 3043 4638 4633 3132 3046 4632 4635 4633
0000810 4634 4244 0a0d 313a 3030 4532 3030 3430
0000820 3446 3546 3446 3946 4246 3546 3234 3446
0000830 3233 3346 3232 3246 3232 3237 3038 3846
0000840 0d45 3a0a 3031 3230 3046 3030 3133 4431
0000850 3134 4431 3135 4431 3238 3045 3232 4630
0000860 3333 4631 3434 4631 3535 4631 3832 0a0d
0000870 313a 3030 3033 3030 3830 3941 4435 4631
0000880 4237 3039 4331 3041 3031 3938 4535 3946
0000890 4632 3946 3032 3946 3333 0d30 3a0a 3031
00008a0 3330 3031 3030 4631 3339 4643 3339 4644
00008b0 3339 4237 3130 4338 3130 4530 3439 4635
00008c0 3130 4245 3130 3036 0a0d 313a 3030 3233
00008d0 3030 3030 4345 3030 3945 3534 3046 3631
00008e0 3143 3742 3044 3642 3538 3745 3433 4330
00008f0 4638 4233 0d41 3a0a 3031 3330 3033 3030
0000900 3830 3439 3145 3830 3146 3830 3130 3930
0000910 3131 3930 3843 3135 4344 4634 3145 3431
0000920 3245 0a0d 313a 3030 3433 3030 4630 3031
0000930 3034 3031 3135 3031 3635 4639 4437 3946
0000940 4331 3946 3131 3946 3031 3946 3131 0d43
0000950 3a0a 3031 3330 3035 3030 4646 3039 4645
0000960 3039 3830 3539 3837 3439 3438 3542 3238
0000970 3036 3438 4442 3438 3542 3135 0a0d 313a
0000980 3030 3633 3030 3830 3631 3830 4234 3844
0000990 4235 3835 3632 3830 4235 3844 4235 3835
00009a0 3631 3830 4235 4244 0d30 3a0a 3031 3330
00009b0 3037 3030 4545 3645 3046 3045 3038 3138
00009c0 3138 3036 3038 3338 3145 3845 3046 3045
00009d0 3031 3238 3943 0a0d 313a 3030 3833 3030
00009e0 3830 3830 3831 3632 3830 3830 3833 3830
00009f0 3831 3631 3830 3830 4533 4530 4638 4530
0000a00 3030 0d41 3a0a 3031 3330 3039 3030 3038
0000a10 3138 3138 3036 3038 3338 3145 4245 3046
0000a20 3045 3038 3138 3438 3036 3038 3338 3446
0000a30 0a0d 313a 3030 4133 3030 4530 4530 4642
0000a40 4530 3830 3830 3831 3631 3830 3830 4533
0000a50 4541 4637 4530 3830 3830 3231 0d42 3a0a
0000a60 3031 3330 3042 3030 3438 3036 3038 3338
0000a70 3038 3138 3238 3036 3038 3338 3038 3138
0000a80 3138 3036 3038 3338 4238 0a0d 313a 3030
0000a90 4333 3030 3830 3830 3831 3630 3838 3830
0000aa0 3133 3930 4332 3031 3030 3938 3035 3945
0000ab0 4134 3042 4631 0d33 3a0a 4530 3330 3044
0000ac0 3030 4530 3439 4138 3030 4530 3439 3537
0000ad0 3030 4446 4643 3846 3439 4646 4643 3642
0000ae0 0a0d 303a 3030 3030 3030 4631 0d46 000a
0000aef

Pour l'assembleur tu en apprendra plus via la doc atmel de ton microcontrôleur que de lire un code assembleur (et surtout pas un hex :sweat_smile:) tout fait à mon avis.
L'utilisation des registres dans ton code arduino pour gagner du temps est plus intéressant également je trouve.

zoroastre:
(Heu !!! à tout hasard, faut le lire avec un éditeur hexa, c'est mieux :wink: )

Oui ... mais non !

.hex désigne un fichier texte représentant des données binaires sous le format intel hexa
(cf http://en.wikipedia.org/wiki/Intel_HEX)

Donc ouvrir un fichier .hex avec un éditeur hexa est totalement idiot !

Par contre à partir du .hex il est possible d'obtenir le code assembleur en utilisant avr studio (ou un désassembleur AVR).

Tien cette sortie console m'a permis de trouver quelque chose d'interessant -> "Compiler.java" dans le source de l'ide arduino.

Le code est assé énorme, donc juste les commentaires de la procédure.

   // 0. include paths for core + all libraries
   // 1. compile the sketch (already in the buildPath)
   // 2. compile the libraries, outputting .o files to: <buildPath>/<library>/
   // 3. compile the core, outputting .o files to <buildPath> and then
   // collecting them into the core.a library file.
    // 4. link it all together into the .elf file
    // For atmega2560, need --relax linker option to link larger
    // programs correctly.
    // 5. extract EEPROM data (from EEMEM directive) to .eep file.
    // 6. build the .hex file

Et la réponse à ma question pour make ou ant ...

  static private List getCommandCompilerS(String avrBasePath, List includePaths,
    String sourceName, String objectName, Map<String, String> boardPreferences) {
    List baseCommandCompiler = new ArrayList(Arrays.asList(new String[] {
      avrBasePath + "avr-gcc",
      "-c", // compile, don't link
      "-g", // include debugging info (so errors include line numbers)
      "-assembler-with-cpp",
      "-mmcu=" + boardPreferences.get("build.mcu"),
      "-DF_CPU=" + boardPreferences.get("build.f_cpu"),
      "-DARDUINO=" + Base.REVISION,
    }));

    List baseCommandCompiler = new ArrayList(Arrays.asList(new String[] {
      avrBasePath + "avr-gcc",
      "-c", // compile, don't link
      "-g", // include debugging info (so errors include line numbers)
      "-Os", // optimize for size
      Preferences.getBoolean("build.verbose") ? "-Wall" : "-w", // show warnings if verbose
      "-ffunction-sections", // place each function in its own section
      "-fdata-sections",
      "-mmcu=" + boardPreferences.get("build.mcu"),
      "-DF_CPU=" + boardPreferences.get("build.f_cpu"),
      "-MMD", // output dependancy info
      "-DARDUINO=" + Base.REVISION,
    }));

   List baseCommandCompilerCPP = new ArrayList(Arrays.asList(new String[] {
      avrBasePath + "avr-g++",
      "-c", // compile, don't link
      "-g", // include debugging info (so errors include line numbers)
      "-Os", // optimize for size
      Preferences.getBoolean("build.verbose") ? "-Wall" : "-w", // show warnings if verbose
      "-fno-exceptions",
      "-ffunction-sections", // place each function in its own section
      "-fdata-sections",
      "-mmcu=" + boardPreferences.get("build.mcu"),
      "-DF_CPU=" + boardPreferences.get("build.f_cpu"),
      "-MMD", // output dependancy info
      "-DARDUINO=" + Base.REVISION,
    }));

C'est pas tellement le .hex qui m'intéresse, c'est plutot le .asm mais avec les "label" et les noms de variables qui correspondent a mon .pde du départ.

Parce que désassembler le .hex pour voir ce qui change quand je modifie une ligne de programme, ca va me compliquer plus a vie que me a simplifier.

Ceci dit, mon arduino a 20 mhz est tellement plus rapide que mon ex pic a 16 mhz/4, que finalement savoir dans que ordre imbriquer mes if c'est moins important finalement. (mais bon, c'est pas une raison pour gaspiller des cycles ^^)

Pour l'example, voila le genre de trucs que j'avais "avant"

Ca c'est un morceau de C que je compile avec SDCC

#define	PIC_CLK 2000000
#include <pic16f886.h>
//unsigned int at 0x2007 __CONFIG = (_CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF & _HS_OSC & _WRT_ENABLE_ON & _LVP_OFF & _DEBUG_OFF & _CPD_OFF);
unsigned int at 0x2007 __CONFIG = 0x3732;
// super boucle d'attente
void wait(unsigned int j){
unsigned int a;
unsigned int i;
for (i=0; i<j; i++);
	{for (a=0;a<65000;a++);{;}
	}
}


// K2000 version beta
void main()
{
unsigned int delay=65000;
TRISB=0; //Port B en sortie (leds rouges)
PORTB=1;

while (1){
	while(PORTB<128){
		PORTB=PORTB<<1;
		//wait(delay);
		}
	while(PORTB>1){
		PORTB=PORTB>>1;
		//wait (delay);
		}
	}
}

Et ca c'est e bazard intermediaire que ca donne en assembleur, avant de rentrer dans GPASM

;--------------------------------------------------------
; File Created by SDCC : free open source ANSI-C Compiler
; Version 2.8.5 #5278 (Dec 12 2008) (Mac OS X i386)
; This file was generated Sat Jun  6 17:27:16 2009
;--------------------------------------------------------
; PIC port for the 14-bit core
;--------------------------------------------------------
;	.file	"k2000.c"
	list	p=16f876
	radix dec
	include "p16f876.inc"
;--------------------------------------------------------
; config word 
;--------------------------------------------------------
	__config 0x3732
;--------------------------------------------------------
; external declarations
;--------------------------------------------------------
	extern	_ADCON0_bits
	extern	_ADCON1_bits
	extern	_CCP1CON_bits
	extern	_CCP2CON_bits
	extern	_EECON1_bits
	extern	_INTCON_bits
	extern	_OPTION_REG_bits
	extern	_PCON_bits
	extern	_PIE1_bits
	extern	_PIE2_bits
	extern	_PIR1_bits
	extern	_PIR2_bits
	extern	_PORTA_bits
	extern	_PORTB_bits
	extern	_PORTC_bits
	extern	_RCSTA_bits
	extern	_SSPCON_bits
	extern	_SSPCON2_bits
	extern	_SSPSTAT_bits
	extern	_STATUS_bits
	extern	_T1CON_bits
	extern	_T2CON_bits
	extern	_TRISA_bits
	extern	_TRISB_bits
	extern	_TRISC_bits
	extern	_TXSTA_bits
	extern	_INDF
	extern	_TMR0
	extern	_PCL
	extern	_STATUS
	extern	_FSR
	extern	_PORTA
	extern	_PORTB
	extern	_PORTC
	extern	_PCLATH
	extern	_INTCON
	extern	_PIR1
	extern	_PIR2
	extern	_TMR1L
	extern	_TMR1H
	extern	_T1CON
	extern	_TMR2
	extern	_T2CON
	extern	_SSPBUF
	extern	_SSPCON
	extern	_CCPR1L
	extern	_CCPR1H
	extern	_CCP1CON
	extern	_RCSTA
	extern	_TXREG
	extern	_RCREG
	extern	_CCPR2L
	extern	_CCPR2H
	extern	_CCP2CON
	extern	_ADRESH
	extern	_ADCON0
	extern	_OPTION_REG
	extern	_TRISA
	extern	_TRISB
	extern	_TRISC
	extern	_PIE1
	extern	_PIE2
	extern	_PCON
	extern	_SSPCON2
	extern	_PR2
	extern	_SSPADD
	extern	_SSPSTAT
	extern	_TXSTA
	extern	_SPBRG
	extern	_ADRESL
	extern	_ADCON1
	extern	_EEDATA
	extern	_EEADR
	extern	_EEDATH
	extern	_EEADRH
	extern	_EECON1
	extern	_EECON2
	extern	__sdcc_gsinit_startup
;--------------------------------------------------------
; global declarations
;--------------------------------------------------------
	global	_wait
	global	_main

	global PSAVE
	global SSAVE
	global WSAVE
	global STK12
	global STK11
	global STK10
	global STK09
	global STK08
	global STK07
	global STK06
	global STK05
	global STK04
	global STK03
	global STK02
	global STK01
	global STK00

sharebank udata_ovr 0x0070
PSAVE	res 1
SSAVE	res 1
WSAVE	res 1
STK12	res 1
STK11	res 1
STK10	res 1
STK09	res 1
STK08	res 1
STK07	res 1
STK06	res 1
STK05	res 1
STK04	res 1
STK03	res 1
STK02	res 1
STK01	res 1
STK00	res 1

;--------------------------------------------------------
; global definitions
;--------------------------------------------------------
;--------------------------------------------------------
; absolute symbol definitions
;--------------------------------------------------------
;--------------------------------------------------------
; compiler-defined variables
;--------------------------------------------------------
UDL_k2000_0	udata
r0x1001	res	1
r0x1000	res	1
r0x1002	res	1
r0x1003	res	1
;--------------------------------------------------------
; initialized data
;--------------------------------------------------------
;--------------------------------------------------------
; overlayable items in internal ram 
;--------------------------------------------------------
;	udata_ovr
;--------------------------------------------------------
; reset vector 
;--------------------------------------------------------
STARTUP	code
	nop
	pagesel __sdcc_gsinit_startup
	goto	__sdcc_gsinit_startup
;--------------------------------------------------------
; code
;--------------------------------------------------------
code_k2000	code
;***
;  pBlock Stats: dbName = M
;***
;entry:  _main	;Function start
; 2 exit points
;has an exit
;; Starting pCode block
_main	;Function start
; 2 exit points
;	.line	19; "k2000.c"	TRISB=0; //Port B en sortie (leds rouges)
	BANKSEL	_TRISB
	CLRF	_TRISB
;	.line	20; "k2000.c"	PORTB=1;
	MOVLW	0x01
	BANKSEL	_PORTB
	MOVWF	_PORTB
;unsigned compare: left < lit(0x80=128), size=1
_00125_DS_
;	.line	23; "k2000.c"	while(PORTB<128){
	MOVLW	0x80
	BANKSEL	_PORTB
	SUBWF	_PORTB,W
	BTFSC	STATUS,0
	GOTO	_00128_DS_
;genSkipc:3083: created from rifx:0xbfff58c4
;	.line	24; "k2000.c"	PORTB=PORTB<<1;
	BCF	STATUS,0
	RLF	_PORTB,F
	GOTO	_00125_DS_
;swapping arguments (AOP_TYPEs 1/3)
;unsigned compare: left >= lit(0x2=2), size=1
_00128_DS_
;	.line	27; "k2000.c"	while(PORTB>1){
	MOVLW	0x02
	BANKSEL	_PORTB
	SUBWF	_PORTB,W
	BTFSS	STATUS,0
	GOTO	_00125_DS_
;genSkipc:3083: created from rifx:0xbfff58c4
;shiftRight_Left2ResultLit:4862: shCount=1, size=1, sign=0, same=1, offr=0
;	.line	28; "k2000.c"	PORTB=PORTB>>1;
	BCF	STATUS,0
	RRF	_PORTB,F
	GOTO	_00128_DS_
	RETURN	
; exit point of _main

;***
;  pBlock Stats: dbName = C
;***
;entry:  _wait	;Function start
; 2 exit points
;has an exit
;5 compiler assigned registers:
;   r0x1000
;   STK00
;   r0x1001
;   r0x1002
;   r0x1003
;; Starting pCode block
_wait	;Function start
; 2 exit points
;	.line	6; "k2000.c"	void wait(unsigned int j){
	BANKSEL	r0x1000
	MOVWF	r0x1000
	MOVF	STK00,W
	MOVWF	r0x1001
;	.line	9; "k2000.c"	for (i=0; i<j; i++);
	CLRF	r0x1002
	CLRF	r0x1003
_00105_DS_
	BANKSEL	r0x1000
	MOVF	r0x1000,W
	SUBWF	r0x1003,W
	BTFSS	STATUS,2
	GOTO	_00120_DS_
	MOVF	r0x1001,W
	SUBWF	r0x1002,W
_00120_DS_
	BTFSC	STATUS,0
	GOTO	_00108_DS_
;genSkipc:3083: created from rifx:0xbfff58c4
	BANKSEL	r0x1002
	INCF	r0x1002,F
	BTFSC	STATUS,2
	INCF	r0x1003,F
	GOTO	_00105_DS_
_00108_DS_
;	.line	10; "k2000.c"	{for (a=0;a<65000;a++);{;}
	MOVLW	0xe8
	BANKSEL	r0x1001
	MOVWF	r0x1001
	MOVLW	0xfd
	MOVWF	r0x1000
_00111_DS_
	MOVLW	0xff
	BANKSEL	r0x1001
	ADDWF	r0x1001,F
	BTFSS	STATUS,0
	DECF	r0x1000,F
	MOVF	r0x1001,W
	IORWF	r0x1000,W
	BTFSS	STATUS,2
	GOTO	_00111_DS_
	RETURN	
; exit point of _wait


;	code size estimation:
;	   48+    9 =    57 instructions (  132 byte)

	end

Ca c'etait un exemple "simple", jute pour voir s'il fallait mieux faire un machin=machin>>1 ou machin=machin/2 ou je ne sait pus quelle autre formule qui reviens au meme.

L'idée c'est de faire le meme genre d'essais mais sur arduino

Pour examiner le code produit j'utilise le dessassembleur avr-objdump sur le fichier .elf (pas le fichier .hex)
(avr-objdump est dans le repertoire \hardware\tools\avr\bin)

essai rapide sous windows XP:
blink.cpp.elf 'attrappé' dans le répertoire temporaire puis copié dans le répertoire d'avr-objdump sous le nom blink.elf
commande : avr-objdump -D -S blink.elf > blink.lst
la syntaxe d'avr-objdump correspond içi à un désassemblage complet et à une sortie imbriquant source C et assembleur. Voir les nombreuses autres options

voilà par exemple la partie loop() :

void loop() {
  digitalWrite(13, HIGH);   // set the LED on
 100:	8d e0       	ldi	r24, 0x0D	; 13
 102:	61 e0       	ldi	r22, 0x01	; 1
 104:	0e 94 9c 01 	call	0x338	; 0x338 <digitalWrite>
  delay(1000);              // wait for a second
 108:	68 ee       	ldi	r22, 0xE8	; 232
 10a:	73 e0       	ldi	r23, 0x03	; 3
 10c:	80 e0       	ldi	r24, 0x00	; 0
 10e:	90 e0       	ldi	r25, 0x00	; 0
 110:	0e 94 e2 00 	call	0x1c4	; 0x1c4 <delay>
  digitalWrite(13, LOW);    // set the LED off
 114:	8d e0       	ldi	r24, 0x0D	; 13
 116:	60 e0       	ldi	r22, 0x00	; 0
 118:	0e 94 9c 01 	call	0x338	; 0x338 <digitalWrite>
  delay(1000);              // wait for a second
 11c:	68 ee       	ldi	r22, 0xE8	; 232
 11e:	73 e0       	ldi	r23, 0x03	; 3
 120:	80 e0       	ldi	r24, 0x00	; 0
 122:	90 e0       	ldi	r25, 0x00	; 0
 124:	0e 94 e2 00 	call	0x1c4	; 0x1c4 <delay>
}
 128:	08 95       	ret

listing blink complet désassemblé joint ci dessous

blink.zip (37.5 KB)

J'ai beaucoup "travaillé" sur l'optimisation de code arduino, mais finalement, j'utilise au max les registres et au minimum les fonctions arduino. il suffit de compiler ces deux codes. il font exactement la même chose : faire clignoter le plus rapidement possible la led 13.
(J'ai compilé pour une méga 2560, c'est ce que j'avais sous la main)

void setup() {
  pinMode (13, OUTPUT);
}

void loop() {
  digitalWrite(13, !digitalRead(13));
}

Compilation : 1486 octets
INTERPRETATION :

t = 5µs / div
Temps d'exécution de loop() : 14µs, mais de temps en temps 20µs comme en témoignent la partie haute du signal qui se prolonge sur 4 div (moins illuminée). Cette "prolongation" n'intervient que sur une mise à 0 de pin13 (why?).
Nombre de cycles occupés par la fonction loop() : 224
Fréquence en sortie pin 13 : 35,715KHz, 29,412KHz quand on a une prolongation.
Je n'ai pas trop cherché à trouver la récurrence de cette prolongation parasite, mais cela semble bien régulier. Il est possible qu'elle provienne de l'ISR du timer 0 (pour les variables des fonctions millis() et micros()). Cette prolongation représenterait environ 96 cycles d'horloge.

void setup() {
  DDRB |= 0x80;   // B7 en sortie (pin 13 de la méga)
}

void loop() {
  PORTB ^= 0x80;   // ou exclusif : inverse le bit 7 de PORTB
}

Compilation : 670 octets
INTERPRETATION :

t = 0,5µs / div
Temps d'exécution de loop() : 0,92µs, on n'observe pas de prolongation.
Nombre de cycles occupés par la fonction loop() : 15
Fréquence en sortie pin 13 : 533,33KHz
De petites oscillations sont visibles (environ 32MHz, le double du quartz, mais elles viennent peut-être de l'oscilo, à cette vitesse, les mesures ne sont peut-être pas fiables, l'oscillo est donné pour 40MHz max). on a aussi un signal périodique parasite à 5.55MHz mais qui doit aussi provenir de l'oscillo ou l'association des capacités internes de l'arduino, de la led 13 et de l'oscillo.

Conclusion : On gagne un rapport 2,22 en taille de programme, et un rapport entre 15 et 17 sur la rapidité d'exécution. C'est déjà une belle avancée. Bien sûr, côté programmation, un digitalWrite(pin_num, value) est bien plus souple qu'un PORTx |= value ou PORTx &= value, mais si on a vraiment besoin de rapidité, alors ça vaut le coup d'y réfléchir.

Pour ce qui est de l'utilisation de la lib timer2ms, je la déconseille fortement, on en avait déjà parlé dans un topic de 68tjs. Cette librairie est très lourde de code et la valeur envoyée en tant qu'intervalle de timer n'est pas du tout vérifiée en sortie. En deux ou trois instructions, on renseigne les registres du timer, et c'est mille fois plus rapide et d'une précision sans faute (il en va de même pour les servos, la lib servo n'est compatible avec aucune autre fonction avancée, le servo se met à trembler).

Je crois qu'un topic regroupant les optimisations simples serait utile...

Merci a tous, c'est tout a fait le genre de choses que je voulais voir/savoir.

Dans la majeure partie des cas les fonctions "toutes faites" d'arduino font parfaitement l'affaire, mais c'est toujours intéressant et parfois utile de pouvoir aller plus loin.

Bonne idée ce topic sur les optimisations !
(C'est un sujet sans fin, la chose risque d’être assez compliquée en fait.)

C'est interessant void le code en assembly pour apprendre a lui utilisé.

C'est a dire que en plusieurs problémes une bonne chose est faire le programme
principal en langage de haut niveau qui apelle une function en assembly.

Au cas du arduino est-que quelqu'un ici a melangé le code en langague Arduino
et assembly? Est-que utilisé asm() est une bonne solution?

Super_Cinci:
J'ai beaucoup "travaillé" sur l'optimisation de code arduino, mais finalement, j'utilise au max les registres et au minimum les fonctions arduino. il suffit de compiler ces deux codes. il font exactement la même chose : faire clignoter le plus rapidement possible la led 13.
(J'ai compilé pour une méga 2560, c'est ce que j'avais sous la main)

Je crois qu'un topic regroupant les optimisations simples serait utile...

démo très intéressante et bien illustrée avec un bon vieil oscillo analogique :grin:

pledoux:
Au cas du arduino est-que quelqu'un ici a melangé le code en langague Arduino
et assembly? Est-que utilisé asm() est une bonne solution?

Dans la lib avr on en rencontre souvent, il suffit d'une simple directive au compilateur.

__asm__ __volatile__ ();

voir util/crc16.h par exemple:

/** \ingroup util_crc
    Optimized CRC-16 calculation.

    Polynomial: x^16 + x^15 + x^2 + 1 (0xa001)

    Initial value: 0xffff

    This CRC is normally used in disk-drive controllers.

    The following is the equivalent functionality written in C.

    \code
    uint16_t
    crc16_update(uint16_t crc, uint8_t a)
    {
	int i;

	crc ^= a;
	for (i = 0; i < 8; ++i)
	{
	    if (crc & 1)
		crc = (crc >> 1) ^ 0xA001;
	    else
		crc = (crc >> 1);
	}

	return crc;
    }

    \endcode */

static __inline__ uint16_t
_crc16_update(uint16_t __crc, uint8_t __data)
{
	uint8_t __tmp;
	uint16_t __ret;

	__asm__ __volatile__ (
		"eor %A0,%2" "\n\t"
		"mov %1,%A0" "\n\t"
		"swap %1" "\n\t"
		"eor %1,%A0" "\n\t"
		"mov __tmp_reg__,%1" "\n\t"
		"lsr %1" "\n\t"
		"lsr %1" "\n\t"
		"eor %1,__tmp_reg__" "\n\t"
		"mov __tmp_reg__,%1" "\n\t"
		"lsr %1" "\n\t"
		"eor %1,__tmp_reg__" "\n\t"
		"andi %1,0x07" "\n\t"
		"mov __tmp_reg__,%A0" "\n\t"
		"mov %A0,%B0" "\n\t"
		"lsr %1" "\n\t"
		"ror __tmp_reg__" "\n\t"
		"ror %1" "\n\t"
		"mov %B0,__tmp_reg__" "\n\t"
		"eor %A0,%1" "\n\t"
		"lsr __tmp_reg__" "\n\t"
		"ror %1" "\n\t"
		"eor %B0,__tmp_reg__" "\n\t"
		"eor %A0,%1"
		: "=r" (__ret), "=d" (__tmp)
		: "r" (__data), "0" (__crc)
		: "r0"
	);
	return __ret;
}