Forum: Mikrocontroller und Digitale Elektronik Z-Pointer lpm Verständnisfrage (Anfänger)


von Timo (Gast)


Lesenswert?

Hallo,

ich arbeite mich zur Zeit als blutiger Programmieranfänger durch das 
AVR-Assembler-Tutorial. Soweit habe ich eigentlich alles gut verstanden 
und auch schon erste kleine eigene Programme zur Led-Ansteuerung 
ausgetüftelt.

Allerdings hänge ich jetzt schon seit gestern Abend an folgender Stelle:

Zitat:
Der Befehl lpm dient zum Laden einzelner Bytes aus dem Programmspeicher. 
Das ist vor allem für Tabellen mit konstanten Werten sehr nützlich 
(7-Segmentdekoder, Zeichensätze, Kennlinien, Parameter Texte, etc.) Doch 
wie kommt man nun in dem wortweise adressierten Programmspeicher an 
einzelne Bytes? Ganz einfach. Der AVR "mogelt" hier und erwartet im 
Z-Register eine Byte-Adresse. Von dieser Adresse bilden die Bits 15..1 
die Wortadresse, welche zur Adressierung des Programmspeichers verwendet 
wird. Bit 0 entscheidet dann, ob das hoch- oder niederwertige Byte in 
das Zielregister kopiert werden soll (0=niederwertiges Byte; 
1=höherwertiges Byte).

Darum muss bei Verwendung des Befehls lpm die Anfangsadresse immer mit 
zwei multipliziert werden.
Zitat Ende.

Wieso man die eigentliche Programmspeicheradresse mit 2 multiplizieren 
muss verstehe ich (alle Bits werden 1 nach links geshiftet, sodass die 
eigentlich Programmspeicheradresse (die ja eh nur 12 Bit lang ist) auf 
den Bits 15-1 liegt). Was mir allerdings unklar ist, ist wie jetzt 
bestimmt wird, welches Byte denn jetzt geladen werden soll. Denn das 
unterste Bit ist nach einer Multiplikation mit 2 doch immer 0 oder 
nicht?

Oder ist es so, dass man generell erst das low Byte lädt, dann den 
Z-Pointer mit lpm r16,Z+ auf das high Byte setzt und anschliesend das 
lädt?

Verstehe ich es richtig, dass der Z-Pointer nur im Zusammenhang mit dem 
lpm Befehlt Byte-Weise positioniert wird und ansonsten immer auf eine 
komplette 16bit Programmspeicheradresse zeigt die dann in ZL und ZH 
aufgeteilt ist und z.b. mit ijmp angesprungen werden kann?


Vielen Dank!

Gruß,
Timo

von Karl H. (kbuchegg)


Lesenswert?

Timo schrieb:

> den Bits 15-1 liegt). Was mir allerdings unklar ist, ist wie jetzt
> bestimmt wird, welches Byte denn jetzt geladen werden soll. Denn das
> unterste Bit ist nach einer Multiplikation mit 2 doch immer 0 oder
> nicht?

2 Dinge

* wenn du mittels eines Labels irgendetwas im Programmspeicher
  unterbringst, dann sorgt der Assembler schon dafür, dass es auf
  die gerade Adresse zu liegen kommt.
  d.h. in dem Fall brauchst du einfach nur die Adresse (in Form des
  Labels) beim Laden des Z-Pointers mal 2 nehmen und alles passt.

* zweitens.
  Auch der Z-Pointer ist im Grunde nur eni Register (eigentlich
  Registerpärchen) wie jedes andere. Alle Befehle, die auf
  Register anwendbar sind, funktionieren selbstverständlich
  auch für das Registerpärchen R30/R31 (welche ja den Z-Pointer
  darstellen). Insbesondere kann man selbstverständlich nach dem
  Laden noch 1 dazuzählen oder man kann das selbstverständlich
  auch direkt beim Laden des Z-Pointers schon angeben. Der Assembler
  kann ja rechnen. Er hat ja auch die Adresse (die durch das
  Label gegeben ist) mal 2 rechnen können. Da kann er dann auch
  ruhig noch 1 dazuzählen.

>
> Oder ist es so, dass man generell erst das low Byte lädt, dann den
> Z-Pointer mit lpm r16,Z+ auf das high Byte setzt und anschliesend das
> lädt?

Das macht jetzt aber was anderes., mittels

    lpm  r16, Z+
    lpm  r17

lädst du ja 2 hintereinanderliegende Bytes aus dem Flash.

