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
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ß
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
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