www.mikrocontroller.net

Forum: Compiler & IDEs Array über Inline-Assembler ansprechen?


Autor: Martin Meyer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo allerseits,

habe gerade folgendes Problem: In einer Interrupt-Routine (Timer) soll 
ein 8bit-Wert aus einem Array an einen Port ausgegeben werden. Es gibt 
eine globale Variable, die die aktuelle Position im Array markiert, 
diese wird in der Timer-Routine inkrementiert. Stellt euch das ganze als 
eine Art Spieluhr vor, das Array ist die Programmwalze.

Hier ist der C-Code, der auch funktioniert:

SIGNAL (SIG_OUTPUT_COMPARE1A)
{
  PortA = program[pos];
  pos++;
  if (pos > prog_len) pos = 0;
}

Das Problem ist nur, daß die maximal geforderte Taktfrequenz nicht 
erreicht wird, weil der vom AVR-GCC erzeugte Code doch recht lang ist. 
In Assembler wären das weniger als 10 Byte.

Allerdings möchte ich nicht das ganze Programm in Assembler schreiben, 
weil es auch einige floating-point-Berechnungen in der Anwendung gibt.

Deshalb nun meine Frage: Kann ich eine ISR auch in Inline-Assembler 
schreiben? Wenn ja, wie spreche ich das Array an? Wie finde ich die 
Startadresse? Wie bekomme ich den Index in das Z-Register? Wie teile ich 
"C" mit, welche Register ich verwurschtelt habe? Muß ich die selber auf 
den Stack schieben oder macht der Compiler das selbst?

Ich habe zwar im Netz ein Tutorial gefunden, aber das ist so kryptisch, 
daß ich nach einer Weile aufgegeben habe. Vielleicht kann mich einer mal 
in die richtige Richtung stoßen, so daß es "klick" macht.

Danke!!!

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ist wenn du das so umschreibst:
uint8_t* pos;
uint8_t* last;

SIGNAL (SIG_OUTPUT_COMPARE1A)
{
  PortA = *pos++;
  if( pos > last )
    pos = program;
}

