ASM fonction ADD

Bonjour, dans le cadre d'un petit projet, je dois faire un programme sur Arduino qui permet d'afficher les valeur de la suie de Fabinacci.

J'aimerai ici juste comprendre la fonction ADD et savoir comment l'utiliser, sur internet j'ai un peu de mal sur l'asm et je me perds facilement dans ce tsunami de nouvelles choses.

Voici ma partie de code, j'aimerai que 'value2' s'ajoute à la valeur de 'value', soit value = value + value2.

volatile uint8_t value = 10;
volatile uint8_t value2 = 10;

void setup()
{
    Serial.begin(9600);
    asm(
        "lds %0, (value)"
        "add %0, (value2)"
        :"=r" (value)
    );
    Serial.print("Value = ");Serial.println(value);
}
 
void loop(void) { }

Merc d'avance pour vos réponses. :wink:

il a une cheminée qui tire mal ce Fabinacci ?? :slight_smile:
peut-être voulez vous parler de la suite de Fibonacci?

pourquoi écrire en assembleur ?

Ahah oui bien vu je me suis mal relu ^^ en effet c'est de la suite de Fabinacci que je parlais, c'est dans le cadre d'un projet, afin de comprendre comment marche le langage machine ect...

un truc de ce genre (tapé ici, non testé) devrait faire une addition

volatile uint8_t value1 asm("value1") __attribute__ ((used)) = 15;
volatile uint8_t value2 asm("value2") __attribute__ ((used)) = 20;

void setup() {
  Serial.begin(115200);
  asm
  (
    "lds r16, (value1)  \n"
    "lds r17, (value2)  \n"
    "add r16, r17       \n"
    "sts (value1), r16  \n"
  );
  Serial.println(value1);
}

void loop() {}

ou

volatile uint8_t value1 asm("v1") __attribute__ ((used)) = 15;
volatile uint8_t value2 asm("v2") __attribute__ ((used)) = 20;

void setup() {
  Serial.begin(115200);
  asm
  (
    "lds r16, v1  \n"
    "lds r17, v2  \n"
    "add r16, r17 \n"
    "sts v1, r16  \n"
  );
  Serial.println(value1);
}

void loop() {}

