Forum: Mikrocontroller und Digitale Elektronik adiw zl, Register?


von Dirk Schlage (Gast)


Lesenswert?

Hallo.
'Tschuldigung, dass ich hier wieder was auf den Tisch bringe, was
schon beliebig häufig durchgekaut worden ist:

Mit folgendem Code kann ich auf das dritte Byte in einer Tabelle
zugreifen.

ldi ZH,high(LookUp*2)
ldi ZL,low(LookUp*2)
adiw ZL,2
lpm
...
.db 0x01, 0x90, 0xwasweissdennich...

In meinem Fall möchte ich aber die Tabelle über ein Register
indizieren. Nun kann ich eine Kopie des Registers erstellen und in
einer Schleife auf Null prüfen, und wenn nicht

adiw ZL,1

und an den Anfang der Schleife hüpfen...

Die Lösung gefällt mir aber nicht, wegen der Schleife.

Ich habe versucht mein Register auf das ZL draufzuaddieren, und dann
den Carry zu verarbeiten. Kommt aber Scheissdreck dabei raus....

Ich habe hier auch in den Beiträgen gesucht, aber nix gefunden...

Wie macht man's richtig?

ciao
   Dirk

von Ichbinsnur (Gast)


Lesenswert?

add ZL,r16
brcc PC+2
inc ZH

von Stefan (Gast)


Lesenswert?

clr R1
 ...
add ZL,R16
addc ZH,R1

gcc hat in Wert R1 immer die NULL stehen, ist sicher auch für
asm-Programmierung kein schlechter Ansatz.

Wenn Du Assembler tiefer verstehen willst: schau Dir den asm-Output
Deines Compilers an und versuche ihn nachzuvollziehen ...

Gruß, Stefan

von Peter D. (peda)


Lesenswert?

R1 sollte man aber besser nicht als Null-Wert verwenden, daß wird doch
bei MUL und SPM benötigt.


Peter

von Stefan (Gast)


Lesenswert?

Ich habe dsa Register angegeben, welches von gcc auch als NULL-Reg
benutzt wird. Dann muss man nicht groß umbauen, wenn die asm-Funktion
vom Compiler aus verwendet wird.

Nach mul oder muls löscht der Compiler R1 wieder auf Null (eor
r1,r1).

Stefan

von Peter D. (peda)


Lesenswert?

@Stefan,

als Assemblerprogramierer ist man ja glücklicherweise an keinerlei
Restriktionen gebunden, wie ein C Compiler.
Da kann man alles so machen, wie es gerade auch vernünftig ist.

Die Sache hat nämlich noch einen weiteren Haken, ein Interrupt muß dann
davon ausgehen, daß R1 doch nicht 0 ist. Die Folge davon ist, daß in C
Interrupts sehr lang werden.
Ein leerer Interrupt dauert ja 10 Zyklen.
Mit einer Grundarie an PUSH/POP für R0,R1,SREG usw. dauert ein leerer
Interrupt in C aber schon 30 Zyklen, d.h. da ist noch garnichts
gemacht.
Das ergibt dann z.B. für einen 16Bit Zähler an einem externen Interrupt
in Assembler 14 Zyklen unter Verwendung von Registervariablen aber in C
sinds dann ja schon 40 Zyklen.

Anders gesagt, wenn man sich in Assembler an die C Konventionen halten
würde, verliert man doch alles Vorteile in Bezug auf Kodegröße und
Geschwindigkeit.

Deshalb würde ich in Assembler auf C überhaupt keine Rücksicht nehmen.
Was einmal in Assembler angefangen wurde kann man eh nicht 1:1 in C
umschreiben oder integrieren.


Peter

von crazy horse (Gast)


Lesenswert?

ich benutze in C eigentlich immer die Option
#savereg-
und kümmer mich selber um die Sicherung, ist in der Tat ein bisschen
viel des guten, was die Compiler da so veranstalten. Oft stört es zwar
nicht, aber es gibt schon zeitkritische Sachen.
Ich habe bis jetzt auch noch keinen Compiler gesehen, der vorher
schaut, was gerettet werden muss, und auch nur dieses tut.

von Dirk Schlage (Gast)


Lesenswert?

Hallo.
Danke nochmal für die Hinweise. Ich hatte 'Add With Carry' verwendet
und nicht darüber nachgedacht, was das eigentlich bedeutet.

Jetzt sieht's echt gut aus.

ciao
   Dirk

von Stefan (Gast)


Lesenswert?

@crazy horse:
ist ne gute Idee, werde ich mal ausprobieren.

@peter:
ich mache eigendlich auch sehr gerne viel in Assembler. Aber Portieren
auf eine andere CPU heisst dann halt immer: komplett neuschreiben.
Mittlerweile bemühe ich mich, den Hauptteil in C zu schreiben und nur
die zeitkritischen Sachen in ASM zu machen.
Klar, einen IR in C, das tut schon weh. Aber die Ausgabe auf ein LCD in
ASM zu optimieren, um danach länger auf selbiges warten zu dürfen ...
muss ich mir nicht mehr antun.
Ich bin gerade am Ausprobieren, wie man gcc überredet, Register
freizuhalten (für den IR), was ich bisher gelesen habe, sollte das
eigendlich schon machbar sein.

Stefan

von crazy horse (Gast)


Lesenswert?

Register freihalten ist doch gar kein Problem, du definierst dir einfach
eine (oder mehrere) char-Variablen global, bei CV kannst du sogar
bestimmen, in welches Register die kommt (bei anderen Compilern sicher
auch, weiss ich aber nicht) unsigned char asm_var @ 5 z.B.
Meckert dann zwar ein bisschen beim compilieren warning: var xxx
declared, but never used bla bla bla), aber wen stört das.
Ist auch ein schöner Weg, in einer ISR per Assembler Daten zu
manipulieren, die dann vom C-Programm weiterverarbeitet werden.
Meist reserviere ich auch ein Register auf diesem Weg für das SREG in
ISRs.
Bsp: eine Int-Variable soll bei Timerüberlauf incrementiert werden.
Lässt man den Compiler gewähren, wie er will, dauert diese einfache
Aufgabe 74 Takte, assembleroptimiert sind es nur 9 Takte...

von Stefan (Gast)


Lesenswert?

Ja, genau das probiere ich gerade beim gcc. Da funktioniert es mit

register char dummy  asm("r8");

Habe aber noch nicht auf ev. Seiteneffekte untersucht bzw. welche Reg
man für sowas verwenden darf. Vor allem wie die libc auf sowas reagiert
will ich mir noch anschauen.

Es gibt auch eine Compiler-Option, die ein Reg freihält, dann geht es
auch ohne Warnung, habe ich aber noch nicht probiert.

Stefan

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.