Microchip schrieb:
> "...Thus, the least significant bit of the Z pointer selects either low byte
(ZLSB = 0) or high byte (ZLSB = 1)."
Also wird das LSB von ZL als Schlater für den Z-Pointer verwendet.
Es entscheidet, welcher Teil vom Datenwort geladen werden soll.
Deshalb macht es irgendwie auch Sinn den ZP beim initialisieren mit 2 zu
multiplizieren. Aber für mich macht es keinen Sinn ZH und ZL einzeln zu
multiplizieren/shiften, da beim multiplizieren mit dem ZH das Carry-bit
von ZL nicht mit rein geshiftet wird. Ein Bit geht dann so zusagen
verloren.
Trotzdem wird das so gemacht und es scheint auch zu funktionieren.
Wie es "alle" machen:
1
ldi ZL, LOW(text*2) ; Adresse des Strings in den
2
ldi ZH, HIGH(text*2) ; Z-Pointer laden
Und so würde es für mich Sinn machen:
1
ldi temp, LOW(text)
2
mul temp, 0x02 ;der entfallene Bit im Carry lagern
Hallo,
das sieht nach AVR Mnemonics aus.
Du weisst schon, dass (text*2) Konstant ist?
Da wird zur Laufzeit nichts gerechnet!
Und die Macros/Anweisungen LOW(n), bzw. HIGH(n) "lesen" nur das
jeweilige Byte aus.
Karl M. schrieb:> Du weisst schon, dass (text*2) Konstant ist?> Da wird zur Laufzeit nichts gerechnet!> Und die Macros/Anweisungen LOW(n), bzw. HIGH(n) "lesen" nur das> jeweilige Byte aus.
Sicher ist mir dass bewusst...
Beim AVR sind alle Flash-Adressen Zeiger auf Worte (16Bit),
eine Flash Byte-Adresse, hat dem nach den Wert (Pointer*2).
Steht auch so im Datenblatt eines AVR µC.
Bei manchen Zugriffen auf das Flash, muss man mit 20 Bit Adressen
hantieren, da ḱommt dann ein weiteres Byte hinzu.
SemiTech schrieb:> Karl M. schrieb:>> Du weisst schon, dass (text*2) Konstant ist?>> Da wird zur Laufzeit nichts gerechnet!>> Und die Macros/Anweisungen LOW(n), bzw. HIGH(n) "lesen" nur das>> jeweilige Byte aus.>> Sicher ist mir dass bewusst...
Dann ist deine Frage nicht sinnvoll.
SemiTech schrieb:> Karl M. schrieb:>> Du weisst schon, dass (text*2) Konstant ist?>> Da wird zur Laufzeit nichts gerechnet!>> Und die Macros/Anweisungen LOW(n), bzw. HIGH(n) "lesen" nur das>> jeweilige Byte aus.>> Sicher ist mir dass bewusst...
Ehm... habs jetzt verstanden, danke.
Ich dachte erstmal du willst auf etwas anderes hinaus
Vielleicht noch eine Anmerkung:
wer mit 2 multipliziert, hat noch nie etwas von einem Verschieben nach
Links ins Carry "shl" und anschließendem rotieren nach Links mit Carry
"rol" gehört.
Karl M. schrieb:> Vielleicht noch eine Anmerkung:> wer mit 2 multipliziert, hat noch nie etwas von einem Verschieben nach> Links ins Carry "shl" und anschließendem rotieren nach Links mit Carry> "rol" gehört.
Doch klar, aber als ich letztens einen Beitrag über die Umwandlung von
Assembler zu OP-Code gelesen habe und herausfand, das es zu rol und lsl
keine OP Codes gibt, sondern dass diese vom Assembler durch andere
Instruktionen ersetzt werden. Z.B. rol tmp == adc tmp, tmp, fand ich das
sinnvoller, weil ich dem Assembler damit die Arbeit erspare.
Aber trotzdem danke für den Hinweis
SemiTech schrieb:> Microchip schrieb:>> "...Thus, the least significant bit of the Z pointer selects either low byte> (ZLSB = 0) or high byte (ZLSB = 1).">> Also wird das LSB von ZL als Schlater für den Z-Pointer verwendet.
Bullshit. Das Zitat stammt aus der Beschreibung der beim Schreiben von
Flash relevanten Funktionalität, konkret: der beim Füllen des
Flashbuffers relevanten.
Das gilt dort UND NUR DORT. Dus unterste Bit von ZL wählt da aus, ob das
Datum aus R0 oder R1 kommt. Das ist schon alles.
SemiTech schrieb:> Deshalb macht es irgendwie auch Sinn den ZP beim initialisieren mit 2 zu> multiplizieren. Aber für mich macht es keinen Sinn ZH und ZL einzeln zu> multiplizieren/shiften, da beim multiplizieren mit dem ZH das Carry-bit> von ZL nicht mit rein geshiftet wird. Ein Bit geht dann so zusagen> verloren.
Wie kommst du darauf?
> Wie es "alle" machen:> ldi ZL, LOW(text*2) ; Adresse des Strings in den> ldi ZH, HIGH(text*2) ; Z-Pointer laden
Es wird also die (16-bittige) Adresse als Ganzes mit 2 multipliziert,
dann der LOW-Teil davon nach ZL geladen. Und das entsprechende wird dann
mit dem HIGH-Byte und ZL gemacht. Wo willst du da irgendein Carry-Bit
verlieren?
Rolf M. schrieb:> Es wird also die (16-bittige) Adresse als Ganzes mit 2 multipliziert,> dann der LOW-Teil davon nach ZL geladen. Und das entsprechende wird dann> mit dem HIGH-Byte und ZL gemacht. Wo willst du da irgendein Carry-Bit> verlieren?
Das hatte mir doch Karl M. schon gut erklärt.
Thema gegessen :D
SemiTech schrieb:> das es zu rol und lsl> keine OP Codes gibt, sondern dass diese vom Assembler durch andere> Instruktionen ersetzt werden. Z.B. rol tmp == adc tmp, tmp, fand ich das> sinnvoller, weil ich dem Assembler damit die Arbeit erspare.
Bitte... was? Dem Assembler die Arbeit ersparen. Habe selten so gelacht.
Danke dafür. Wie viele Tage Urlaub bekommt der Assembler bei dir?
Und um deine Frage noch zu beantworten:
Das label 'text' liefert die 16 bit Wort-Adresse zurück. Aber der lpm
Befehl erwartet eine Byte-Adresse im Z_Pointer. Deswegen wird text mit 2
multipliziert (vom Assembler, da statischer Ausdruck) und diese Adresse
wird dann verwendet.
Anzumerken ist dabei, dass dir .db vom Assembler aus diesem Grund immer
an eine 16bit Wortadresse gelegt wird.
Diese zwei Bytes:
1
text: .db 0x10 ; <= Adresse text*2
2
.db 0x11 ; <= Adresse (text+1)*2
liegen im Speicher nicht hintereinander. Es wird vom Assembler ein
Pufferbyte eingefügt, sodass 0x11 wieder an einer wort adresse liegt. In
diesem Fall warnt dich der Assembler aber. Will man die Bytes
kontinuierlich im Speicher haben muss man
M. H. schrieb:> Bitte... was? Dem Assembler die Arbeit ersparen. Habe selten so gelacht.> Danke dafür.
sicherlich genial etwas knapp daneben, aber so ganz genau könnte der
Opcode für mul Rd,k ["wer mit 2 multipliziert",..] auch nicht passen.
1
/*a*/ mul temp, 0x02; früher: R1:R0 ← (tmp x Rr) << 1
2
; rol tmp == adc tmp, tmp
3
/*b*/ lsl tmp ; tmp*2
4
/*c*/ add tmp, tmp ; tmp+tmp
5
; ....
6
adc temp, 0x00 ;Add with Carry
/*c*/ könnte sich aufgrund der vielen Buchstaben als Mehrbeit für den
Assembler herausstellen und hoffentlich findet SemiTech auch etwas zum
schmunzeln daran. Interessant wäre ob add tmp,tmp vs. lsl tmp dem
programmierenden Denker Arbeit erspart, wenn der nicht aus Gewohnheit
mit lsl vorbelastet ist.