Forum: Compiler & IDEs variable/zeiger in GPIOR0 fest registrieren


von Daniel R. (zerrome)


Lesenswert?

hallo,

ich würde gerne eine variable oder einen zeiger fest in dem
register GPIOR0 registrieren. hab aber keine ahnung wie das
gehen soll.
hab schon mehrere sachen ausprobiert, klappt aber nicht.

das geht nicht:
1
asm(".DEF meins = GPIOR0");
2
register unsigned char *bytesOfSec asm("meins");

das auch nicht:
1
register unsigned char *bytesOfSec asm("GPIOR0");


muss dazu sagen, ich hab keine ahnung von asm.

von Johannes M. (johnny-m)


Lesenswert?

GPIOR0 ist ein I/O-Register und kein Rechenregister! Deshalb ist der 
Speicherklassenqualifizierer register sowieso fehl am Platze, weil er 
sich auf den Rechenregistersatz bezieht. I/O-Register sind (im Prinzip 
zumindest, abgesehen von speziellen Maschinenbefehlen zum Zugriff auf 
einen Teil von ihnen) relativ normale SRAM-Zellen und werden auch wie 
solche angesprochen. GPIOR0 ist also nix anderes als z.B. PORTA oder 
TCCR1A...

von Daniel R. (zerrome)


Lesenswert?

hm,

dann bringt mir das nix...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

So geht's mit avr-gcc und avr-ld

Du legst die Variable in eine Section und lokatierst wo es eben hin 
soll.

Hier ein Beispiel für ATmega8 und TCNT1 (0x004c)
1
unsigned char *x __attribute__ ((section ("bar")));
2
3
void foo (void)
4
{
5
    *x = 0x42;
6
}

Gelinkt wird mit --section-start bar=0x8004c

Der obige Code wird dann
1
<foo>:
2
     198:  e0 91 4c 00   lds  r30, 0x004C
3
     19c:  f0 91 4d 00   lds  r31, 0x004D
4
     1a0:  82 e4         ldi  r24, 0x42
5
     1a2:  80 83         st  Z, r24
6
     1a4:  08 95         ret

hack as hack can

Das ganze geht auch via Linkersymbol:

 --defsym bazz=0x8004c als ld-Option
1
extern unsigned char *bazz;
2
3
void foo (void)
4
{
5
    *bazz = 0x42;
6
}

Der Code wird wie oben.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

...last not least gibt's noch die Version
1
#define P (*((unsigned char**) (&TCNT1)))
2
3
void foo (void)
4
{
5
    *P = 0x42;
6
}

Die allerdings Neuübersetzung braucht, wenn sich die Adresse des SFR 
ändert (oben muss nur neu gelinkt werden).

der Code ist:
1
<foo>:
2
     198:  ec b5         in  r30, 0x2c  ; 44
3
     19a:  fd b5         in  r31, 0x2d  ; 45
4
     19c:  82 e4         ldi  r24, 0x42  ; 66
5
     19e:  80 83         st  Z, r24
6
     1a0:  08 95         ret

von Daniel R. (zerrome)


Lesenswert?

jau,

das sieht sehr gut aus, danke !

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ich vermute mal Du brauchst das für

Beitrag "Unbenutztes Register im 8-Bit Atmel?"

Falls es kein 16-Bit-Register gibt, sondern nur 2 zerstreute 
8-Bit-Register, geht das auch (in allen 3 Varianten). Wird nur noch 
etwas mehr Hack, aber der Code ist im Endeffekt der gleiche von Laufzeit 
und Platzbedarf her.

von Daniel R. (zerrome)


Lesenswert?

ja,
den beitrag hatte ich auch schon gelesen.
was ich noch nicht ganz verstehe ist, das GPIOR0 register liegt im 
bereich der "working register" wo man schnell drauf zugreifen kann, wenn 
ich aber den code so wie oben beschrieben nutze, benutzt der compiler 
den pointer wie einen pointer auf sram...

