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
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.
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:
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
> 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.
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
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.
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.
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.
> 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.
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
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.
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
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.
@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.
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.
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.
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.
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.
pgm_read_byte() kann es logischerweise nicht geben, wenn die
zu Grunde liegende Maschine das nicht kann.
>
1
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.
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 ;-).
> 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. ;-)
> 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.
> 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.
> 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.