int main()
{
  pos = program;
  last = pos + prog_len;

   ...

  

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

SIGNAL (SIG_OUTPUT_COMPARE1A)
{
  if (pos < prog_len)
  {
     pos++;
  }
  else
  {
     pos = 0;
  }
  PortA = program[pos];
}

sollte noch kürzer sein

MW

Autor: Martin Meyer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok... Hat 3 Minuten gedauert, bis ich das verstanden habe, aber macht 
Sinn! Ich probiere das nach Feierabend mal aus und melde mich dann 
wieder!

Danke schonmal!

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Hauptvorteil den ich mir verspreche liegt darin,
dass ich die Arrayindizierung aus der ISR raus kriege.

So gehts noch einen Tick schneller
Achte auf die Deklaration von 'last'. Da ist jetzt noch
ein const mit drinnen.
#include <avr/io.h>
#include <avr/signal.h>

#define prog_len 20
uint8_t program[prog_len];

uint8_t* pos;
uint8_t* const last = program + prog_len;

SIGNAL (SIG_OUTPUT_COMPARE1A)
{
  PORTA = *pos++;
  if( pos > last )
    pos = program;
}

int main()
{
  pos = program;
//  last = pos + prog_len;
}

SIGNAL (SIG_OUTPUT_COMPARE1A)
{
  8e:  1f 92         push  r1
  90:  0f 92         push  r0
  92:  0f b6         in  r0, 0x3f  ; 63
  94:  0f 92         push  r0
  96:  11 24         eor  r1, r1
  98:  8f 93         push  r24
  9a:  9f 93         push  r25
  9c:  ef 93         push  r30
  9e:  ff 93         push  r31
  PORTA = *pos++;
  a0:  e0 91 76 00   lds  r30, 0x0076
  a4:  f0 91 77 00   lds  r31, 0x0077
  a8:  81 91         ld  r24, Z+
  aa:  f0 93 77 00   sts  0x0077, r31
  ae:  e0 93 76 00   sts  0x0076, r30
  b2:  8b bb         out  0x1b, r24  ; 27
  if( pos > last )
  b4:  e6 57         subi  r30, 0x76  ; 118
  b6:  f0 40         sbci  r31, 0x00  ; 0
  b8:  39 f0         breq  .+14       ; 0xc8 <__vector_6+0x3a>
  ba:  30 f0         brcs  .+12       ; 0xc8 <__vector_6+0x3a>
    pos = program;
  bc:  82 e6         ldi  r24, 0x62  ; 98
  be:  90 e0         ldi  r25, 0x00  ; 0
  c0:  90 93 77 00   sts  0x0077, r25
  c4:  80 93 76 00   sts  0x0076, r24
  c8:  ff 91         pop  r31
  ca:  ef 91         pop  r30
  cc:  9f 91         pop  r25
  ce:  8f 91         pop  r24
  d0:  0f 90         pop  r0
  d2:  0f be         out  0x3f, r0  ; 63
  d4:  0f 90         pop  r0
  d6:  1f 90         pop  r1
  d8:  18 95         reti

Ein Register, R25, hätte er noch einsparen können, wenn ich
das richtig sehe. Aber sonst sehe ich nicht mehr viel
was überflüssig wäre.


Wie lauten eigentlich die Forumskürzel für Assemblercode?
Also das Äquivalent zu [ C ] [ /C ]

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das war jetzt mit OPtimizer auf -Os

Auf -O3 generiert der gcc Folgendes
SIGNAL (SIG_OUTPUT_COMPARE1A)
{
  8e:  1f 92         push  r1
  90:  0f 92         push  r0
  92:  0f b6         in  r0, 0x3f  ; 63
  94:  0f 92         push  r0
  96:  11 24         eor  r1, r1
  98:  2f 93         push  r18
  9a:  3f 93         push  r19
  9c:  8f 93         push  r24
  9e:  9f 93         push  r25
  a0:  ef 93         push  r30
  a2:  ff 93         push  r31
  PORTA = *pos++;
  a4:  e0 91 76 00   lds  r30, 0x0076
  a8:  f0 91 77 00   lds  r31, 0x0077
  ac:  81 91         ld  r24, Z+
  ae:  8b bb         out  0x1b, r24  ; 27
  if( pos > last )
  b0:  80 e0         ldi  r24, 0x00  ; 0
  b2:  e6 37         cpi  r30, 0x76  ; 118
  b4:  f8 07         cpc  r31, r24
  b6:  41 f0         breq  .+16       ; 0xc8 <__vector_6+0x3a>
  b8:  38 f0         brcs  .+14       ; 0xc8 <__vector_6+0x3a>
    pos = program;
  ba:  22 e6         ldi  r18, 0x62  ; 98
  bc:  30 e0         ldi  r19, 0x00  ; 0
  be:  30 93 77 00   sts  0x0077, r19
  c2:  20 93 76 00   sts  0x0076, r18
  c6:  04 c0         rjmp  .+8        ; 0xd0 <__vector_6+0x42>
  c8:  f0 93 77 00   sts  0x0077, r31
  cc:  e0 93 76 00   sts  0x0076, r30
  d0:  ff 91         pop  r31
  d2:  ef 91         pop  r30
  d4:  9f 91         pop  r25
  d6:  8f 91         pop  r24
  d8:  3f 91         pop  r19
  da:  2f 91         pop  r18
  dc:  0f 90         pop  r0
  de:  0f be         out  0x3f, r0  ; 63
  e0:  0f 90         pop  r0
  e2:  1f 90         pop  r1
  e4:  18 95         reti

eher schwach.
2 neue Register angepatzt. Und die Sequenz
  ...
    pos = program;
  ba:  22 e6         ldi  r18, 0x62  ; 98
  bc:  30 e0         ldi  r19, 0x00  ; 0
  be:  30 93 77 00   sts  0x0077, r19
  c2:  20 93 76 00   sts  0x0076, r18
  c6:  04 c0         rjmp  .+8        ; 0xd0 <__vector_6+0x42>
  c8:  f0 93 77 00   sts  0x0077, r31
  cc:  e0 93 76 00   sts  0x0076, r30
  d0:  ff 91         pop  r31
  ...
könnte auch besser sein.
  ...
  ldi  r31, 0x62  ; 98
  ldi  r30, 0x00  ; 0
  sts  0x0077, r31
  sts  0x0076, r30
  pop  r31
  ...

  

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin Meyer wrote:

> Deshalb nun meine Frage: Kann ich eine ISR auch in Inline-Assembler
> schreiben?

Ja, aber ich würde es dann eher gleich komplett in Assembler
schreiben.

Siehe auch http://avr-libc.nongnu.org/user-manual/group__asmdemo.html

> Wenn ja, wie spreche ich das Array an?

Ist ein globaler Name.

> Wie finde ich die
> Startadresse?

Der Name ist die Startadresse.

> Wie bekomme ich den Index in das Z-Register?

Mit MOV?

> Wie teile ich
> "C" mit, welche Register ich verwurschtelt habe?

Als clobber list.

> Muß ich die selber auf
> den Stack schieben oder macht der Compiler das selbst?

Um die clobbers kümmert sich der Compiler.

> Ich habe zwar im Netz ein Tutorial gefunden, aber das ist so kryptisch,
> daß ich nach einer Weile aufgegeben habe.

Inline-Assembler ist auf Grund der vielen Möglichkeiten kryptisch.
Daher ja auch mein Rat, es wenn schon dann gleich separat als
Assemblerquelle zu schreiben.

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
   \   __nearfunc __interrupt void timer1_ovf_isr();
   \                     timer1_ovf_isr:
   \   00000000   93FA                       ST      -Y,R31
   \   00000002   93EA                       ST      -Y,R30
   \   00000004   932A                       ST      -Y,R18
   \   00000006   931A                       ST      -Y,R17
   \   00000008   930A                       ST      -Y,R16
   \   0000000A   B72F                       IN      R18,0x3F
     10            if (pos < prog_len)
   \   0000000C   9100....                   LDS     R16,pos
   \   00000010   9110....                   LDS     R17,prog_len
   \   00000014   1701                       CP      R16,R17
   \   00000016   F428                       BRCC    ??timer1_ovf_isr_0
     11            {
     12               pos++;
   \   00000018   ....                       LDI     R30,LOW(pos)
   \   0000001A   ....                       LDI     R31,(pos) >> 8
   \   0000001C   9503                       INC     R16
   \   0000001E   8300                       ST      Z,R16
   \   00000020   C003                       RJMP    ??timer1_ovf_isr_1
     13            }
     14            else
     15            {
     16               pos = 0;
   \                     ??timer1_ovf_isr_0:
   \   00000022   E000                       LDI     R16,0
   \   00000024   9300....                   STS     pos,R16
     17            }
     18            PORTA = program[pos];
   \                     ??timer1_ovf_isr_1:
   \   00000028   9100....                   LDS     R16,pos
   \   0000002C   E010                       LDI     R17,0
   \   0000002E   01F8                       MOVW    R31 : R30,R17 : R16
   \   00000030   ....                       SUBI    R30,LOW((-(program) 
& 0xFFFF))
   \   00000032   ....                       SBCI    R31,(-(program) & 
0xFFFF) >> 8
   \   00000034   8100                       LD      R16,Z
   \   00000036   BB0B                       OUT     0x1B,R16
     19          }
   \   00000038   BF2F                       OUT     0x3F,R18
   \   0000003A   9109                       LD      R16,Y+
   \   0000003C   9119                       LD      R17,Y+
   \   0000003E   9129                       LD      R18,Y+
   \   00000040   91E9                       LD      R30,Y+
   \   00000042   91F9                       LD      R31,Y+
   \   00000044   9518                       RETI

Und das macht IAR daraus.

MW

Autor: Martin Meyer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Recht herzlichen Dank für alle Eure Hilfen!

Dieses Forum ist wirklich toll, besonders wenn man merkt, daß wirkliche 
Profis sich die Zeit nehmen, einem Anfänger zu helfen.

Mit einer "anderen Formulierung" in C nach Karl-Heinz bin ich nun in der 
Lage, die nötige Taktfrequenz auch ohne Assembler zu erreichen. Damit 
kann ich mich dann mal in Ruhe beschäftigen, wenn ich Zeit habe ;)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:

> Wie lauten eigentlich die Forumskürzel für Assemblercode?
> Also das Äquivalent zu [ C ] [ /C ]

[ avrasm ]
...
[ /avrasm ]

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.