das sind hier wären nur 6 clocks, aber ein ganzes register weg...
1
register unsigned char p asm("r3");  
2
3
void foo4 (void){
4
     cb6:  a2 e4         ldi  r26, 0x42  ; 66
5
     cb8:  3a 2e         mov  r3, r26
6
     cba:  08 95         ret

der code bringt 9 clocks:
1
#define P (*((unsigned char**) (&TCNT1)))
2
3
void foo (void)
4
{
5
    *P = 0x42;
6
}

die anderen oben beschriebenen varianten beide 11 clocks.

es gibt da eine variable die long int ist bei mir und teils 6*10^6 oder 
noch öfter geschrieben wird, da ist der geschwindigkeitszuwachs mit 
einer registrierung in einem register enorm. z.b. von 31 sec auf 26 
sec...


ps: bei der linker option fehlte eine 0 glaub ich, bei mir läuft das nur 
so: -Wl,--section-start=bar=0x80002B,--defsym=bazz=0x80001E
(atmega168 bar=GPIOR2 bazz=GPIOR0)

grüße daniel

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Daniel Platte wrote:
> ja,
> den beitrag hatte ich auch schon gelesen.
> was ich noch nicht ganz verstehe ist, das GPIOR0 register liegt im
> bereich der "working register" wo man schnell drauf zugreifen kann, wenn
> ich aber den code so wie oben beschrieben nutze, benutzt der compiler
> den pointer wie einen pointer auf sram...

Klaro, so ist's ja auch auf C-Ebene formuliert und für I/O-Regs bzw IN, 
OUT, SBI, CBI, SBIC, SBIS gibt's AFAIK keine Relocs. Wüsst auch garnet 
wie man das GCC ohne neue Qualifier beibringen sollte (übliches Problem 
bei Harvard-Architektur).

Der Compiler kann nur dann Instruktionen wie IN etc. verwenden, wenn er 
die Adresse kennt. Ok? Bei den ersten 2 Beispielen ist die zur 
Compilezeit nicht bekannt, erst zur Link-Zeit. Dividier für Dich nochmal 
die Schritte auseinander, wie man zu nem hex-File kommt, was da jeweils 
gemacht wird und welche Infos man jeweils hat bzw. nicht hat.

1) Präprozess c->i
2) Compile i->s
3) Assemble i->o
4) Link o->elf
5) Hexify elf->hex

> das sind hier wären nur 6 clocks, aber ein ganzes register weg...
>
>
1
> register unsigned char p asm("r3");
2
> 
3
> void foo4 (void){
4
>      cb6:  a2 e4         ldi  r26, 0x42  ; 66
5
>      cb8:  3a 2e         mov  r3, r26
6
>      cba:  08 95         ret
7
>
>
> der code bringt 9 clocks:
>
>
1
> #define P (*((unsigned char**) (&TCNT1)))
2
> 
3
> void foo (void)
4
> {
5
>     *P = 0x42;
6
> }
7
>
>
> die anderen oben beschriebenen varianten beide 11 clocks.
>
> es gibt da eine variable die long int ist bei mir und teils 6*10^6 oder
> noch öfter geschrieben wird, da ist der geschwindigkeitszuwachs mit
> einer registrierung in einem register enorm. z.b. von 31 sec auf 26
> sec...
>

Ich vermute mal Du verwendest avr-gcc und avr-binutils.

Falls Du keine (lib-)Funktionen verwendest, die R2-R5 verwenden, kannst 
Du die zum Speichern nehmen als globales Register. Da gcc die eh kaum 
verwendet, ist's nicht dramatisch.

In einigen lib-Funktionen werden diese Regs jedoch verwendet.

0) Überleg Dir GENAU, was es bedeutet, ein GPR zu einem globalen 
Register zu machen!
1) Du übersetzt Dein Projekt mit -ffixed-2 -ffixed-3 -ffixed-4 -ffixed-5
2) Wenn im hex-Dump eins von r2-r5 verwendet wird, geht's so nicht. Evtl 
kommt die Verwendung von call-prologues, das ist wiederum ok.

3) Die Variable p kommt in ein globales Register
1
   register unsigned long p asm ("r2");

> ps: bei der linker option fehlte eine 0 glaub ich, bei mir läuft das nur
> so: -Wl,--section-start=bar=0x80002B,--defsym=bazz=0x80001E
> (atmega168 bar=GPIOR2 bazz=GPIOR0)

Jo, die VMAs sieht man im map-File und im elf-Dump

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.