Forum: Compiler & IDEs Sprungtabelle in Assembler


von Christian Rötzer (Gast)


Lesenswert?

Hallo AVR-Fans,
um meinen Strom von Anfragen nicht abreissen zu lassen, kommt hier schon 
wieder die nächste :-)
Also:
Wie kann ich in GCC-Assembler-Code eine Sprungtabelle im ROM definieren 
und zwar so, daß die Adresse NICHT zur Laufzeit durch zwei geteilt wird 
(ich kenne bereits die Funktionen pm_lo8 und pm_hi8, mit denen man so 
ähnliche Dinge erreicht, aber die helfen nichts)

Beispiel:

ziel1:
  ; code...
ziel2:
  ; code...

sprung_tabelle:
  .word ziel1 >> 1
  .word ziel2 >> 1

So würde es im Prinzip aussehen, weil der Prozessor Wortadressen 
benötigt (von Vorwärtsreferenzen wage ich momentan noch gar nicht zu 
träumen). Leider packt das aber der Assembler nicht. Gibt's eine 
korrekte Vorgehensweise? Oder anders: Gibt's eine Doku mit allen 
Funktionen des Assemblers?

In freudiger Erwartung

Christian

von Joerg Wunsch (Gast)


Lesenswert?

Nun, das einfachste ist, Du läßt das den Compiler machen und
schaust Dir den generierten Assemblercode an. ;-)

Ich habe folgendes Stückchen C mal durch den Compiler gejagt
(avr-gcc -S ...):

void foo(void) {
}

void doo(void) {
}

void (*footab[])(void) _attribute_ ((progmem)) = {
        foo, doo
};

Das pm() scheint der Trick zu sein.  Das besagt offenbar,
daß der entsprechende Wert aus dem program memory zu nehmen
ist.

Normalerweise findest Du die Doku des GNU Assemblers im Netz
(oder bei WinAVR auch mit auf der Platte).  Allerdings
scheinen mir die plattformabhängigen Teile für AVR nicht
dokumentiert worden zu sein. :-(  Wenn ich mal viel Zeit
habe, schaue ich mir mal an, ob man da wenigstens eine kurze
Zusammenfassung innerhalb der avr-libc Doku einarbeiten kann.

von Christian Rötzer (Gast)


Lesenswert?

Ja, durch den Assembler jagen ist nicht schlecht...ich hab diese pm() 
Funktion mal direkt im Assembler getestet, die tut einfach nichts :-(. 
Naja, damit ich mal langsam vorwärts komme, rechne ich halt nun doch zur 
Laufzeit um (damit kann man "nur" 64k>Byte< des verwendeten ATmega128 
erreichen, was derzeit aber ein eher theoretisches Problem ist).
Ziel war es ursprünglich, einen bestehenden Quelltext 1:1 von GCC-AS 
übersetzen zu lassen und zwar so, daß sich der gleiche Binärcode ergibt. 
Damit könnte ich feststellen, ob sich Fehler bei der "Portierung" 
eingeschlichen haben. Man glaubt nicht, was das für Probleme aufwirft! 
Erst im nächsten Schritt wollte ich dann Schritt für Schritt C-Code 
einbinden. Naja vielleicht finden wir ja noch den Befehl (mal im 
Quelltext von GCC-AS nachschaun)

von Joerg Wunsch (Gast)


Lesenswert?

Habe gerade mal ins tc-avr.c geschaut:

        case BFD_RELOC_AVR_16_PM:
          bfd_putl16 ((bfd_vma) (value >> 1), where);
          break;

Sieht also so aus, als würde dieser pm() Operator bereits die
Umrechnung von Byte- auf Wortadressen vornehmen.

von Christian Rötzer (Gast)


Lesenswert?

Ich hab mal Dein foo-Beispiel durch den Compiler geschoben: Damit liegt 
die Tabelle aber noch im RAM. Das sieht man deutlicher, wenn man mal 
eine Funktion über die Tabelle aufruft, z.B. footab[0](). Da greift er 
dann mittels lds-Befehl auf die Tabelle zu.
Wenn ich aber stattdessen statt _attribute_ ((progmem)) einfach nur 
PROGMEM schreibe (mit passendem Include), dann greift er mit dem 
lpm-Befehl in die Tabelle. Nur - die Tabelle wird einfach direkt vom 
Compiler korrekt erzeugt. Damit konnte ich also auch keine 
Assembler-Geheimnisse entlocken...es bleibt spannend!

von Joerg Wunsch (Gast)


Lesenswert?

Ob Du __attribute__((progmem)) oder __attribute__((_progmem_))
schreibst (was anderes ist PROGMEM nicht), ist weitgehend egal.
Im generierten Assemblercode siehst Du, daß er das nach section
.progmem.data setzt, das ist genau das, wo es hingehört.

Daß Du auf ein progmem-Array nicht direkt zugreifen kannst
sondern nur mit LPM, liegt in der Verantwortung des Programmierers.
Der Compiler benutzt LPM nie von sich aus!  Wenn das also bei
Dir dann irgendwann doch geklappt hat, hast Du das irgendwo
in einem Macro oder sowas indirekt selbst getan.

Was fehlt Dir denn noch an Assembler-,,Geheimnissen''?  Das pm()
war der eigentliche Trick.

von Christian Rötzer (Gast)


Lesenswert?

Ja, wie gesagt, der pm()-Operator liefert mir als Ergebnis leider nur 
das zurück, was ich als Argument übergeben habe (komisch). Benötigen tue 
ich das Teilen durch zwei.
Moment mal, hast Du .progmem.data gesagt? Das ist quasi eine subsection 
oder wie, da muß ich nochmal forschen!

von Christian Rötzer (Gast)


Lesenswert?

Jetzt frag' mich mal jemand was ich früher gemacht habe: Es interessiert 
mich nicht mehr. Fakt ist: der pm()-Operator tut was er soll. Die 
Software ist jetzt 1:1 auf den neuen Assembler übernommen: Ab jetzt wird 
nur noch C programmiert :-)))))

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.