Hallo! Ich frage mich gerade, angeregt von meinem anderen Thread, wo überhaupt der Unterschied zwischen funktionsname("Hallo Welt!"); und funktionsname(PSTR("Hallo Welt!"); liegt. Beides wird im µC im gleichen Speicher untergebracht bloß im ersten Fall am Ende, im zweiten Fall mitten drin. Welche Vorteile/Nachteile bietet dieses Prinzip? Warum legt gcc überhaupt eine Trennung an? Der Atmel unterscheidet das doch nicht oder liege ich da falsch? Ergeben sich zur Laufzeit unterschiede? Grüße!
Die erste Version dürfte kompilieren, die zweite wird der Compiler abweisen weil eine schließende Klammer fehlt ;-) Doch Spass beiseite: Welche "pseudo-Havard-Architektur" meinst du? In der Annahme du sprichst vom AVR (der keine "pseudo-Havard-Architektur" besitzt) Wie kommst du auf "...bloß im ersten Fall am Ende, im zweiten Fall mitten drin." Im ersten Fall steht der String sowohl im Flash als auch im RAM. Im zweiten Fall steht er nur im Flash, und die Funktion muss mit den entsprechenden *_P - Befehlen auf diesen Speicherbereich zugreifen. In beiden Fällen steht er "bevorzugt" (= wenn dort noch Platz ist) in den ersten 64kByte des Flash.
> Im ersten Fall steht der String sowohl im Flash als auch im RAM.
Wobei man sagen muss, dass aus Sicht des Programmes der String
nur im SRAM steht.
Nur: Irgendwie muss der ja auch dorthin kommen. Das macht die
Startup Sequenz, die den String aus dem Flash ins SRAM kopiert,
noch bevor main() die Kontrolle erhält. Danach ist das Original
im Flash eigentlich überflüssig. Gearbeitet wird nur noch mit
der Version im SRAM.
Jetzt wird mir doch einiges klarer. Also "vergeude" ich jedes mal, wenn ich eine Konstante nutze wertvollen Arbeitsspeicher, wenn diese nicht direkt aus dem Flash geladen wird. Und das betrifft ja durchaus auch Konstanten, die im Assembler als Displacement gespeichert würden. Betrifft denn die Speicherplatzzuweisung von Konstanten nur die pre-main Funktion? Sprich, wenn ich in einem Unterblock/Funktion eine Konstante definiere, dann ist diese doch nicht schon im SRAM, wenn ich noch nicht dahin verzweigt habe, oder? Ich hätte das schon längst überprüft, weiss aber nicht, wie ich bei meinem AVR-Studio das SRAM anzeigen kann. Weiss jemand, wie das geht? Ich komme wohl an den Programmspeicher und das EEPROM, aber nicht an den Inhalt des SRAM. Dann schließe ich also daraus, dass ein AVR eine echte Havard-Architektur ist, die Daten und Befehle getrennt verwalten kann? Donnerwetter, das hätte ich nicht gedacht. Grüße!
Äh, natürlich kommst Du im AVR-Studio ans RAM, was meinst Du wohl, wo Variablen gespeichert werden und der Stack liegt?
Ja, das ist mir schon klar. Nur man kann ihn nicht gesamtheitlich anzeigen, so wie man das mit dem Programmspeicher machen kann oder übersehe ich da was? Bei Variablen muss ich halt immer den Namen kennen. Da kann ich doch nicht sagen: Zeig mir mal alle Speicheradressen von 0x00 bis 0x10.
Günther Frings wrote: Da's noch nicht beantwortet worden ist: > Welche Vorteile/Nachteile bietet dieses Prinzip? Vorteile: parallelisierte Buszugriffe und damit kürzere Abarbeitungszeit. Drückt sich darin aus, dass ein LDS in 2 Takten abgearbeitet wird, ein LPM in 3 Takten. Das hängt damit zusammen, dass beim LPM der ROM-Bus erst einmal mit dem Lesen des Befehls beschäftigt ist und danach dann erst für die Daten zur Verfügung steht. Nachteile: hast du ja praktisch schon bemerkt. Der Datenzugriff auf den ROM benutzt andere Befehle als der auf den RAM. Ein Befehlszugriff auf den RAM ist gar nicht möglich (wobei das manche sicher nicht als großen Nachteil empfinden werden ;-). Die Sprache C hat bislang keinerlei Unterstützung für verschiedene physisch getrennte Adressräume. Zwar wurde C auch schon sehr früh auf Harvard-Maschinen benutzt (PDP-11 mit getrenntem Daten- und Adressbereich), aber damals hat man das nur gemacht, um den adressierbaren Speicher pro Task von 64 KiB auf 128 KiB zu vergrößern, da wurden aus dem Befehlsspeicher dann wirklich nur Befehle gelesen und aus dem Datenspeicher nur Daten. Will man hingegen aus dem Befehlsspeicher Daten lesen, hört's mit den Standardmitteln von C auf. GCC kennt praktisch nur einen flachen Adressraum, die verschiedenen Adressräume eines AVR (RAM, ROM, EEPROM) werden daher im AVR-GCC mit fiktiven Offsets (die außerhalb der Speichergrenzen von AVRs liegen) in einen flachen 32-bit-Adressraum abgebildet. Das ist ein ziemlicher Hack. Andere Compiler bieten da zwar integrierten Support an, aber letztlich kann durch die fehlenden C-Hausmittel eine gerufene Funktion nicht mehr vom bloßen Angucken eines Zeigers her sagen, ob dieser nun in den RAM oder ROM zeigt. Es gibt einen Entwurf im C-Standard-Kommittee für "Embedded C", der u. a. auch den sauberen Umgang mit mehreren Speicherbereichen abdeckt, aber den hat meines Wissens noch kein (namhafter) Compilerhersteller implementiert.
Jörg Wunsch wrote: > GCC kennt praktisch nur einen flachen Adressraum, die verschiedenen > Adressräume eines AVR (RAM, ROM, EEPROM) werden daher im AVR-GCC mit > fiktiven Offsets (die außerhalb der Speichergrenzen von AVRs liegen) > in einen flachen 32-bit-Adressraum abgebildet. Das ist ein ziemlicher > Hack. Im GCC gibt es ja den Datentyp prog_char bzw prog_uintxx_t. Könnte man nicht das ganze so machen wie z.B. in Codevision, dass entsprechende Daten von einem solchen Pointer automatisch aus dem Flash geladen werden ? Das setzt natürlich voraus, das der Compiler den Datentyp strenger überprüft, und eine Umandlung von Pointern in prog_ Pointer nicht ohne explizite Casts zulässt. Dies sollte ja eigentlich kein allzugroßer Aufwand sein, denn genauso wie Adressen jenseits der 64k andere Befehle erfordern, verwendet der Compiler für den Flash Bereich entsprechende Befehle. Oder habe ich da was übersehen ?
Wenn man das könnte hätte man das längt getan. Offensichtlich ist jedoch der GCC bislang nicht in der Lage, die Assoziation eines Pointers mit einem Adressraum zum Codegenerator durchzureichen. Was man sicherlich realisieren könnte: Alle Pointer als generische Pointer implementieren. 3 Bytes lang, mit einem Bit für ROM/RAM. Natürlich kostet das etwas: umständlicher platzraubender Zugriff oder Laufzeitfunktionen für Zugriff. Und weil GCC auch dann immer noch keine Unterschied zwischen Pointern macht, gilt das dann zwangsläufig für jeden Pointer.
> denn genauso wie Adressen jenseits der 64k andere Befehle > erfordern, verwendet der Compiler für den Flash > Bereich entsprechende Befehle. Bei bekannten Adressen ist das kein Problem. Die Krux ist nur, dass bekannte Adressen die absolute Ausnahme darstellen. Sowas gibt es eigentlich nur bei Zugriffen auf I/O-Ports (*(uchar)0x55). Bereits bei einer normalen Variable kennt erst der Linker die Adresse, und dann ist es zu spät. Unter so etwas leiden auch Architekturen, die zwar nur einen einzigen Adressraum haben, aber unterschiedlich lange Adressen (z.B. 68xx, M16C) in den Befehlen codieren.
> Dann schließe ich also daraus, dass ein AVR eine echte > Havard-Architektur ist, die Daten und Befehle getrennt verwalten kann? Ja. Es gibt Codespeicher (Flash) und Datenspeicher (RAM), die intern über getrennte Busse angebunden sind. Code kann nur aus dem Flash ausgeführt werden. Daten können zwas aus RAM und Flash gelesen werden, aber die Assembler-Instruktionen sind verschieden.
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.