Hi, Eine Frage: Ich verwende den ARM7-TDMI-S und habe einen C-Quellcode dafür. Darin verwende ich inline-Assembler. Wenn ich im inline-Assembler den Befehl "BX" anwende, wird zwar im Debugger zuerst zur richtigen Stelle gesprungen doch sobald ich den Befehl nach BX ausführen will, springt er im Speicher wo ganz anderes hin. Kann mir da jemand Rat geben? liebe Grüße
Bitte mehr Infos: - welcher Compiler - welche CPU (Hersteller, Typ) - Compilereinstellungen (Optimierung,... usw) - Codeauszug - insgesamt mehr Infos zum Kontext - welches JTAG/trace (OpenOCD, Keil, ...)
>Wenn ich im inline-Assembler >den Befehl "BX" anwende, wird zwar im Debugger zuerst zur richtigen >Stelle gesprungen doch sobald ich den Befehl nach BX ausführen will, >springt er im Speicher wo ganz anderes hin. Na dann nimm den Debugger und sieh nach in welches schwarze Loch er gesprungen ist, und wo der Point of no Return ist.
Hallo Johnson, willst Du wirklich das Instruction-Set mit dem Sprung tauschen? Von z.B. ARM-Mode zu Thumb-Mode? Wenn nicht wird der Code danach wahrscheinlich als Thunb-Code gedeutet, was nicht klappt. Versuche statt dessen B oder BL, dann sollte es klappen. Gruß Microman
Das ist wohl die Vorgeschichte: Beitrag "ARM und Thumb mischen" Aus Ludwig ist ein Johnson geworden.
Ja ich verwende die Befehle um zwischen den einzelnen Modis (ARM und Thumb) zu switchen. Ich habe: - die MDK von Keil (microcontroller development kit) - Microvision von Keil - Keil ULINK JTAG Adapter Codeauszug: __asm { start: ; ARM-Modus MOV r0, #-1 ; Ergebnis vom Vergleich MOV r1, #3 MOV r2, #4 CMP r1, r2 ; r1 == r2 ? LDR r0, ungleich ADD r0, r0, #1 BXNE r0 MOV r0, #0 B ende ungleich: ; Thumb-Modus CMP r0, r1 ende: } Gruß
Es reicht nicht, dem Prozessor den Thumb-Mode beizubringen. Der Assembler muss ebenfalls wissen, ob er ARM- oder Thumb-Code zu erzeugen hat.
__asm { ARM start: ; ARM-Modus MOV r0, #-1 ; Ergebnis vom Vergleich MOV r1, #3 MOV r2, #4 CMP r1, r2 ; r1 == r2 ? LDR r0, ungleich ADD r0, r0, #1 BXNE r0 MOV r0, #0 B ende THUMB ungleich: ; Thumb-Modus CMP r0, r1 ende: } Abhängig natürlich wie das dein Assembler sehen möchte
Das geht freilich immer noch in die Hose. Immerhin ist der vom Compiler erzeugte Code bei "ende:" hier gleichermassen für ARM- und Thumb-Mode zuständig.
A. K. schrieb: > Das geht freilich immer noch in die Hose. Immerhin ist der vom Compiler > erzeugte Code bei "ende:" hier gleichermassen für ARM- und Thumb-Mode > zuständig. Ausweg BLX
Das Problem ist, dass man die Befehle "ARM" und "THUMB" in Microvision nicht direkt angeben kann. Es heißt dann "undefined identifier".
geht wenigstens das #PRAGMA ARM / THUMB http://www.keil.com/support/man/docs/armcc/armcc_Cihdeeja.htm
Ja das geht schon. Aber ich will einfach herauskriegen wie ich innerhalb eine Funktion zwischen den Modis "ARM" und "Thumb" switchen kann.
Dennis Heynlein schrieb: > Ausweg BLX Klar muss man wieder zurück in den ARM Modus. Aber mit BLX geht das im hier betrachteten Fall nicht, da es diesen Befehl nicht gibt. Ausserdem muss man dann evtl. LR sichern. In seinem Sinn wäre es wohl passender, auf die gleiche Weise in dem ARM Modus zurück zu wechseln, wie er in den Thumb Modus kam.
Das "CMP r0, r1" im Thumb-Modus löst ein Software Interrupt aus, das erklärt auch wieso dieser Befehl dazu führt, dass ich im Speicher wo ganz anders, nämlich im Interrupt-Vektor des "Software Interrupts" lande. Wieso passiert das?
Hallo Johnson, BX mit displacement gibt es beim ARM7TDMI im ARM-Mode nicht. BX Rn aber schon. BLX ist dem ARM9 oder dem Thumb-Mode überlassen. Aber hier noch etwas Code, Achtung der Code muss immer aligned sein (32 Bit) auch wenn in den Thumb-Mode gesprungen wird. Ich mache das sehr einfach, achte auf das NOP um Aligned zu sein. CODE16 integer_2_float_Thumb: // change to ARM Mode bx pc // und das im laufenden Programm nop CODE32 integer_2_float: CMP R0,#0x0 MOV R1,#0x9D ORRMI R1,R1,#0x100 ..... ..... BX LR // und zurück // change to thumb mode ldr r0,=PGM_Thumb // change to Thumb State bx r0 // Thumb Mode Programm CODE16 PGM_Thumb: // DAC für Batt Current Messung ausgeben EXTERN Setup_Current_DAC_Thumb bl Setup_Current_DAC_Thumb Gruß Sascha
Erstmal danke für die Antwort. Aber mein Hauptproblem ist ja, dass ich "CODE16" oder "CODE32" nicht angeben kann. Dann heißt es "undefined identifier".
geht das ? #pragma arm __asm { start: ; ARM-Modus MOV r0, #-1 ; Ergebnis vom Vergleich MOV r1, #3 MOV r2, #4 CMP r1, r2 ; r1 == r2 ? LDR r0, ungleich ADD r0, r0, #1 BXNE r0 MOV r0, #0 B ende } #pragma thumb __asm { ungleich: ; Thumb-Modus CMP r0, r1 ende: } #pragma arm und vorallem wie wirds am Ende kompiliert und ist ungleich: von dem erstem __asm aus zu erreichen ? Kann Du die Assembler-Geschichte nicht in ein extra Assembler-File auslagern ?
Johnson schrieb: > Das Problem ist, dass man die Befehle "ARM" und "THUMB" in Microvision > nicht direkt angeben kann. Es heißt dann "undefined identifier". Der inline assembler des armcc unterstützt erst in recht aktuellen Versionen Thumb code. Erlaube mir die Frage, wozu das ganze? Generell ist es möglich, aber meist nicht sinnvoll, innerhalb der Funktion umzuschalten.
Hallo, also ich programmiere gerne meine ARM Controller in Assembler, dabei ist natürlich klar, das jeder Befehl mit 32 Bit 4 Bytes im ROM (Programmspeicher) vernichten. Ich schreibe aber nur dann im Thumb Mode, wenn der Controller nicht viel flash hat. Da wird ein Befehl mit 16 Bit also 2 Bytes codiert. Die Relation vom Speicherplatz von ARM-Mode zu Thumb mode ist in der Praxis auch nicht so groß wie auf jeder Promotion Werbetrommel immer steht. Wer die umfangreiche stärke des ARM-Modes nutzen kann kommt fast gleich hin. Nur hat sich doch in letzter Zeit viel geändert, das der Speicher nichts mehr kostet und auch noch sehr groß geworden ist. Das Problem beim ARM ist doch eher seine Store & Load Architektur und die wurde leider auch beim Cortex M3 nicht verbessert. Es gibt da schon bessere CPUs aber klar der Preis macht die Musik. Also als Fazit der ARM-Mode reicht heute voll aus. Beim Cortex M3 hat mich schon der IT Befehl gestört. Gruß Sascha
Sascha schrieb: > [...] Und was war jetzt der zwingende Grund innerhalb einer Funktion umzuschalten? Beim ARM7 kostet das Zyklen und (unnötigen) Entwicklungsaufwand, wie man an diesem Thread feststellen kann. > Beim Cortex M3 hat mich schon der IT Befehl gestört. Warum? -- Marcus
Johnson schrieb: > Kann jemand bitte mal etwas konkreteres vorschlagen? Code wäre nicht > schlecht. Mein Vorschlag: Nimm einen Assembler, wenn Du in Assembler programmieren willst. Den C Compiler zu benutzen um durch die Hintertuer Assembler zu schreiben wird immer nur eine Notloesung sein. Viele wichtige Assembler Direktiven werden nicht unterstuetze werden. ZigZeg
Hallo Johnson, also was du wirklich versuchen solltest ist ein seperates Assembler File zu erstellen und dort die Assembler Routinen anlegst. Das geht auch mit Keil. Du must dich nur um folgende Informationen in der Keil Docu einlesen. 1. Wie gebe ich für den Linker den Programmbereich frei, z.B. Rseg Code 2. Welche Register werden in welcher Reihenfolge mit Variablen aus C beladen 3. Public und Extern muss definiert werden, z.B. Public Meine_C_Routine dann kann die Routine wie eine C-Funktion aufgerufen werden. Eventuell muss die Routine im C noch als extern deklariert werden. 4. in welchem Register wird der Rückgabewert an C gemacht. Also ich arbeite so ohne Probleme, nur jetzt nicht mit Keil, aber der Keil muss das ohne Probleme können. Und hier noch einen kleines Code-Schnipsel wenn es ein externes File wird. In deinem Linker Script File kannst du nachlesen wie die einzelnen Code Bereiche heißen und kannst ein Rseg (Relocatable Segment) erzeugen. Hier ein Beispiel für Keil ist aber 8051 Assembler: NAME CRC8_Routines PUBLIC CRC8 CRC8_segment SEGMENT CODE RSEG CRC8_segment ;******************************** ;****** CRC8 Routine Start ****** ;******************************** CRC8: push dph ; Save DPH push dpl ; Save DPL push acc ; Save Acc mov dptr,#CRC8_DATA ; Point To Table .............. .............. end Hier ein Beispiel für IAR für ARM um ganz einfach mal Globale Interrupts ein/ausschalten über SWI. Es muss also erst durch einen SWI in den Supervisor Modus gewechselt werden, ist hier aber nicht weiter wichtig..... .Programm steht für den Linker, Code für Programm, es gibt ja auch noch Data usw... //******************************** //* * //* Interrupt Handling * //* * //******************************** // // Disable all Interrupts // // Enable all Interupts // // // CPU Mode definition #define Mode_USR 0x10 // Mode definitions #define Mode_FIQ 0x11 #define Mode_IRQ 0x12 #define Mode_SVC 0x13 #define Mode_ABT 0x17 #define Mode_UNDEF 0x1B #define Mode_SYS 0x1F // CPU Bit definition #define I_Bit 0x80 // when I bit is set, IRQ is disabled #define F_Bit 0x40 // when F bit is set, FIQ is disabled NAME Interrupt // Low Level Routines PUBLIC Enable_Interrupt_ARM,Disable_Interrupt_ARM // Programm Section SECTION .Programm : CODE (2) CODE32 //************************************ //* * //* Disable all Interrupts * SWI-Mode required //* User-Mode * privileged Mode //* * //************************************ Disable_Interrupt_ARM: // Programmaufruf nur durch SWI möglich mrs r11,spsr // read User-Mode PSR orr r11,r11,#I_Bit|F_Bit // disable IRQ and FIQ msr spsr_cxsf,r11 // save back modified PSR bx lr //************************************ //* * //* Enable all Interrupts * SWI-Mode required //* User-Mode * privileged Mode //* * //************************************ Enable_Interrupt_ARM: // Programmaufruf nur durch SWI möglich mrs r11,spsr // read User-Mode PSR bic r11,r11,#I_Bit|F_Bit // enable IRQ and FIQ msr spsr_cxsf,r11 // save back modified PSR bx lr END Ich hoffe ich konnte dir etwas helfen, oder Mut machen, das manche Dinge doch einfach etwas mehr einlernarbeit kosten. Gruß Sascha
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.