Forum: Compiler & IDEs arm-none-eabi-gcc: Verwendung von "immediate offset" erzwingen


von Uwe Bonnes (Gast)


Lesenswert?

Hallo,

z.B. bei Cortex3 gibt es den Bit Banding Zugriff. Wenn man Programme 
fuer den Zugriff auf Peripherie schreibt, kommen haeufig Sequenzen wie
Setze Bit 1 in Register 1 der Peripherieregisterstruktur,
Loesche Bit 2 in Register 2,
Setze Bit 3 in Register 3.
Hat man die Basisadresse der BitBand Region der Registerstruktur (BBR) 
ausgerechnet, ware dann eine Pseudeassemblersequenz
MOV RY, 1
MOVE RZ, 1
MOV RX, LowWord(BBR)
MOVT RX, HighWord(BBR)
STR RY, [RX, (1<<5 + 1<<2)]
STR RZ [RX, (2<<5 + 2<<2)]
STR RY, [RX, (3<<5 + 3<<2)]

Bisher habe ich gcc aber nur bei Zugriffen wie RCC->CFG dazu gebracht, 
Zugriffe mit "immediate offset" zu generieren. Egal, wie ich den Zugriff 
formuliere, der Zugriff erfolgt ohne Offset uns sieht wie folgt aus
MOV RY, 1
MOVE RZ, 1
MOV RX, LowWord(BBR + 1<<5 + 1<<2]
MOVT RX, HighWord(BBR + 1<<5 + 1<<2]
STR RY, [RX, 0]
MOV RX, LowWord(BBR + 2<<5 + 2<<2]
MOVT RX, HighWord(BBR + 2<<5 + 2<<2]
STR RY, [RX, 0]
MOV RX, LowWord(BBR + 3<<5 + 3<<2]
MOVT RX, HighWord(BBR + 3<<5 + 3<<2]
STR RY, [RX, 0]

GCC ist gcc version 4.6.0 (GCC).

Ist das ein Manko von GCC oder hat jemand andere Hinweise

von Jim M. (turboj)


Lesenswert?

Blöde Frage, aber welche Optimierungsstufe (-O) verwendest Du? Bei mir 
(CS 4.5.2) sieht "-Os" ganz anders aus als "-O2".

Außerdem müsste man auch Deinen C Code sehen.

von (prx) A. K. (prx)


Lesenswert?

Ich mache das so:
1
// Convert regular base address of a peripheral to bitbanded base address.
2
// perPtr: base address of peripheral, typed as pointer to peripheral_TypeDef 
3
#define BBaseOfPeriph(perPtr)    ((__typeof__(*(perPtr))*) (PERIPH_BB_BASE + (((unsigned)(perPtr) - PERIPH_BASE) << 5)))
4
5
// Access bitbanded peripheral register by bitbanded base address and register offset.
6
// perBB: bitbanded base address of peripheral, typed as pointer to peripheral_TypeDef 
7
// member: member name of peripheral_TypeDef
8
#define BBOffset(perBB, member)    (__builtin_offsetof(__typeof__(*(perBB)), member) << 5)
9
#define BBasedBit(perBB, member, bit)  (*(__typeof__((perBB)->member)*) (((unsigned)(perBB) + BBOffset(perBB, member) + ((bit) << 2))))
10
#define BBasedMask(perBB, member, mask)  BBasedBit(perBB, member, BBitOfMask(mask))
11
12
#define BBitOfMask(mask) (31 - __builtin_clz(mask))
mit Anwendung
1
#define PERIPH_BASE  0x40000000
2
#define PERIPH_BB_BASE  0x42000000
3
4
struct S {
5
  unsigned reg0;
6
  unsigned reg1;
7
  unsigned reg2;
8
};
9
10
#define IO ((volatile struct S *)0x40000000)
11
12
void f(void)
13
{
14
  volatile struct S *p = BBaseOfPeriph(IO);
15
  BBasedBit(p,reg1,4) = 1;
16
  BBasedBit(p,reg2,31) = 1;
17
}
ergibt als erzeugten Code (-O2, -Os):
1
        mov     r3, #1107296256
2
        mov     r2, #1