(si on veut faire concis en utilisant les noms des variables associés pour l'assembleur)

Merci de ta réponse, en effet le programme marche correctement, je me doute que les r16 et r17 viennent de la mémoire, mais comment connaître ces cases mémoires ? (exemple si il y en a d'autre du type r17, r18 ect).

ps: je suis sur une arduino UNO, je ne sais pas si ca influe...

As tu regarder dans la documentation?
J'ai l'impression que tu essaye de programmer en assembler au feeling?

Je ne suis pas spécialiste des processeurs Atmel, mais j'ai trouvé ce document qui me semble assez complet.

1 Like

r16 et r17 ce sont des registres. cf dans le doc pointé par @terwal

Oui le fait d'être sur un UNO compte, en tout cas le MCU sous jacent quand on écrit en assembleur. ça ne fonctionnerait pas sur un ESP32

lisez le AVR Instruction Set Manual

1 Like

Merci de ton message, en effet j'ai fait des recherches de mon côté, et c'est la première fois que je fais de l'ASM (et aussi m'intéresser aux machines ect) et je ne comprend pas toujours tout ce qui m'est présenté sur internet ^^

Si jamais ca intéresse quelqu'un, j'ai du comparer la rapidité entre le calcul en C et en ASM de la suite de Fabinacci.

volatile uint8_t aa asm("aa")     = 1;
volatile uint8_t bb asm("bb")     = 2;
volatile uint8_t rASM asm("rASM") = 0;

void setup() {
  Serial.begin(9600);
  long start = micros();
  int compt = 0;
  int compt2 = 0;
  int limit = 10;
  
  while(compt<limit){
    fiboASM();
    compt++;
  }
  
  long endASM = micros();
  
  while(compt2<limit){
    fibo();
    compt2++;
  }

  long endN = micros();
  Serial.print("ASM time : ");  Serial.println(endASM - start);
  Serial.print("C time : ");    Serial.println(endN - endASM);
}


long fiboASM(){
  /*
  asm
  (
    "lds r18, 1      \n"
    "lds r16,(aa)    \n"
    "lds r17,(bb)    \n"
    "add r18, r16    \n"
    "add r18, r17    \n"
    "sts (aa), r17   \n"
    "sts (bb), r18   \n"
    "sts (rASM), r18 \n"
    );
 */
  asm
  (
    "lds [0x12], 1        \n"
    "lds [0x10], (aa)     \n"
    "lds [0x11], (bb)     \n"
    "add [0x12], [0x10]   \n"
    "add [0x12], [0x11]   \n"
    "sts (aa), [0x11]     \n"
    "sts (bb), [0x12]     \n"
    "sts (rASM), [0x12]   \n"
    );
    
    Serial.println(rASM); 
}

long a = 1;
long b = 2;
long fibo(){
  long r = a + b;
  a = b;
  b = r;
  Serial.println(r);
  }

void loop(){
  
}

Il n'est peut être pas optimisé à 100% mais l'essentiel est ici.
Ce qui donne dans la console (sur les 10 premiers nombres) :
image

ce n'est pas très judicieux de rajouter un Serial.print() dans la boucle !

vous ne pouvez pas comparer des maths sur un octet avec des maths sur un long... et en plus le print vient mettre le bazar...

essayez cela plutôt

volatile uint8_t aa asm("aa")     = 1;
volatile uint8_t bb asm("bb")     = 2;
volatile uint8_t rASM asm("rASM") = 0;

long fiboASM() {
  asm
  (
    "lds [0x12], 1        \n"
    "lds [0x10], (aa)     \n"
    "lds [0x11], (bb)     \n"
    "add [0x12], [0x10]   \n"
    "add [0x12], [0x11]   \n"
    "sts (aa), [0x11]     \n"
    "sts (bb), [0x12]     \n"
    "sts (rASM), [0x12]   \n"
  );
}

uint8_t a = 1;
uint8_t b = 2;
uint8_t fibo() {
  uint8_t r = a + b;
  a = b;
  b = r;
}


void setup() {
  Serial.begin(115200);
  unsigned long start, dureeASM, dureeCpp;

  start = micros();
  for (byte compt = 0; compt < 10; compt++) fiboASM();
  dureeASM = micros() - start;

  start = micros();
  for (byte compt = 0; compt < 10; compt++) fibo();
  dureeCpp = micros() - start;

  Serial.print("ASM time :\t");  Serial.println(dureeASM);
  Serial.print("C time :\t");    Serial.println(dureeCpp);
}

void loop() {}

ASM time :	12
C time :	8

comme micros() à une résolution de 4µs on ne peut pas en conclure quoi que ce soit...

votre code assembleur ne pourra pas aller bcp plus loin que 10 itérations puisque vous travaillez juste sur 8 bits... en C on peut prendre un unsigned long ou unsigned long long et rien qu'en changeant le type on a un code fonctionnel qui va plus loin...

pas d'avantage à utiliser l'assembleur pour ce genre de choses

1 Like

Oui le but de l'exercice est de voir comment ça marche, et aussi de voir cette subtilité sur 8 bits.
En effet les Serial.print ralentissent plus qu'autre chose...

Non seulement ça ralenti, mais ça fausse complètement la comparaison.

Serial étant buffurisé, dans la première boucle le buffer n'est pas plein et Serial.println() range les caractères dans le buffer très rapidement, mais dans la deuxième boucle le buffer est plein et Serial.println() doit attendre que de la place dans le buffer se libère (par transmission d'un caractère) pour ranger les caractères dans le buffer.

D'ailleurs si tu inverses et que tu fais le calcul en C en premier tu verras que le calcul en C prend 1184 µs et le calcul en assembleur 12412 µs

Tu n'as pas que ADD qui existe, et il pourrait être intéressant de regarder comment le compilateur gère des entiers sur 32 ou 64 bits.
D'ailleurs je pense que ADC, qui est la même chose que ADD mais qui tient compte de la retenue serait intéressant à regarder :slight_smile: :grinning: :

Bonjour

Ce logiciel léger (sous Windows ou Linux) pourrait peut être faciliter le travail d'édition, d'assemblage et de suivi, au besoin pas à pas, du contenu des registres, des ports, de la RAM...... tout ce qu'il faut pour entrer dans l'intimité d'une puce AVR !

http://www.avr-asm-tutorial.net/avr_sim/index_en.html

1 Like

Merci beaucoup de ta réponse, en effet je comprend ce que tu veux dire et j'ai cherché sur internet comment marche un buffer (Buffer circulaire — Wikipédia). Tout est plus claire maintenant !

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.