Hallo, ich versuche verzweifelt meinen AT91SAM7A3 in den Thumb-Mode zu zwingen. Ich benutze den GCC 4.1.1 mit der option -mthumb-interwork. Nun sollte doch beim bx im Startup-Code der Core in den Thumb modus umschalten. Das macht er aber leider nicht. Kann mir jemand sagen, wo mein Problem liegt ? Ich habe mal das Starup-File angefügt.
Hi, > ldr r0,=main Hier das Bit 0 in R0 setzen (unter der Annahme dass Dein main() bereits -mthumb-interwork'ed ist)? > bx r0
So, habe es mal ausprobiert : > ldr r0,=main > add r0, # 1 // switch to Thumb-Mode > bx r0 Wenn ich das mache, hänge ich nach dem Sprung im undefined instruction oder im Data abort Vektor. > unter der Annahme > dass Dein main() bereits -mthumb-interwork'ed ist ich habe den kompletten Quelltext mit -mthumb-interwork zusammen kompiliert. Dann sollte doch auch die Main bereit zum Thumb-Modus sein, richtig ? Was läuft denn hier schief ?
"ich habe den kompletten Quelltext mit -mthumb-interwork zusammen kompiliert. Dann sollte doch auch die Main bereit zum Thumb-Modus sein, richtig ?" Nein, der Schalter thumb-interwork hat eine andere Funktion. Der gezeigte Startup-Code ist in Bezug auf den Aufruf von main so o.k. Die Adresse der Funktion main wird in r0 geladen und dann mittels BX zu dieser Adresse gesprungen - egal ob diese Ziel Thumb- oder ARM-code ist, dies wird automatisch erkannt: das "Thumb-Bit" (LS-Bit) sagt dem Controller, ob das Ziel thumb- oder ARM-code enthält. Ingendwas per ADD#1 zu erzwingen ist falsch, wenn die Zielfunktion ARM-Code ist. Der Controller "schaltet" dann zwar in thumb-mode aber findet ARM-code -> Fehler. Thumb-Code erzeugt man mit gcc aus C-Quellcode, indem man -mthumb als Option angibt. Naeheres dazu im gcc-Manual. Kurzform: -mthumb -> erzeuge thumb-code -mthumb-interwork -> erzeuge ARM-code aus dem thumb-code augerufen werden kann -mthumb -mthumb-interwork -> erzeuge thumb-code aus dem ARM-code augerufen werden kann keine Option -> erzeuge ARM-code Vielleicht sind die makefiles aus meinen Beispielen zur Verdeutlichung nützlich: http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/ Hoffe, es hilft Martin Thomas
Die 1 nicht per ADD sondern per ORR erzwingen. Das stellt zumindest sicher, dass eine schon vorhandene 1 im LSB nicht stört.
Ein Bit, das gesetzt werden soll, einzuodern ist sicher besser als ein ADD. Man ändert damit aber aber in diesem Anwendungsfalls nicht die Art des Zielcodes, sondern nur die Sprungaddrese. Die "Manipulation" der Addresse durch setzten von Bit 0 ist nicht nötig und darüber hinaus hier einfach falsch, wenn am Sprungziel ARM-code ist (man erwingt thumb-mode für Anweisungen, die keine Thumb-Anweisungen sind). Man muss nichts "herumbiegen" - zumindest musste ich das bisher dafür noch nie bei Verwendung der GNU-Toolchain (gcc...). Die Addresse von main() wird schon richtig verwaltet und gibt somit implizit bereits an, ob die Funktion Thumb- oder ARM-Code ist (das LS-Bit "stimmt" bereits) ein Sprung mit BX schaltet automatisch in den passenden Mode. Zur Veranschaulichung (aus meinem "gamma"-Beispiel (link oben), Toolchain: arm-elf-gcc 4.1.1 et. al. aus meiner WinARM-Sammlung): (1) Code von main() kompiliert mit -mthumb und -mthumb-interwork. Startup-Code nur mit -mthumb-interwork. Ausschnitt aus dem Disassembly:
1 | [...] |
2 | ldr r0,=main |
3 | 1000f8: e59f0034 ldr r0, [pc, #52] ; 100134 <.text+0x134> |
4 | bx r0 |
5 | 1000fc: e12fff10 bx r0 |
6 | [...] |
7 | 100134: 001001b5 ldreqh r0, [r0], -r5 |
8 | [...] |
9 | int main(void) |
10 | { |
11 | 1001b4: b5b0 push {r4, r5, r7, lr} |
12 | 1001b6: 4a6c ldr r2, [pc, #432] (100368 <.text+0x368>) |
13 | 1001b8: 4b6c ldr r3, [pc, #432] (10036c <.text+0x36c>) |
14 | [...] |
Man erkennt, dass main() thumb-code ist (16-bit Anweisungen, push...) - wegen -mthumb. ldr, r0,=main läd die Addresse von main() als 001001b5, man sieht, dass Bit 0 darin gesetzt ist, somit schaltet BX den Controller in Thumb-Mode und springt zur Zieladdresse. (2) Nun ein Ausschnitt, wenn alles ohne thumb/thumb-IW kompiliert wird:
1 | ldr r0,=main |
2 | 1000f8: e59f0034 ldr r0, [pc, #52] ; 100134 <.text+0x134> |
3 | bx r0 |
4 | 1000fc: e12fff10 bx r0 |
5 | [...] |
6 | 100134: 001001e0 andeqs r0, r0, r0, ror #3 |
7 | [...] |
8 | int main(void) |
9 | { |
10 | 1001e0: e1a0c00d mov ip, sp |
11 | 1001e4: e92dd830 stmdb sp!, {r4, r5, fp, ip, lr, pc} |
12 | [...] |
Hier identifiziert man den Code von main() als ARM-code (32-bit Anweisungen, stmdb...). Im startup-Code wird die Addresse 001001e0 geladen, Bit 0 ist nicht gesetzt -> ARM-Mode am Sprungziel, Sprung mit BX schaltet in ARM-mode (oder in diesem Fall: keine Aenderung, da schon im ARM-Mode) und springt zu main. Zusammenfassend: den Quellcode einfach mit der passenden Compileroption kompilieren (mit -mthumb oder ohen -mthumb), der Rest erledigt sich von alleine. Hoffe, dies erklärt die "Angelegenheit" halbwegs verständlich. Martin Thomas
Vielen Dank für die Antworten, besonders an Martin Thomas! Ich denke jetzt habe ich die Sache verstanden. Leider fehlt mir nun die Zeit es auszuprobieren. Aber wenn es soweit ist, werde ich Ergebnisse melden. Viele Grüße
Nabend! ich hätte dazu auch noch eine Frage. Das ganze Funktioniert sehr gut mit dem Aufruf von main(). Ich konnte das Disassembler Listing oben bei mir nachvollziehen, tut so weit. Allerdings kommen die folgenden Warnings: "arm-elf-ld: Warning: main.o does not support interworking, whereas main.elf does". Das ist ja auch OK, aber kann ich die irgendwie unterdrücken? Mich macht so etwas immer nervös... crt.s wird mit -mthumb-interwork, der Rest mit -mthumb. Gruß Mathias
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.