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
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.
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] |
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?
@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
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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.