www.mikrocontroller.net

Forum: Compiler & IDEs wortbreite void*


Autor: kosmonaut pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,
kann mir jemand auf anhieb die wortbreite eines
void*
in avr-gcc nennen?

ich vermute 16 bit. zumindest da beschwert sich der kompiler nicht. vll 
ist das auch der grund, warum die guten pgmspace-routinen nur bis 64k 
definiert sind (u.a. ja, ich hab mir ein paar beispiele daraus 
angeschaut)

vielen dank,
schönen abend,
bye kosmo

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mal sizeof (void *) ausgeben lassen?

Ansonsten: Deine Annahme ist korrekt, in avr-gcc ist ein Pointer 16 Bit 
breit.

Autor: kosmonaut pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ach ja, gute idee :)
das ist ja dumm, sehr ärgerlich für 128k flash.
danke vielmals

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kosmonaut pirx wrote:

> [...] vll

Viel lieber?
Viel länger?

Wir sind doch hier nicht beim Morsecode.

> ist das auch der grund, warum die guten pgmspace-routinen nur bis 64k
> definiert sind

Naja, der Grund ist eher, dass ein uint8_t * auch 16 bits breit ist. ;-)
Ja, um auf mehr als 64 KiB ROM im Datenmodus zuzugreifen, muss man
zusätzlich zum normalen Zeiger noch RAMPZ behandeln, das machen all
die _P-Routinen nicht.  Dafür ist der Linkerscript so gebaut, dass er
ROM-Daten direkt nach der Initialisierung, aber vor dem restlichen
Code ablegt, damit sie möglichst unterhalb der 64-KiB-Grenze liegen.

Für Programmzugriffe wird der ROM 16-bit-weise adressiert, daher ist
dort die ,,magische Grenze'' erst bei 128 KiB -- was der Grund war,
warum der Patch für die ATmega256x so lange gebraucht hat, bis jemand
eine Idee hatte und jemand anders sie auch umgesetzt hat.

Autor: kosmonaut_pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
moin moin,

>> [...] vll

>Viel lieber?
>Viel länger?

>Wir sind doch hier nicht beim Morsecode.

chat-sprache, entschuldigung.
vll == vielleicht (man schreibt es einfach zu häufig)

>Dafür ist der Linkerscript so gebaut, dass er
>ROM-Daten direkt nach der Initialisierung, aber vor dem restlichen
>Code ablegt, damit sie möglichst unterhalb der 64-KiB-Grenze liegen.

"möglichst" finde ich eine nette ausdrucksweise :)

>Für Programmzugriffe wird der ROM 16-bit-weise adressiert, daher ist
>dort die ,,magische Grenze'' erst bei 128 KiB -- was der Grund war,
>warum der Patch für die ATmega256x so lange gebraucht hat, bis jemand
>eine Idee hatte und jemand anders sie auch umgesetzt hat

kapier ich nicht .. 16Bit-weise?
ich vermute, du meinst die verwendung des RAMPZ und die 16 Bit 
adressierung, ansonsten habe ich keine idee, wieso die grenze bei 128k 
liegen soll.
vom ATmega256x habe ich bisher nur gehört, keinen plan davon.

aber noch einmal zu meinem problemchen: mein ziel war/ist es, meiner 
anwendung eine routine zum schreiben in das flash anzubieten. etwa so:
const void * PROGMEM
memcpy_p(const void * PROGMEM dest, void * src, size_t len, MEM mem)
das letzte argument ist dazu da, um die quelle der daten zu kennzeichnen 
(flash oder sram).
ich gehe derzeit davon aus, dass das durch die 16bit- void-pointer mit 
>64k nicht funktioniert. ist diese annahme korrekt?


danke,
bye kosmo



Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> kapier ich nicht .. 16Bit-weise?

1 Befehlswort = 1 Adresse. Nächstes Befehlswort = Adresse+1. Da ein 
Befehlswort 2 Bytes gross ist, sind mit einem 16 Bit breiten Program 
Counter 64KWorte = 128KByte realisierbar.

Und da GCC verschiedene Pointer nicht verschieden implementieren kann, 
gibt's bei >128KB Flash gewisse Probleme.

Für Datenzugriff auf Flash besteht das Problem seit langem, dank 
Mega128. Und deshalb existieren entsprechende Lib-Funktionen, die mehr 
als 64KB adressieren können. Nur kann man da nicht "void *" verwenden, 
sonden sollte den dort vereinbarten Datentyp nutzen.

