Branching ARM

Gast #2776428
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
Gast #2776467
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.
Gast #2776474
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
Gast #2776488
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ß
Gast #2777228
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?
Gast #2777511
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
Persönliche Seite #2777693
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 ?
Persönliche Seite #2778092
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.
Gast #2778405
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
#2778447
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
Gast #2779827
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren