Inline Assembler

Hallo Programmierer,

ich habe ein kleines Problem was die Verbindung zwischen C(++) und Assembler angeht.

void asmTest(uint8_t argC)
{
  uint8_t outC = 0;
  do
  {
    outC++;
    //super-zeitkritisches Zeug
  }while(--argC);
  
  Serial.println(outC); //gibt 42 aus, wie es sein soll
}
void setup()
{
  Serial.begin(9600);
}
void loop()
{
  asmTest(42);
}

Das Programm funktioniert soweit , da das ganze sehr zeitkritisch ist, muss aber ich die do-while schleife in assembler schreiben:

void asmTest(uint8_t argC)
{
  uint8_t outC = 0;
  
  asm volatile(";asm\n"
  "counter:\n"
  "inc %[outA]\n"
  "dec %[argA]\n"
  "brne counter\n"
  : [argA]"=r"(argC), [outA]"=r"(outC)
  :
  );
  
  Serial.println(outC); //gibt 52 aus obwohl es 42 ausgeben sollte
}
void setup()
{
  Serial.begin(9600);
}
void loop()
{
  asmTest(42);
}

Das funktioniert aber irgendwie nicht: Statt 42 gibt Serial.println(outC) 52 aus.

Ich hoffe ihr könnt mir sagen wie man es richtig macht, und woher die 52 kommt.

Ich würde dir vorschlagen: 1. die IDE zwingen dir einen Assemblerdump auszugeben 2. Den Assembler Kram in einer Lib unterbringen dann kompiliert es auch *.S Dateien

Hallöle, hier liegt wohl ein Missverständniss der "Constraint"-Charakter im I/O-Bereich des ASM-Codes vor. Folgender geänderter Code liefert die gewünschte "42"...

void setup()
{ 
  Serial.begin(9600);
}
void loop()
{
  asmTest(42);
}

void asmTest( uint8_t argC )
{
  uint8_t outC = 0;

  asm volatile
  (
    "cnt:    INC   %[outA]  \n\t"
    "        DEC   %[argA]  \n\t"
    "        BRNE  cnt      \n\t"
    : [argA] "+r"  (argC),  
      [outA] "+r"  (outC) 
    :
  );

  Serial.println( outC ); // gibt 42 aus wie es sein sollte
}

Die "Constraints" sind nicht einfach zu verstehen und ich musste auch zuerst etwas "um die Ecke" denken, dann aber ging es sogar mit 32Bit-Werten... Gute Info dazu >>> http://www.nongnu.org/avr-libc/user-manual/inline_asm.html Rudi

Wobei outC als Ausgang mit = passt. Aber argC muss read/write sein

Modifier Specifies
= Write-only operand, usually used for all output operands.

  • Read-write operand
    & Register should be used for output only

Output operands must be write-only…

@RudiDL5 & Serenifly Danke, wenn man sowohl argC als auch outC mit + macht funktioniert es. Seltsamerweise gibt es bei = bei outC weiterhin 52 aus (liegt es daran dass Incrementieren ja eig. nicht nur schreiben sondern lesen, um eins erhöhen und dann schreiben ist?)

wenn ich [name]"&r"(var) mache steht da:

sketch_aug13a.ino: In function 'void asmTest(uint8_t)':
sketch_aug13a:12: error: output operand constraint lacks '='
sketch_aug13a:12: error: output operand constraint lacks '='
sketch_aug13a:12: error: invalid lvalue in asm output 1
output operand constraint lacks '='

@ michael_x er ist langsamer, mehrere Takte. Ich muss eine Ledleiste ansteuern, und 850-400ns pulse senden. Da ist die Zeit nicht drinnen. Außerdem könnte es sein dass eine andere Compilerversion das ganze schneller/langsamer macht -> funktioniert nicht auf jedem PC da die pulse genau so und so lang sein müssen.

@combie Dann muss ich aber die Ganze Funktion in asm schreiben. Das löst mein Problem nicht dass ich nicht in asm auf C(++) variablen zugreifen kann.

Seltsamerweise gibt es bei = bei outC weiterhin 52 aus (liegt es daran dass Incrementieren ja eig. nicht nur schreiben sondern lesen, um eins erhöhen und dann schreiben ist?)

Ich hatte es mit mehreren verschiedenen Argumenten probiert und es ging

Seltsamerweise gibt es bei = bei outC

Genau das selbe habe ich gerade auch festgestellt.

    : [argA] "=r"  (argC),  
      [outA] "+r"  (outC)
    :

und

    : [argA] "+r"  (argC),  
      [outA] "+r"  (outC)
    :

Liefern auf jeden Fall 42

(liegt es daran dass Incrementieren ja eig. nicht nur schreiben sondern lesen, um eins erhöhen und dann schreiben ist?)

So in der Art muss man das verstehen. Im Fall "+" setzt der Compiler 2 Register ein, damit er den Output nicht durch den Input überschreibt. Ist 'ne echt böse Falle ;)

Mhhh. Könnte schwören dass es mit = ging. Vielleicht habe ich mich auch geirrt und auf die Schnelle die ++ Version hochgeladen :s