Autor: kosmonaut_pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,

>Und deshalb existieren entsprechende Lib-Funktionen, die mehr
>als 64KB adressieren können.
>Nur kann man da nicht "void *" verwenden,
>sonden sollte den dort vereinbarten Datentyp nutzen

ich dachte, ich kenne mich in der avr-libc etwas aus. anscheinend doch 
nicht. welcher ist der datentyp, von dem du sprichst?

Danke,
bye kosmo

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In avr/pgmspace.h gibt es ein paar pgm_read_xxx_far Funktionen, denen 
die Adresse als uint32_t übergeben wird. Damit lassen sich Adressen 
jenseits der ersten 64KB ansprechen.

Autor: kosmonaut_pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hm, also als datentyp würde ich das ja nicht gerade bezeichnen.

die pgm-far-dinger sind imho "bloss" assembler-macros, die explizit das 
RAMPZ setzen. übergeben werden zwar 32 bit, da gebe ich dir recht. 
verwendet werden davon aber immer nur 16, was auch sonst. es obliegt dem 
programmierer, seine 32-bit-adresse zu beurteilen und das entsprechende 
far- oder near-macro aufzurufen.
ergo müsste ich mir für ein allgemeingültiges vorgehen zu einem void* 
(oder uint8_t* oder oder :) noch merken, in welcher "bank" die adresse 
liegt. oje.




Autor: kosmonaut_pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sorry, korrektur,
RAMPZ wird aus dem 32 Bit genommen (aus dem .. dritten byte(C)).
ok.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum gibt's eigentlich nicht so ähnlich wie früher mal im DOS 
Zeigerarten "near" und "far"? Es gibt meines Wissens gcc-Targets, die 
sowas unterstützen.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Es gibt meines Wissens gcc-Targets, die sowas unterstützen.

Details?

Bislang hiess es immer, dass GCC nicht in der Lage ist, für verschiedene 
Pointer verschiedene Maschinendarstellungen zu verwenden. Das aber ist 
eine Grundvoraussetzung.

Autor: kosmonaut pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,
ich will diesen thread nicht endlos gestalten, aber ihc muss noch einmal 
nerven:

>1 Befehlswort = 1 Adresse. Nächstes Befehlswort = Adresse+1. Da ein
>Befehlswort 2 Bytes gross ist, sind mit einem 16 Bit breiten Program
>Counter 64KWorte = 128KByte realisierbar.

ums kurz zu machen: der PC adressiert wörter?

danke,
bye kosmo

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kosmonaut pirx wrote:
> ums kurz zu machen: der PC adressiert wörter?
Ja.

EDIT (jetzt wirds doch länger):
Macht ja auch Sinn. Schließlich sind alle AVR-Instruktionen 16 oder 
(seltener) 32 Bit breit. Deshalb wäre ein Byte-Zugriff ziemlich sinnlos. 
Beim Zugriff auf Daten sieht das natürlich anders aus, weshalb der 
(e)lpm-Befehl ja auch ein bisschen "tricksen" muss, um an einzelne Bytes 
heranzukommen.

Autor: kosmonaut pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,
das mit der breite der befehle ist mir inzwischen auch im manual übern 
weg gelaufen.
es ist nur irritierend, dass der zugriff auf daten byteweise erfolgt. 
nun gut, so langsam habe ich's geschnallt.

euch vielen dank,
bye kosmo

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du wirklich irritiert werden willst, dann programmier mal 
abwechselnd mit Atmels Assembler und mit dem GNU-Assembler. Atmel zählt 
nämlich im Code konsequenterweise Worte, GAS aber trotzdem Bytes.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Andreas Kaiser:

Ich dachte wirklich, daß es sowas gibt, aber finde nichts. Vielleicht 
habe ich mich da getäuscht. Immerhin gibt es aber so Sachen wie:

5.32.1 M32R/D Variable Attributes
One attribute is currently defined for the M32R/D.
model (model-name)
Use this attribute on the M32R/D to set the addressability of an object. 
The identifier model-name is one of small, medium, or large, 
representing each of the code models.
Small model objects live in the lower 16MB of memory (so that their 
addresses can be loaded with the ld24 instruction).
Medium and large model objects may live anywhere in the 32-bit address 
space (the compiler will generate seth/add3 instructions to load their 
addresses).


