Forum: Mikrocontroller und Digitale Elektronik Branching ARM


von Johnson (Gast)


Lesenswert?

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

von René B. (reneb)


Lesenswert?

Bitte mehr Infos:
- welcher Compiler
- welche CPU (Hersteller, Typ)
- Compilereinstellungen (Optimierung,... usw)
- Codeauszug
- insgesamt mehr Infos zum Kontext
- welches JTAG/trace (OpenOCD, Keil, ...)

von holger (Gast)


Lesenswert?

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

von Microman (Gast)


Lesenswert?

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

von holger (Gast)


Lesenswert?

Das ist wohl die Vorgeschichte:

Beitrag "ARM und Thumb mischen"

Aus Ludwig ist ein Johnson geworden.

von Johnson (Gast)


Lesenswert?

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ß

von (prx) A. K. (prx)


Lesenswert?

Es reicht nicht, dem Prozessor den Thumb-Mode beizubringen. Der 
Assembler muss ebenfalls wissen, ob er ARM- oder Thumb-Code zu erzeugen 
hat.

von Johnson (Gast)


Lesenswert?

Wie soll ich das anstellen? Kannst du bitte den Code angeben?

von (prx) A. K. (prx)


Lesenswert?

Kann ich nicht, da ich zwar ARM kenne, aber nicht Keil.

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

__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

von (prx) A. K. (prx)


Lesenswert?

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.

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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

von Johnson (Gast)


Lesenswert?

Das Problem ist, dass man die Befehle "ARM" und "THUMB" in Microvision 
nicht direkt angeben kann. Es heißt dann "undefined identifier".

von Dennis H. (c-logic) Benutzerseite


Lesenswert?


von Johnson (Gast)


Lesenswert?

Ja das geht schon. Aber ich will einfach herauskriegen wie ich innerhalb 
eine Funktion zwischen den Modis "ARM" und "Thumb" switchen kann.

von (prx) A. K. (prx)


Lesenswert?

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.

von Johnson (Gast)


Lesenswert?

Kann jemand bitte mal etwas konkreteres vorschlagen? Code wäre nicht 
schlecht.

von Johnson (Gast)


Lesenswert?

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?

von Johnson (Gast)


Lesenswert?

Danach ist die CPU im "undefined Modus"

von Sascha (Gast)


Lesenswert?

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

von Johnson (Gast)


Lesenswert?

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".

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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 ?

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

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.

von Sascha (Gast)


Lesenswert?

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

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

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

von Kai S. (zigzeg)


Lesenswert?

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

von Johnson (Gast)


Lesenswert?

Danke für die vielen Antworten!

von Sascha (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.