> Verstehe ich es richtig, dass der Z-Pointer nur im Zusammenhang mit dem
> lpm Befehlt Byte-Weise positioniert wird und ansonsten immer auf eine
> komplette 16bit Programmspeicheradresse zeigt die dann in ZL und ZH
> aufgeteilt ist

Der Z-Pointer ist immer in ZH und ZL aufgeteilt (volgo R30/R31)

von Kali (Gast)


Lesenswert?

>Was mir allerdings unklar ist, ist wie jetzt bestimmt wird, welches Byte >denn 
jetzt geladen werden soll. Denn das unterste Bit ist nach einer >Multiplikation 
mit 2 doch immer 0 oder nicht?

Was hindert Dich daran unmittelbar nach der Multiplikation noch eine 
weitere Operation anzufügen, die das zu ladende Byte bestimmt?
Stimmt. Nichts.

>Oder ist es so, dass man generell erst das low Byte lädt, dann den
>Z-Pointer mit lpm r16,Z+ auf das high Byte setzt und anschliesend das
>lädt?

Nein. Mit lpm r16,Z+ wird sowohl ein Byte geladen und Z erhöht.

Es wäre sinnlos, generell erst das low Byte laden. Es mag z.B. sein, das 
man nur das Byte an der ungeraden Adresse braucht. Wozu dann noch das an 
der geraden Adresse laden?

>Verstehe ich es richtig, dass der Z-Pointer nur im Zusammenhang mit dem
>lpm Befehl Byte-Weise positioniert ...
Nicht nur. Aber beim lpm Befehl schon.

> ... und ansonsten immer auf eine
komplette 16bit Programmspeicheradresse zeigt die dann in ZL und ZH
aufgeteilt ist und z.b. mit ijmp angesprungen werden kann?

Nein. Nicht "ansonsten". Was Du beschreibst ist die Interpretation des 
Wertes in Z im Falle des ijmp. Es gibt andere Interpretationen. In der 
Befehlsbeschreibung stehen die weiteren.

von Kali (Gast)


Lesenswert?

Zu spät. Man soll halt nicht während des Antwortens noch Tee kochen. :-{

von Timo (Gast)


Lesenswert?

Vielen Dank erst mal ihr Beiden!! :) Das bringt mich weiter.

Karl Heinz Buchegger schrieb:
> Das macht jetzt aber was anderes., mittels
>
>     lpm  r16, Z+
>     lpm  r17
>
> lädst du ja 2 hintereinanderliegende Bytes aus dem Flash.

Kali schrieb:
> Nein. Mit lpm r16,Z+ wird sowohl ein Byte geladen und Z erhöht.

Stimmt... da hab ich wohl einmal zu viel geladen

Kali schrieb:
> Nein. Nicht "ansonsten". Was Du beschreibst ist die Interpretation des
> Wertes in Z im Falle des ijmp. Es gibt andere Interpretationen. In der
> Befehlsbeschreibung stehen die weiteren.

Ah natürlich.. ich verstehe. Der Z-Pointer enthält einfach eine Adresse 
des Programmspeichers. Die Befehle können damit dann natürlich machen 
was sie wollen :) (lpm sieht einfach die obersten 15 Bits als 
Programmspeicheradresse von der geladen werden soll an)

Kali schrieb:
> Was hindert Dich daran unmittelbar nach der Multiplikation noch eine
> weitere Operation anzufügen, die das zu ladende Byte bestimmt?
> Stimmt. Nichts.

Stimmt.. jetzt wo du es sagst. Frage mich, wieso ich mich damit jetzt so 
schwer getan habe. Ist doch eigentlich alles nur logisch :) 
Warscheinlich muss sich mein Hirn erst mal an die neue Denkweise mit den 
ganzen Registern und Speicheradressen gewöhnen, ist doch recht viel 
neuer Stoff den es zu verarbeiten gilt.

von Karl H. (kbuchegg)


Lesenswert?

Timo schrieb:

> Ah natürlich.. ich verstehe. Der Z-Pointer enthält einfach eine Adresse
> des Programmspeichers. Die Befehle können damit dann natürlich machen
> was sie wollen :) (lpm sieht einfach die obersten 15 Bits als
> Programmspeicheradresse von der geladen werden soll an)

Du magst jetzt vielleicht lächeln, aber das, genau das, ist eine ganz 
wichtige Erkentniss in so gut wie allen Programmiersprachen, ganz 
speziell aber in Assembler. Die Kombination von Befehlen macht das 
Rennen. Die Befehle selbst sind eigentlich ganz einfach.

von Falk B. (falk)


Lesenswert?


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.