Das bringt einem aber natürlich nichts, wenn man über Zeiger darauf 
zugerifen will. Hier könnte aber C++ mal wieder seine Vorteile voll 
ausspielen. Man könnte damit ein Zeiger-Klassentemplate schreiben, das 
sich fast genau so verhält wie ein normaler Zeiger, aber sich 
automatisch um RAMPZ kümmert. Ich hab auch schon solche Spezialzeiger 
für RAM- und EEPROM-Zugriff geschrieben. Leider gibt es da ein Problem, 
nämlich den Operator->, der leider nicht so problemlos geht.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Global kannst du alle Pointer einstellen wie du willst, d.h. per 
Compiler-Option von 16bit Pointern auf 32bit Pointer umstellen. Das 
betrifft dann aber alle Pointer. Was nicht geht: einzelne Pointer 
entsprechend kennzeichnen. Das ist die alte wohlbekannte Krux an GCC und 
grösstes Hindernis bei der Portierung auf etliche 
Controller-Architekturen.

Mit C++ bist zu wohl auf dem richtigen Weg, damit lassen sich jene 
generischen Pointer realisieren, wie sie von anderen Compilern für AVR 
oder 8051 implementiert werden. Als Kombination von Adresse und 
Addressraum. Billig ist das allerdings nicht und bei den 
Library-Funktionen wie strxxx und printf hilft das auch nicht weiter, es 
sei denn du implementierst auch diese neu.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Kaiser wrote:

> Wenn du wirklich irritiert werden willst, dann programmier mal
> abwechselnd mit Atmels Assembler und mit dem GNU-Assembler. Atmel zählt
> nämlich im Code konsequenterweise Worte, GAS aber trotzdem Bytes.

Atmel's Assembler ist da einfach in der eigenen Suppe gewachsen.
Macht niemand sonst, obwohl RISC-CPUs schon seit vielen Jahren
nur Vielfache ihrer Wortgröße adressieren können (und die ist dann
größer als 16 Bits).  Wenn du als Programmierer jedesmal zwischen
Bytes und der jeweiligen Maschinenwortgröße umrechnen darfst,
bekommste doch auf Dauer eine Macke.  Bekommste ja auch beim AVR,
da LPM inkonsequenterweise Bytes adressieren kann...  Meiner
Meinung nach wäre es sinnvoller gewesen, sie hätten LPM dann auch
auf 16-bit-Worten aufgesetzt.  Das gelegentlich mal verplemperte
Byte an Ende eines Strings macht das Kraut nicht fett.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie stellst du dir ein solches LPM vor? Als 16bit Ladebefehl? Ok. Dann 
werden aber alle String-Operation *_p deutlich komplizierter, denn wo 
steht geschrieben, dass der String an einer geraden Adresse anfängt.

Bliebe allenfalls die Variante eines Byte-LPM mit Byteauswahl im 
Carr<flag oder so. Auch nicht der Weisheit letzter Schluss.

Die angesprochenen RISCs übrigens arbeiten zwar wortweise, adressieren 
aber durchaus Bytes, anders als AVR im Code. Besseres Beispiel ist Maxim 
MAX2000 (auch sonst lohnend, in dessen Doku mal reinzuschauen). Das ist 
die wohl einzige Mikroprozessorarchitektur jenseits der 70er Jahre, die 
allen Ernstes auch Daten wortweise adressiert. Will man Bytes 
laden/speichern, stellt man das Speicherinterface ad hoc auf 
Byteadressierung um. Da kommt Freude auf, zumal die Adresse eines 
Objektes auch noch davon abhängt, in welchem Speicher der Befehl steht, 
der darauf zugreift.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Kaiser wrote:

> Wie stellst du dir ein solches LPM vor? Als 16bit Ladebefehl? Ok.

Ja, werden eben als Ziel immer zwei Register geladen.

> Dann
> werden aber alle String-Operation *_p deutlich komplizierter, denn wo
> steht geschrieben, dass der String an einer geraden Adresse anfängt.

Das wäre dann die Bedingung gewesen.  Lässt sich im Compiler einfach
realisieren.  Wie geschrieben, man verplempert mit 50%iger
Wahrscheinlichkeit ein Byte, aber das stört beim ROM eher nicht.