3
        str     r2, [r3, #144]
4
        str     r2, [r3, #380]

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

A. K. schrieb:
> Ich mache das so:

Ich glaube, das wäre durchaus mal einen Wiki-Artikel hier im
mikrocontroller.net-Wiki wert.  ARM ist dort nach wie vor eher
unterbelichtet, finde ich.

Würdest du das selbst machen wollen?

von (prx) A. K. (prx)


Lesenswert?

Kann ich mal machen.

von Uwe Bonnes (Gast)


Lesenswert?

@A. K.
Typeof() und __builtin_clz sind kein Ansi-Standard. Und
BBasedBit(p,reg1,4) = 1;
ist auch nicht mehr besonders gut lesbar. Und fuer z.B. TIM_TypeDef wird 
die struct S{} definition auch recht lang.
Ich verwende bisher
#define CM3BBREG(base, regstruct, reg, bit) *(volatile uint32_t *) 
&(((uint8_t *) ((base & 0xF0000000) + 0x02000000 + ((base & 
0xFFFFF)<<5))) [(offsetof(regstruct, reg) <<5) + (bit <<2)] )
Das kommt ohne die nicht Ansi Konstrukte aus, gibt allerdings Zugriffe 
ohne "immediate offset"

@Jim

Ich hatte es mit -O0 und -O2 probiert. -Os erkennt zumindestens 
aufeinanderfolgende Zugriffe auf Bits eines Registers, aber auch nicht 
immer

von (prx) A. K. (prx)


Lesenswert?

Uwe Bonnes schrieb:

> Typeof() und __builtin_clz sind kein Ansi-Standard. Und

__builtin_clz lässt sich durch
   ((x) & 0x80000000 ? 31 :
    (x) & 0x40000000 ? 30 :
    ...
ersetzen. Steht bei mit als Alternative auch drin, ich hatte es hier 
aber der Übersichtlichkeit halber weggelassen.

Ohne eine solche Umsetzung von Masken in Bits sind diese Definitionen 
ziemlich sinnlos, jedenfalls beim STM32, da die Bits in den 
Include-Files leider ziemlich konsequent als Maske statt als Bitnummer 
angegeben sind. Und solche Bits als Zahl statt als Bitname in den 
Quelltext zu schreiben widerstrebt mir.

> BBasedBit(p,reg1,4) = 1;
> ist auch nicht mehr besonders gut lesbar.
> Ich verwende bisher
> #define CM3BBREG(base, regstruct, reg, bit)

Inwiefern deine Variante lesbarer ist erschliesst sich mit nicht.

Wobei bei deiner Variante problematisch sein könnte, dass du stets auf 
32-Bit Worte zugreifst. Ich hatte meine Variante mit voller Absicht so 
konstruiert, dass der Datentyp erhalten bleibt, d.h. auf ein als 16-Bit 
Typ deklariertes Register wird auch mit einem 16-Bit Lade/Speicherbefehl 
zugegriffen. Das könnte bei irgendwelchen Peripheriemodulen von 
Bedeutung sein. Nur kommt man dann nicht ohne typeof aus.

> Und fuer z.B. TIM_TypeDef wird
> die struct S{} definition auch recht lang.

Das war nur ein ad hoc hingeschriebenes Beispiel für eine bereits 
vorhandene Struct, wie sie üblicherweise von den Herstellern oder bei 
den IDEs mitgeliefert werden. Da muss nichts selbst geschrieben werden.

von (prx) A. K. (prx)


Lesenswert?

Ein weiteres Problem deiner Version entsteht möglicherweise bei 
generischen Device Drivern. Also bei Softwaremodulen, die sich ohne 
Änderung nur durch einen Parameter auf verschiedene Instanzen der 
Periphierie eignet, wie die diversen USARTs. Du musst dann darauf 
vertrauen, dass die immer und immer wieder hingeschriebene Umrechnung 
der nicht konstanten Basisadresse von der CSE Optimierung des Compilers 
erfasst wird.

Ich hatte hier auch nur die Version hingeschrieben, die sich für solch 
ggf. variable Basiszeiger eignet. In einfachen Fällen in denen zwischen 
Basis und Offset nicht unterschieden werden muss sieht es bei mir auch 
etwas anders aus.

von (prx) A. K. (prx)


Lesenswert?

Jörg Wunsch schrieb:

> Ich glaube, das wäre durchaus mal einen Wiki-Artikel hier im
> mikrocontroller.net-Wiki wert.  ARM ist dort nach wie vor eher
> unterbelichtet, finde ich.
>
> Würdest du das selbst machen wollen?

ARM Bitbanding

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.