Forum: Compiler & IDEs Wie ist PORTB implementiert?


von Thomas H. (thux)


Lesenswert?

Hallo,

Ich frage mich wie z.B. PORTB implementiert ist. Das habe ich bisher 
herausgefunden:

Die Addresse des Ports kann man aus dem Datenblatt entnehmen oder aus 
der avrlibc. Für den ATmega8 steht sie in der Datei iom8.h und lautet 
0x18.
1
#define PORTB  _SFR_IO8(0x18)

Das Makro _SFR_IO8 ist in der Datei sfr_defs.h definiert und addiert je 
nach verwendeten AVR noch einen Offset hinzu, in meinem Fall beträgt der 
Offset 0x20. Danach wird diese Zahl (0x18+0x20) mit Hilfe eines weiteren 
Makros _MMIO_BYTE als ein 8 Bit breiter Pointer mit dem Attribut 
volatile interpretiert. Da es sich hier um ein Hardware Register handelt 
kann der Compilier keine Annahmen für Optimierungen treffen, daher ist 
das volatile notwenig.

Der so erzeuge Pointer wird sofort dereferenziert damit damit eine 
einfach Zuweisung mit = möglich ist.

Man kann sich das alles zur Compilezeit mit folgenden Code anzeigen 
lassen:
1
#define STR(x) #x
2
#define XSTR(x) STR(x)
3
#pragma message "PORTB " XSTR(PORTB)
1
note: '#pragma message: PORTB (*(volatile uint8_t *)((0x18) + 0x20))'

Nun will ich mir den erzeugten Assembler Code für diese Zeile Code 
genauer ansehen: PORTB |= 0xf0;
Es werden 3 Instructionen erzeugt:
1
in r24,0x18
2
ori r24,lo8(-16)
3
out 0x18,r24

Als erstes wird ein Wert von PORTB geladen, dann die OR Verknüpfung mit 
der Konstante 0xf0 durchgeführt (die hier als signed Zahl angezeigt 
wird, daher die -16) und zum Schluss wird das Ergebniss wieder nach 
PORTB gespeicher. Es wird das Register r24 benutzt um den Wert zwischen 
zu speichern und gelesen und geschrieben wird von Addresse 0x18.

Warum wird hier im Assembler Code Addresse 0x18 benutzt und nicht 0x38? 
Also 0x18+0x20. Im C Code steht eindeutig 0x18+0x20. Also muss der 
Compiler hier doch zusätzliches Wissen einprogrammiert haben um den 
Offset für bestimme (oder alle?) Hardware Register wieder abzuziehen.

Weis hier jemand dazu etwas?


Sobald ich wieder etwas Zeit habe, werde ich von den anderen Sachen 
berichten die ich herausgefunden habe.

Grüße

von Oliver S. (oliverso)


Lesenswert?

Thomas H. schrieb:
> Weis hier jemand dazu etwas?

Das Datenblatt deines unbekannten Prozessors.
Wobei es sich wohl um einen classic AVR handeln dürfte. Zu dem wurde im 
Netz und auch hier im Forum eigentlich schon alles geschrieben, was es 
zuschreiben gibt, und das sogar von jedem…

Mal ein Beispiel:

Beitrag "Adressen verstehen im Datenblatt"

Oliver

von Nemopuk (nemopuk)


Lesenswert?

Thomas H. schrieb:
> Warum wird hier im Assembler Code Addresse 0x18 benutzt und nicht 0x38?

a) in, out, cbi, sbi, sbic und sbis greifen auf I/O Register 
anhand ihrer Registernummer zu.

b) Zusätzlich kann man auch über die Adresse/Zeiger 0x38 auf das 
Register zugreifen, aber mit anderen Befehlen (die gleichen, die auch 
auf RAM zugreifen).

Der Compiler entscheidet automatisch, welche Variante für die jeweilige 
Stelle im Quelltext die günstigere ist.

> Also muss der Compiler hier doch zusätzliches Wissen einprogrammiert
> haben um den Offset für bestimme (oder alle?) Hardware Register wieder
> abzuziehen.

Hat er. Und der Optimizer mischt da auch noch mit.

: Bearbeitet durch User
von Michael B. (laberkopp)


Lesenswert?

Oliver S. schrieb:
> Das Datenblatt deines unbekannten Prozessors.

Thomas H. schrieb:
> Für den ATmega8

OUT – Store Register to I/O Location
5.84.1 Description
Stores data from register Rr in the Register File to I/O space.
Operation:
(i) I/O(A) ← Rr
Syntax: Operands: Program Counter:
(i) OUT A,Rr 0 ≤ r ≤ 31, 0 ≤ A ≤ 63 PC ← PC + 1
16-bit Opcode:
1011 1AAr rrrr AAAA
5.84.2 Status Register (SREG) and Boolean Formula
I T H S V N Z C
– – – – – – – –
Example:
 clr r16 ; Clear r16
 ser r17 ; Set r17
 out 0x18,r16 ; Write zeros to Port B
 nop ; Wait (do nothing)
 out 0x18,r17 ; Write ones to Port B

ST – Store Indirect From Register to Data Space using Index X
5.114.1 Description
Stores one byte indirect from a register to data space. The data space 
usually consists of the Register File, I/O
memory, and SRAM, refer to the device data sheet for a detailed 
definition of the data space.

The I/O memory space contains 64 addresses for CPU peripheral functions 
as Control Regis-
ters, SPI, and other I/O functions. The I/O Memory can be accessed 
directly, or as the Data
Space locations following those of the Register File, 0x20 - 0x5F.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Thomas H. schrieb:

> Wie ist PORTB implementiert?

In den Headern stehen immer die RAM-Adressen, nicht die I/O-Adressen.

> Warum wird hier im Assembler Code Addresse 0x18 benutzt und nicht 0x38?

Optimierung.

0x38 ist die RAM-Adresse des SFRs, also die Adresse beim Zugriff per 
LDS, STS, LD, LDD oder ST oder STD.

0x18 ist die I/O Adresse, also die Adresse die IN, OUT, SBI, CBI, SBIC, 
SBIS verwenden.  Falls also die Adresse zur Linktime bekannt ist UND im 
Adressbereich einer I/O Instruktion liegt, kann eine I/O Instruktion 
verwendet werden.

Der I/O Offset ist abhängig vom Core: 0x0 für ATxmega und 0x20 für 
andere AVRs.

IN ist besser als z.B. LDS weil kleinerer Code (hängt vom Core ab) und 
schneller (hängt auch vom Core ab).  Pferdefuß der I/O Instruktionen 
ist, dass sie nur einen kleinen Speicherbereich abdecken: I/O-Adressen 
0x0..0x3f (IN und OUT) bzw. I/O-Adressen 0x0..0x1f (andere I/O 
Instruktionen), wohingegen "normale" Schreib-Lases Operationen einen 
16-Bit Adressbereuch haben (Ausnahmen: AVRrc und Operationen wie ELPM. 
Außerdem Instruktionen wie RAMPx verwenden, was aber GCC nicht nutzt).

> als ein 8 Bit breiter Pointer

Nitpick: Der Zeiger ist 16 Bits breit.  Das Ziel ist ein 8-Bit Wert.

: Bearbeitet durch User
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.