Auch den Rest (Zugriff auf die beiden gelesenen Bytes) kann ein
Compiler einfach erledigen, und das war ja mal die Grundidee hinter
RISC.

Dafür wäre wenigstens die Adressierung konsistent gewesen.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Das wäre dann die Bedingung gewesen.  Lässt sich im Compiler einfach
> realisieren.

Und was wird aus:
char hex[] PROGMEM = "0123456789ABCDEF";
pgm_read_byte(&hex[i]);
strcpy_p(buf, "unsinn"+(sinn ? 2 : 0));

sizeof(char)==1 per Definition. Geht also nur, wenn pro Wort nur 1 Byte 
gespeichert wird.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Kaiser wrote:

> Und was wird aus:
>
char hex[] PROGMEM = "0123456789ABCDEF";
> pgm_read_byte(&hex[i]);

pgm_read_byte() kann es logischerweise nicht geben, wenn die
zu Grunde liegende Maschine das nicht kann.

>
strcpy_p(buf, "unsinn"+(sinn ? 2 : 0));

Verboten. ;-)  strcpy_p() ist keine Standard-Funktion, es wäre der
Implementierung also einfach möglich gewesen zu erklären, dass das
Ergebnis nur definiert ist, solange der Parameter ein string
literal ist, das vom Compiler in den Flash gelegt worden ist.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:

> pgm_read_byte() kann es logischerweise nicht geben, wenn die
> zu Grunde liegende Maschine das nicht kann.

Und was ist mit &hex[i]? Wenn es dem Compiler überhaupt noch gestattet 
sein soll, selbst Adressen für Flash-Datenobjekte zu vergeben und zu 
nutzen, dann muss dieser Ausdruck erlaubt sein. Sofern man sich 
einigermassen an den C Kontext halten und keine neue Programmiersprache 
für die Flash-Objekte erfinden will.

Nope. Wenn &hex[i] überhaupt definiert ist, dann ist 1 char = 1 
Flash-Wort, alle Probleme sind gelöst - ausser dem entstehenden 
Platzproblem. Nur diese Variante ist wirklich konsistent.

Wenn es dir dann noch gelingt, im Codeword 2 Bits einzusparen, dann hast 
du einen PIC14 ;-).

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wenn es dir dann noch gelingt, im Codeword 2 Bits einzusparen, dann hast
> du einen PIC14 ;-).

Ick. ;-)

Ich würde wohl eher das Codewort auf 32 Bits ausdehnen.  Ach nee,
hilft auch nicht, dann hab' ich einen ARM. ;-)

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Billig ist das allerdings nicht

Doch, wenn man es richtig implementiert schon. Mein Flash-Pointer ist 
kein bischen größer als direkte Zugriffe auf Flash-Variablen mittels 
pgm_read_*. Es wird immer angenommen, mit C++ habe man einen immanenten 
Overhead gegenüber C, aber das ist Unsinn.

> und bei denLibrary-Funktionen wie strxxx und printf hilft das auch
> nicht weiter, es sei denn du implementierst auch diese neu.

Das stimmt. Aber ein cout-artiges Interface wäre eh viel geschickter auf 
einem AVR als printf.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Doch, wenn man es richtig implementiert schon.

Ich dachte eher an generische Pointer, d.h. 3 Byte für die Adresse, 1 
für den Adressraum (code/data). Das ist schon ein bischen teurer. Das 
wird man bei AVRs aus Platzgründen eher nicht inlinen wollen, und kostet 
damit doch etwas mehr Zeit.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich dachte eher an generische Pointer

Ach so. An sowas hatte ich auch schon mal gedacht, per Compilerflag 
ein-/ausschaltbar.

>, d.h. 3 Byte für die Adresse, 1 ür den Adressraum (code/data).

Im Prinzip reicht auch ein Bit für den Adressraum. 23 Bits für die 
Adresse reichen ja auch für alle bisherigen AVRs. Erst wenn mal einer 
mit mehr als 8MB Flash rauskommt, braucht man noch ein Byte mehr.

> Das ist schon ein bischen teurer.

Ja, aber nur dort, wo auch wirklich die Unterscheidung zur Laufzeit 
gemacht werden muß. Für direkte Variablenzugriffe (und wegoptimierte 
Zeigerderferenzierungen) zahlt man nichts extra. Da kann schon der 
Compiler abhängig von der Adresse den richtigen Ladebefehl einsetzen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.