Liebe Leser,
mittlerweile habe ich mehrfach an verschiedenen Stellen im Netz gelesen,
dass man in Assembler nicht mit den Original-Registerbezeichnungen
arbeiten soll.
Statt
1
ldi r16, 0
sollte man per .def die Registerbezeichnungen ändern und folgendermaßen
programmieren
1
.def tmp = r16
2
;
3
; massig anderer Code ;)
4
;
5
ldi tmp, 0
Gibt es dafür einen Grund? Außer, dass man dann eben andere Namen hat...
Liebe Grüße
Uwe Homm
Hallo,
manche Register haben auch Spezalfunktionen (R0, R26-31 z.B.).
manchmal will man auch Registerpaar als Doppelregister für einige
Befehle wo das möglich ist, manchmal will man ein High-Register nach
unten verlgen, weil man merkt, daß die Zugriffsmöglichkieten doch
reichen.
Wenn ich jetzt im Source alle r16 durch r9 ersteze kann auch schnell ein
r16 in einer Bezeichung durch r9 erstezt werden und damit ist was
anderes kaputt.
Wenn sie definert sind, muß ich nur .def tmp = r16 in .def tmp = r9
ändern.
Gruß aus Berlin
Michael
Lieber Michael,
das leuchtet mir ein...und erinnert mich an das gute alte #define in C
um z.B. lesbarere UND leichter zu ändernde Konstanten zu erhalten.
Ich merke, dass ich schon länger nicht mehr in Assembler programmiert
habe ;)
LG
Uwe Homm
Uwe H. schrieb:> mittlerweile habe ich mehrfach an verschiedenen Stellen im Netz> gelesen, dass man ...> Gibt es dafür einen Grund?
Ist doch eigentlich ganz einfach. Wenn du irgendwo liest, daß man
unbedingt <beliebiges einsetzen> tun (bzw. nicht tun) sollte, dafür aber
keine einleuchtende Begründung geliefert wird, dann kannst (und
solltest!) du diese Empfehlung ignorieren.
Was nun speziell diesen Fall angeht: kommt drauf an. Hauptsächlich
darauf, wie groß oder komplex das Programm ist. Die Verwendung von
Aliasnamen für Register kann das Programm lesbarer machen. Oder auch
nicht.
Mal ein Beispiel, wo ich es sinnvoll finde. Eine Multiplikationsroutine
24 Bit unsigend * 24 Bit unsigned. Durch die Verwendung von Aliasnamen
für fac(tor) und prod(uct) kann man sich im Code nicht mehr vertun und
evtl. Register vertauschen. Das gilt umso mehr, wenn man die 3 bzw. 6
zusammengehörigen Register nicht am Block belegen kann.
Ein paar Register benenne ich immer, so z.B. R16 als temp und ein
anderes als exklusiven Speicher für SREG in ISRs. Das erhöht dann die
Übersicht deutlich und man zermanscht es nicht aus Versehen. X, Y und Z
definiert zumindest der AVR Assembler schon selber.
Ein Verbot, oder einen triftigen Grund gibt es nicht, die
Originalbezeichnungen zu verwenden. Allerdings kann man sich das
Leben beim Programmieren einfacher machen, wenn man die Namen
ersetzt.
Meine (Privat-Regel) bei AVR-ASM ist es, den Registern r0...r15
als fest verfügbaren Variablen per #define einen Programm-
spezifischen Namen zuzuweisen.
Die oberen Register (r16...r25, die auch "ldi" können), werden
immer per #define als Tmp0...Tmp9 angesprochen. Damit wird in
Unterfunktionen gerechnet.
Den Adressregistern r26...r31 sind ja schon von Hause aus die
Namen XL...ZH zugeordnet.
Axel S. schrieb:> Uwe H. schrieb:>> mittlerweile habe ich mehrfach an verschiedenen Stellen im Netz>> gelesen, dass man ...>> Gibt es dafür einen Grund?>> Ist doch eigentlich ganz einfach. Wenn du irgendwo liest, daß man> unbedingt <beliebiges einsetzen> tun (bzw. nicht tun) sollte, dafür aber> keine einleuchtende Begründung geliefert wird, dann kannst (und> solltest!) du diese Empfehlung ignorieren.
Nein. Man sollte versuchen zu verstehen, woher die Regel kommt und was
sie einem bringt (also genau das, was der TE macht). Dann kann man
entscheiden, ob man sie für sinnvoll erachtet oder nicht. Konventionen
zu ignorieren, nur weil man sie nicht versteht, ist wenig sinnvoll.
Rolf M. schrieb:> Axel S. schrieb:>>>> Ist doch eigentlich ganz einfach. Wenn du irgendwo liest, daß man>> unbedingt <beliebiges einsetzen> tun (bzw. nicht tun) sollte, dafür aber>> keine einleuchtende Begründung geliefert wird, dann kannst (und>> solltest!) du diese Empfehlung ignorieren.>> Nein. Man sollte versuchen zu verstehen, woher die Regel kommt und was> sie einem bringt
Da hätte man viel zu tun. Das Internet ist voll von Ratschlägen und
angeblich hilfreichen Regeln. Und die wenigsten sind gut begründet. Oder
manche vielleicht auch gar nicht.
Andererseits ist es aber auch nicht so, daß man nirgendwo eine
Begründung dafür finden könnte, warum man Makros oder Defines verwenden
möchte. Hat ja auch mit der Programmiersprache wenig zu tun. Auch in
BASIC oder C gibt man Variablen sprechende Namen und nennt sie nicht
einfach x1, x2, x3 usw.
Axel S. schrieb:> Das Internet ist voll von Ratschlägen und angeblich hilfreichen> Regeln. Und die wenigsten sind gut begründet.
Daraus zu schlussfolgern, dass man sämtliche Ratschläge und Regeln
ignorieren soll, wenn man sie nicht sofort offensichtlich findet, wirkt
aber auch nicht gerade klug.
Davon abgesehen hast du gerade genau so einen "guten" Ratschlag
produziert und nicht gut begründet, deiner eigenen Regel folgend sollte
er also auch von dir selbst ignoriert werden.
Hallo,
Du meinst immediate wie z.B. ldi?
Moby schrieb im Beitrag #5486877:
> Einem unbenannten r10 statt "name" sehe ich z. B. auch eher an dass> Integeroperationen nicht möglich sind.
Es wird wohl (privat und als Hobby) immer jeder selbst entscheiden
müssen. Bei mir bekommt sowas Namen seit es z.B. auf dem C64 in möglich
war.
Ist genauso eine Frage wie mit den Registernamen und Registerbits.
Selbst Editor.Sachen wie Autovervollständigung sind mir nicht wirklich
in ASM wichtig. Auch das ist mehr tippen muß ist für mich meist ein
Vorteil. Während des Eintippens habe ich Zeit (nehme mir diese) zu
beachten, was ich da mache. logische Fehler u.ä. fallen mir meist schon
da auf, weniger Debug-Geschichten geben mir diese Zeit zurück.
Gruß aus Berlin
Michael
Hallo,
Moby schrieb im Beitrag #5487063:
> Michael U. schrieb:>> Ist genauso eine Frage wie mit den Registernamen und Registerbits.>> Ich bevorzuge die kürzestmögliche Schreibweise.> In aller Regel und bei aller Sorgfalt muss man Initialisierungen später> nicht mehr hinterfragen und wenn doch wird halt ein Blick ins Datenblatt> fällig.
Initialisiereung sind ja auch eigene Sachen, externe Komponenten usw.
Könnte ich jetzt nur ein Beispiel konstruieren:
ldi r16, 0x6
out PORTB, r16.
ldi TEMP_1, 0x6
out PORTB, TEMP1
Ich halte mich da an meine eigene Konvention: TEMP_x sind temporäre
Register. Ich muß also nur innerhalb eines Unterprogamms aufpassen, ob
TEMP_1 noch frei ist oder ich eben TEMP_2 usw, nehmen muß oder obe ich
eben mit
push TEMP_1
ldi TEMP_1, 0x6
out PORTB, TEMP1
pop TEMP_1
es genau hier temporär retten muß.
ldi TEMP_1, 0b00000110
würde mir die Bits sagen ohne ein hex auseinanderzunehmen.
LDI TEMP, LED_2 | LED_1
wenn ich z.B. mit
.def LED_1 = 0b0000010
.def LED_2 = 0b0000100
als Bitmasken definiert habe, macht manchmal Sinn.
ldi TEMP, (1<<LED_2) | (1<<LED_1)
wenn ich mit
.def LED_1 = 1
.def LED_2 = 2
als Bitnummer definiere.
Jetzt noch .def LED_PORT = PORTB
ins Spiel gebracht und
ldi TEMP, (1<<LED_2) | (1<<LED_1)
out LED_PORT,TEMP_1
enden (oder anfangen...) würde es bei mir aber mit
.def LED_ERR = 1
.def LED_RDY = 2
ldi TEMP, (1<<LED_RDY) | (1<<LED_ERR)
out LED_PORT,TEMP_1
>> logische Fehler u.ä. fallen mir meist schon>> da auf>> Wie Du logische Fehler durchs Umbenennen von Registern und Ausschreiben> der Registerbits erkennst müsstest Du mal genauer erklären.
Wenn ich jetzt beim 2. Eintippen oder C&P draufschaue, fällt mir
vermutlich auf, daß es u.U. unsinning ist, Ready und Error gleichzeitig
anzumachen.
Wie gesagt, ein konstruiertes Beispiel.
Ich fange ja gleich so an und wenn ich ein neues Register brauche, daß
nicht temporär sein soll, bin ich eben oben in der definition.inc,
schaue, was noch frei ist und benne es und wenn nötig, sortiere ich eben
ein paar Registerdefinition um oder ob ich ein High-Register ohne großen
Aufwand doch nach unten befördern kann.
Gruß aus Berlin
Michael
Moby schrieb im Beitrag #5487063:
>> Ist genauso eine Frage wie mit den Registernamen und Registerbits.>> Ich bevorzuge die kürzestmögliche Schreibweise.
Normalerweise bevorzugt man (gerade bei Assembler) sinnvolle Names.
Man schreibt sich das alles in z.B. "MyDef.inc" und braucht sich nicht
mehr darum zu kümmern, etwa so:
oder so ähnlich.
Ein paar Low-Register und ein paar High-Register lässt man frei
und das wars dann.
>> logische Fehler u.ä. fallen mir meist schon da auf>> Wie Du logische Fehler durchs Umbenennen von Registern und Ausschreiben> der Registerbits erkennst müsstest Du mal genauer erklären.
Ob ich etwas so schreibe:
1
sbrsProgReg,InteliMode
2
rjmpDumbErase
oder so:
1
sbrsr21,5
2
rjmpl005
macht schon einen Unterschied, oder ?
Und folgendes wäre wahrscheinlich nicht durchgegangen:
Hi
Ich komme seit über 20 Jahren ohne diese .def-Gedödel aus. Das kann man
vielleicht für irgendwelche Spielzeugprograme machen. Wenn es größer
wird, so 10..15k Programmcode (nicht Quellcode), der noch aus zig
verschiedene Dateien besteht wird es unüberssichtlich oder ist mit
einem immensen Schreibaufwand verbunden. Ich bin da mehr für eine gut
strukturierte Programmierung.
MfG Spess
Hallo,
Moby schrieb im Beitrag #5487219:
> Das zu Mark V Gesagte würde ich so auch Dir entgegnen. Unter dem Strich> ist das alles der 4fache Schreibaufwand und sind das unötig komplex> werdende Projekte.
die Projektstruktur bei den ASM-Sachen zieht sich bei mir durch etliche
Jahre nahezu unverändert. Damit auch definitionen.inc als Beispiel.
Subroutinen/IRQ-Routinen werden meist recycelt, Anpassungen sind dort
fast nie nötig, weil die für mich brauchbar gekapselt sind.
Anpassungen gibt es da nur, wo unvermeidbar bzw. wo ich keine Lust habe,
mit irgendwelchen .ifdef zu rumzuwursteln (UART-Register der
verscheidenen AVR wenn ich da noch kein alten passendes Projekt auf
Lager habe.
Wenn ich nur einen debug-UART brauche, kommt der per .include eben rein.
Der ist Softuart, kann nur auf einem Pin als TX senden, das dann eben
ein .def bekommt. Baudrate 38400 geht auch immer. Wenn der AVR mit
internem Oszillator läuft und Zeichenmüll ankommt, wird eben aus F_CPU
1000000 mal schnell 990000 oder 1010000 gemacht, eins war bisher immer
im Toleranzfeld des Terminalprogramms.
Da ist an diesen Stellen sehr wenig Tippaufwand.
Inzwischen ist ASM ohnehin nur noch Pflege alter, bei mir im Einsatz
befindlicher Projekte, inzwischen hat C gewonnen, wegen der ESPs auch
die Arduino-IDE und ein wenig C++...
Gruß aus Berlin
Michael
spess53 schrieb:> Ich komme seit über 20 Jahren ohne diese .def-Gedödel aus. Das kann man> vielleicht für irgendwelche Spielzeugprograme machen.
LOL. No comment.
> Wenn es größer> wird, so 10..15k Programmcode (nicht Quellcode), der noch aus zig> verschiedene Dateien besteht wird es unüberssichtlich oder ist mit> einem immensen Schreibaufwand verbunden.
10...15K Programmcode in Assembler ohne .def und .equ ?
Die hast du bestimmt noch nie geschrieben, ansonsten wusstest du was
10..15K Programmcode in Assembler bedeutet.
> Ich bin da mehr für eine gut strukturierte Programmierung.
Das verstehst sich von selbst und schliesst sich gegenseitig nicht aus.
Moby schrieb im Beitrag #5487063:
>> Während des Eintippens habe ich Zeit (nehme mir diese) zu>> beachten, was ich da mache.>> Interessanter Einwand...> Kann ich aber nicht ganz ernst nehmen :)
Kann ich bestätigen. Abtippen dauert länger, währenddessen läuft das
Gehirn mit und kann stückweise mit verarbeiten, was passiert. Daraus
folgt bei mir ein besseres Verständnis, was überhaupt los ist.
Klar kann ich auch 1000 Zeilen per Copy/Paste oder #include in meinen
Code einfügen, aber dann weiß ich trotzdem nicht, wie er funktioniert.
>> logische Fehler u.ä. fallen mir meist schon da auf>> Wie Du logische Fehler durchs Umbenennen von Registern und Ausschreiben> der Registerbits erkennst müsstest Du mal genauer erklären.
Inkonsistenzen fallen auf.
Bei Java-Programmierung macht Ausschreiben tatsächlich keinen Spaß,
dafür verbringt man die Hälfte der Zeit damit, irgendwelche Interfaces
aneinander anzupassen. Bei C oder Assembler ist das noch ein Vorteil.
Moby schrieb im Beitrag #5487293:
> Marc V. schrieb:>> 10...15K Programmcode in Assembler ohne .def und .equ ?>> Die hast du bestimmt noch nie geschrieben, ansonsten wusstest du was>> 10..15K Programmcode in Assembler bedeutet.>> Von equ war ja gar nicht die Rede. Def ist da jedenfalls kein Muss,> warum auch. Ich nehms sehr sparsam eigentlich nur für SREG und zur> Definition "schneller" Variablen im Registerspeicher her.
Nein, tatsächlich ist nichts ein Muss, man kann sich alles schwer
machen...
Aber die Bemerkung, dass man .def nur für 'irgendwelche
Spielzeugprograme' braucht, ist bestimmt nicht wahr.
Gerade bei Nichtspielzeugprogrammen benutzt man .def und wenn diese
Programme auch nur einigermassen kompliziert sind, wird mit .undef
alles noch übersichtlicher gehalten.
Beispiel:
Bei (fast) allen unseren Steuerprogrammen gibt es INPUT, BEARBEITUNG
und OUTPUT, ev. noch die ANZEIGE als Unterprogramme bzw. Klassen.
Da werden am Anfang Register mit .def umbenannt und am Ende mit .undef
wieder freigegeben. So ist r18 in INPUT InpReg, in OUTPUT OutReg usw.
Manche Register dürfen natürlich nicht verschmutzt werden, dessen Namen
bleiben dann auch durchgehend unverändert.
Und jeder, der irgendwann etwas längeres als 1K in Assembler
geschrieben hat, wird wissen warum.
> P. S. sitze auch gerade an einem 13K Projekt
Und es handelt sich um ?
Marc V. schrieb:> Da werden am Anfang Register mit .def umbenannt und am Ende mit .undef> wieder freigegeben.
Hallo, ich muss diese Ausgabe noch gerade rücken, umbenannt wird hier
nichts, sondern ein Namenersatz definiert und später wieder aufgehoben.
Like C #define und #undef
Hi
>Die hast du bestimmt noch nie geschrieben, ansonsten wusstest du was> 10..15K Programmcode in Assembler bedeutet.
Ob du das glaubst ist mir persönlich egal.
Das sind Anlagen-/Verstärkersteuerungen für Vibrationstestanlagen. Auf
größeren Anlagen mit bis zu vier Shakern werden bei der ESA komplette
Satelliten getestet.
MfG Spess
spess53 schrieb:>>Die hast du bestimmt noch nie geschrieben, ansonsten wusstest du was>> 10..15K Programmcode in Assembler bedeutet.>> Ob du das glaubst ist mir persönlich egal.
Ob ich das glaube oder nicht ist auf jeden Fall egal.
Es ist nur unlogisch, dass ausgerechnet kleine Programme .def benutzen
und grosse nicht.
Und was die tatsächliche Programmgröße betrifft:
Wir hatten letztes Jahr 29K Assemblerprogramm, allerdings nur knapp
4K Code, dafür aber 25K von Computer generierten Tabellen, das ist
natürlich nicht dasselbe wie durchgehend 29K Code...
Hi
>Und was die tatsächliche Programmgröße betrifft:> Wir hatten letztes Jahr 29K Assemblerprogramm, allerdings nur knapp> 4K Code, dafür aber 25K von Computer generierten Tabellen, das ist> natürlich nicht dasselbe wie durchgehend 29K Code...
Das ist mir klar. Aber ich meine reinen Programmcode
Aus einem der Listfiles:
ATmega1281 memory use summary [bytes]:
Segment Begin End Code Data Used Size Use%
---------------------------------------------------------------
[.cseg] 0x000000 0x00ed56 10042 50682 60724 131072 46.3%
[.dseg] 0x000200 0x00083c 0 1596 1596 8192 19.5%
[.eseg] 0x000010 0x00001b 0 11 11 4096 0.3%
Assembly complete, 0 errors, 0 warnings
Da kannst du sehen, das noch über 50k an Daten (für das Grafikdisplay)
vorhanden sind.
Und ich weiß was 10..15 K in Assembler bedeuten
Kleines Beispiel:
Re: Zeigt her Eure Kunstwerke !
MfG Spess
Zu Assemblerzeiten hab ich immer die originalen Registernamen benutzt.
Meine eigene Konvention war Parameter an Routine in r20, zurueck in r21.
Schleifen in r22 (innere) und r23 (aussere). Lokal werden diese aber
auch anders benutzt. Und das ist genau der Grund warum ich keine anderen
Namen vergebe. Zwei verschiedene Namen fuer das gleiche Register zu
verwenden ist gefaehrlich (Aliasing). Aber einen Bezeichner
zweckzuentfremden leitet erst recht auf die falsche Faehrte.
Und zuletzt: Ein Register moechte ich auf den ersten Blick als solches
erkennen.
PS: r10 enthaellt immer Wert 0 und r11 immer den Wert 1.
spess53 schrieb:> Und ich weiß was 10..15 K in Assembler bedeuten
Glaube ich. Aber dein Beitrag klang irgendwie herablassend, deswegen
schrieb ich das...
Assemblierer schrieb:> Schleifen in r22 (innere) und r23 (aussere). Lokal werden diese aber> auch anders benutzt. Und das ist genau der Grund warum ich keine anderen> Namen vergebe. Zwei verschiedene Namen fuer das gleiche Register zu> verwenden ist gefaehrlich (Aliasing). Aber einen Bezeichner> zweckzuentfremden leitet erst recht auf die falsche Faehrte.
Gerade umgekehrt.
Bei Assemblerprogrammen weiss ich nach spätestens 2-3 Wochen nicht mehr
warum ich etwas so und nicht anders geschrieben habe. Deswegen sind
meine Programme mindestens 70:30 - 70% Code, 30% Komentare.
Sinnvolle Namen für benutzte Register zu vergeben kann auch unheimlich
helfen. Man sollte sich schon bei einigermassen komplizierten
Programmen sowieso eine Tabelle mit benutzten Registern und Variablen
erstellen - wie, wo und warum diese benutzt und verändert werden,
welche Register Tabu sind usw.
> Und zuletzt: Ein Register moechte ich auf den ersten Blick als solches> erkennen.
Ich hänge meistens Reg hinten dran, z.B. FlagReg, ModeReg, SysReg usw.
Und wie schon gesagt,
1
sbrsr19,5
sagt mir in einem Unterprogramm von 1K nicht viel, aber