Forum: Mikrocontroller und Digitale Elektronik Verständnisfrage zu Assembler bei PIC und ATMEL


von Jürgen K. (geduld)


Lesenswert?

Ich beschäftige mich seit Längeren bereits mit ATtiny85, ATMega328 und 
jetzt auch mit PIC. Angefangen habe ich mit den Lernbausätzen von 
Franzis. Interessante Anregungen habe ich als Anfänger unter anderen bei 
BKainka bzw. seinem Elektronik-Labor gefunden. Er hat wohl auch den 
Lernbausatz ATtiny85 für Franzis entwickelt.

Inzwischen sind mir die Vorteile/Unterschiede zwischen der 
Programmierung via Bootloader oder mittels Programmer klar.

Da ich bisher nur Hochsprachen wie Bascom oder C benutzt habe, war 
Assembler erst einmal zweitrangig. Allerdings läuft im Mikrocontroller 
natürlich in Maschinensprache übersetzter Code, egal ob aus Bascom oder 
C.

Wenn ich nun mit einem Programmer (STK500 bei ATMEL oder PICKit bei PIC) 
einen Controller komplett auslese, welcher mittels Bootloader über die 
Serielle Schnittstelle/USB programmiert wurde, finde ich natürlich im 
untersten Speicherbereich den Bootloader und z.B. bei PIC ab 0400hex das 
eigentliche Programm. Diesen Inhalt ab 0400hex könnte ich natürlich 
abspeichern und wieder in einen jungfreulichen Controller laden. 
(Configbits bzw. Fuses nicht vergessen)
Will ich jetzt allerdings den Bootloader weglassen, so könnte ich doch 
nur den eigentlichen Maschinencode des Anwendungsprogrammes speichern, 
der ab 0400hex zu finden ist. Das spart Speicherplatz und reicht für 
fertige Geräte ja völlig aus, welche nur einmal programmiert werden 
sollen.

Bei diesem Gedankengang kamen mir dann folgende Fragen:

1. Gibt es bei PIC/ATMEL im Assembler auch absolute 
Sprünge/Sprungadressen?

2. Kann ich den eigentlichen Programmcode ab 0400hex einfach an eine 
andere Adresse verschieben?

Falls Frage 1 mit "Ja" zu beantworten ist, dann sollte Frage 2 bzw. das 
Verschieben nicht möglich sein. Oder sorgt der Compiler bei diesen 
Controllern (ATtiny85, ATMega328, PIC18F23K22) dafür, dass es keine 
absoluten Sprünge gibt?

Sorry für die etwas akademische Frage, aber für mein Verständnis 
durchaus wichtig.

von Oliver S. (oliverso)


Lesenswert?

Die AVRs haben absolute Sprünge (jmp) bei den Modellen, bei denen der 
relative Sprungbefehl (rjmp) nicht für den gesamten Flash ausreicht.

guggst du Datenblatt.

Oliver

: Bearbeitet durch User
von S. L. (sldt)


Lesenswert?

Wobei ich mich gerade frage, welchen Sinn die Fragestellung für Atmel 
ergibt: bei den genannten Typen (Klasse 'AVRe') befindet sich der 
Bootloader doch am Ende des Flash.

PS:
Auch dies verstehe ich nicht:
> Das spart Speicherplatz ...
Welchen Vorteil soll das haben?

: Bearbeitet durch User
von Jürgen K. (geduld)


Lesenswert?

Danke für den Hinweis. Das würde bedeuten, dass meine Gedanken nur bei 
den PICs zutreffen würden, da dort der Bootloader vorn (0 - 0400hex) 
liegt. Bei den Atmels würde sich ja nichts an den Adressen verändern, 
wenn ich nur den Maschinencode des eigentlichen Programmes abspeichere. 
Insofern bezieht sich meine Frage dann nur auf die PICs!

von Jens M. (schuchkleisser)


Lesenswert?

Jürgen K. schrieb:
> Das spart Speicherplatz

Du bekommst kein Geld zurück für nicht gebrauchtes Flash.
Und auf der Festplatte sind es nur wenige hundert Bytes weniger, 
Flashzeit wird ebenfalls nur marginal reduziert.

Jürgen K. schrieb:
> 1. Gibt es bei PIC/ATMEL im Assembler auch absolute
> Sprünge/Sprungadressen?

Na klar.
Liegt am Programmierer und Compiler ob das passiert, aber möglich sind 
sowohl absolute als auch relative Sprünge.

Jürgen K. schrieb:
> 2. Kann ich den eigentlichen Programmcode ab 0400hex einfach an eine
> andere Adresse verschieben?

In der Regel nicht.
Es sei denn du schreibst ihn als Quellcode um. Eben als "relativ", oder 
an eine andere Startsadresse.

Plus:
Es kann sein, das der Bootloader Hardwarehürden umschifft in dem er 
nicht das programmiert was du meinst, will sagen: er patcht das Programm 
um, damit das normalerweise nicht "Bootloader-Aware" erstellte Programm 
"mit" läuft.
Auslesen und neu Programmieren geht dann nicht, weil im zweiten Teil der 
Bootloader fehlt, der z.B. Sprungadressen benutzt.

Aber warum sich das antun?
Du kannst mit jedem Compiler oder Assembler einfach ein Programm 
erstellen und die Hexdatei z.B. via avrdude auch ohne Bootloader 
programmieren, und das tut dann auch, ohne die Sicherheitslücke 
Bootloader und ohne Frickelei mit Auslesen und umpatchen.

von Jens M. (schuchkleisser)


Lesenswert?

Jürgen K. schrieb:
> Das würde bedeuten, dass meine Gedanken nur bei
> den PICs zutreffen würden, da dort der Bootloader vorn (0 - 0400hex)
> liegt.

Nicht zwangsläufig.
Je nach Chip ist der Bootloader oben, aber der Resetvektor wird 
umgepatcht.
Dadurch ist der Bootloader "unsichtbar", das Programm kann mit und ohne 
laufen ohne das es zwei Versionen gibt.
Bei deinem "BL vorne" musst du das Programm entsprechend übersetzen, was 
Fehleranfällig ist.

Bei AVRs stimmen evtl. die Fuses nicht mit/ohne BL. Zum Glück haben die 
PICs das nicht, die Config steht mit im Hexfile, wenn der Programmierer 
kein Volldepp ist.

von Peter D. (peda)


Lesenswert?

Bei den klassischen ATtiny/ATmega muß der Compiler nicht wissen, ob ein 
Bootloader benutzt wird oder nicht. Die Applikation startet immer an 
0x0000.

Bei den neuen AVRs muß man die Applikation verschieben, d.h. der Linker 
muß die Adresse der Applikation kennen. Ansonsten zeigen absolute 
Sprünge und Calls, die Interruptvektoren sowie konstante Daten im Flash 
in den Wald.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jürgen K. schrieb:
> 1. Gibt es bei PIC/ATMEL im Assembler auch absolute
> Sprünge/Sprungadressen?

Selbst wenn keine absoluten Sprünge / Calls verwendet werden bedeutet 
das noch lange nicht, dass der Code relokatibel ist.

Zum Beispiel ein indirekter Funktionsaufruf:  Das Problem ist die 
"Berechnung" der Funktionsadresse; die besteht aus dem Nehmen der 
absoluten Adresse der Funktion.

Dito für indirekte Sprünge, etwa in if/else Dispatch-Tables, Computed 
Goto, Nonlocal Goto (Exceptions), etc.

Eine Möglichkeit, relokatiblen Code zu realisieren ist z.B. ein ELF 
Loader auf dem Device, das zur Load-Zeit entsprechende RELOCs fixt.  Der 
entstehende Code ist dann zwar nicht mehr relokatibel, spielt aber keine 
Rolle, weil bei erneutem Laden die Loader den Code wieder auf die 
gewählte Adresse anpasst.

Für AVR wüsste ich nicht, dass jemand mal auch nur versucht hätte, einen 
ELF-Loader zu schreiben -- wäre auch nicht sonderlich sinnvoll, weil die 
Tools keine entsprechenden RELOCs erzeugen.

Dann gibt es noch die Möglichkeit, echt relokatiblen Code zu erzeugen. 
Aber auch das würde Erweiterungen der Tools erfordern, etwa wie die 
Adresse eines Labels zu berechnen ist.  Weiteres Problem ist, dass es 
keine absoluten Sprünge / Calls geben kann, d.h. man braucht ein 
Branch-Relaxing im Linker, was zB für AVR nicht umsetzbar ist.

: Bearbeitet durch User
von Axel S. (a-za-z0-9)


Lesenswert?

Johann L. schrieb:
> Eine Möglichkeit, relokatiblen Code zu realisieren ist z.B. ein ELF
> Loader auf dem Device, das zur Load-Zeit entsprechende RELOCs fixt.

Um Himmels willen! Darf ich nochmal an das Subject erinnern? In 
Assembler kann man selbstverständlich relokatiblen Code schreiben. Die 
Frage ist, ob man das überhaupt will (bzw. braucht). Denn auch wenn man 
in Assembler programmiert, hat man ja den Quellcode und es kostet nur 
ein paar Klicks um den für eine andere Adresse zu übersetzen.

Aber darum ging es dem TE ja auch nicht. Ihm geht es um die Behandlung 
des Maschinencodes. Und der ist im Normalfall weder relokatibel noch ist 
garantiert, daß er ohne den Bootloader überhaupt tut. Kommt auf den 
Bootloader und auf die µC-Architektur an. Speziell bei Architekturen 
ohne eigenen Bootloader-Support werden da Vektoren umgebogen und andere 
Verrenkungen gemacht.

Abgesehen davon verstehe ich den Sinn hinter der Anfrage nicht. Wenn man 
ein Programm hat, das mit dem Bootloader tut und offensichtlich auch in 
den Flash paßt - warum zur Hölle würde man da den Bootloader 
nachträglich weglassen wollen?

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Also normalerweise ist der Assembler fit genug, Programm-Adressen 
passend hinzubiegen. Im Flash ändern sich auch keine Adressen, oder 
möchtest Du einen Virus für AVR/PIC-Controller schreiben?

Übrigens kann ich Dir nicht empfehlen, die PICs in Assembler zu 
programmieren. Ich bin genau deswegen zu den AVRs gewechselt, die einen 
deutlich kompletteren Registersatz und Assembler-Instructions haben, 
obwohl ich mit PICs angefangen habe.

von Jens M. (schuchkleisser)


Lesenswert?

Axel S. schrieb:
> warum zur Hölle würde man da den Bootloader
> nachträglich weglassen wollen?

- Kostet Startzeit
- ermöglicht Fremdflashen
- Ermöglicht evtl. auslesen
- Erfordert u.U. fehlenden Codeschutz

Ben B. schrieb:
> Übrigens kann ich Dir nicht empfehlen, die PICs in Assembler zu
> programmieren.

PIC-Assembler ist wesentlich einfacher als der des AVR zu verstehen, und 
wesentlich vorhersehbarer.
Plus es entfällt dieser ganze Kram mit den Registern, alle Befehle sind 
gleich lang usw. usf.
Und, das allerwichtigste: keine Fuses, die man manuell transportieren 
muss und bei denen jeder Programmer ein anderes Interface hat: Config in 
den Code, die Bytes landen im Hex, eine Datei in der alles steht, 
fertig.

Aber: es ist kein "besser", es ist "anders", denn die beiden 
Architekturen sind wesenlich unterschiedlich.
Das ist wie Mac und Windows. Irgendwie gleich, aber im Detail halt doch 
ganz anders.
Je nachdem welche anderen Architekturen man kennt kommt man dann mit PIC 
oder AVR besser klar, wenn man sich die Qual des Assemblers noch antun 
will.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Jens M. schrieb:
> PIC-Assembler ist wesentlich einfacher als der des AVR zu verstehen, und
> wesentlich vorhersehbarer.

Aber erst ab PIC18 einigermaßen brauchbar.
Die PIC12/16 mit Hardwarestack, segmentiertem RAM und Flash, ständiger 
Bankumschaltung, RETLW, DECFSZ, PCLATH sind einfach nur gruselig.

Bezüglich vorhersehbar. Ich möchte nicht wissen, wieviel Entwickler da 
schon geflucht haben, weil nach Einfügen eines Befehls plötzlich nichts 
mehr ging, weil die Flashadresse einen 8Bit Überlauf hatte.

: Bearbeitet durch User
von Rainer W. (rawi)


Lesenswert?

Jens M. schrieb:
> Auslesen und neu Programmieren geht dann nicht, weil im zweiten Teil der
> Bootloader fehlt, der z.B. Sprungadressen benutzt.

Das stimmt so nicht. Auslesen und Programmieren kann man auch direkt 
über die Programmierschnittstelle des Prozessors.
Ein Bootloader macht das Einspielen der Anwendersoftware zwar sehr 
bequem, ist aber nicht unbedingt erforderlich. Wenn es ohne Bootloader 
nicht funktionieren würde, hätte man ein Henne-Ei-Problem beim 
Aufspielen des Bootloaders.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Also ich bin mit beiden Architekturen gut mit Assembler klargekommen, 
nur daß ich das beim AVR wie gesagt durch den großen Register- und 
Befehlssatz wesentlich komfortabler fand.

von Axel S. (a-za-z0-9)


Lesenswert?

Jens M. schrieb:
> Axel S. schrieb:
>> warum zur Hölle würde man da den Bootloader
>> nachträglich weglassen wollen?
>
> - Kostet Startzeit

Wie oft startet man eine µC-Anwendung?

> - ermöglicht Fremdflashen
> - Ermöglicht evtl. auslesen

Das Problem hat man immer und es wird durch setzen der Fuses (zumindest 
auf dem AVR, heißt bei PIC vermutlich anders) gelöst.

> - Erfordert u.U. fehlenden Codeschutz

Dieser Satz kein Sinn.

Bei selbstentwickeltem Code hat man zudem immer den Quellcode. Wenn man 
den Bootloader nicht haben mag, übersetzt man den halt nochmal ohne 
Bootloader. Da frickelt man nicht mit dem Maschinencode rum.

> Ben B. schrieb:
>> Übrigens kann ich Dir nicht empfehlen, die PICs in Assembler zu
>> programmieren.
>
> PIC-Assembler ist wesentlich einfacher als der des AVR zu verstehen, und
> wesentlich vorhersehbarer.

Nein. Weniger Befehle sind nicht besser. Wenn das so wäre, wären ja auch 
Whitespace oder Brainfuck beliebte Programmiersprachen. PIC Assembler 
ist der sicherste Weg, schnell verrückt zu werden. So wie Beulenpest und 
Lepra gleichzeitig.

Zumindest die kleinen PICs bis PIC16. PIC18 geht einigermaßen. PIC24 ist 
eine reguläre µC-Architektur. Und PIC32 ist eigentlich MIPS.

Mit dieser krampfhaften Umbenennerei von Architekturen tut sich 
Microchip IMHO keinen Gefallen. Wer einmal mit PIC16 konfrontiert war 
und nicht das Privileg hatte, den Compiler benutzen zu können (es gab 
nur einen und der kostete Geld) macht um alles was PIC heißt einen 
großen Bogen.

von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> PIC-Assembler ist wesentlich einfacher als der des AVR zu verstehen

Vorausgesetzt vielleicht, es ist die erste Programmierumgebung, der man 
ausgesetzt ist, und man kennt keine andere :).

Die archaische Mnemotechnik erinnert an Rechner aus grauer Vorzeit und 
weicht von den mittlerweile gängigen Architekturen deutlich ab.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Axel S. schrieb:
> Mit dieser krampfhaften Umbenennerei von Architekturen

Der erste PIC ist von 1976. Damals waren bei den verschiedenen 
Architekturen die Namen und die Syntax von Befehlen noch Kraut und 
Rüben. Allmählich vereinheitlichte sich das jedoch, auch erkennbar an 
der Migration vom 8080 Stil zum Z80 Stil. Bei den PICs ist man einfach 
beim archaischen Schema geblieben, weshalb das heute deutlich aus der 
Zeit gefallen wirkt.

: Bearbeitet durch User
von Jens M. (schuchkleisser)


Lesenswert?

Peter D. schrieb:
> Die PIC12/16 mit Hardwarestack, segmentiertem RAM und Flash, ständiger
> Bankumschaltung, RETLW, DECFSZ, PCLATH sind einfach nur gruselig.

Och, geht.
Die Register bei AVR die man nicht benutzen darf weil "das muss immer 0 
sein" und so finde ich (neben den Fuses) auch absolute 
Designfehlentscheidungen.
Wenn man's richtig macht sind PIC16 recht einfach nzu benutzen.
PIC12 ist noch wesentlich einfacher, weil das ja auch nur wenig Flash 
hat.
Bei den aufgeblasenen Typen sollte man dann wirklich schon einen 18er 
nehmen, aber die sind in den letzten Generationen dann auch wirklich 
unübersichtlich geworden.
Dreistellige PIC16F sind aber leicht zu programmieren.

Peter D. schrieb:
> Bezüglich vorhersehbar. Ich möchte nicht wissen, wieviel Entwickler da
> schon geflucht haben, weil nach Einfügen eines Befehls plötzlich nichts
> mehr ging, weil die Flashadresse einen 8Bit Überlauf hatte.

Jaha, das ist eine gern gefundene Falle.
Ich meinte aber z.B. Taktzeiten und Speicherbedarf. Ein Befehl ist ein 
Wort ist ein Takt, außer bei Sprüngen.
Wenn der Assembler vom Programmierer ausgetrickst wird und Flashbanks 
auf einmal ein Problem werden, ist das aber Layer 8.

Rainer W. schrieb:
> Das stimmt so nicht. Auslesen und Programmieren kann man auch direkt
> über die Programmierschnittstelle des Prozessors.
> Ein Bootloader macht das Einspielen der Anwendersoftware zwar sehr
> bequem, ist aber nicht unbedingt erforderlich.

Das stimmt sehr wohl.
Es gibt bei PICs nur einen Resetvektor, und der ist nicht wie bei AVRs 
via Configbit/Fuse umsetzbar.
Da muss (!) also ein Hinweis auf den Bootloader rein, und der wird einen 
Teufel tun diese Stelle mit dem zu überschreiben was er vom PC bekommt, 
nämlich den Start des Anwenderprogramms: dieser wird in den Bootloader 
selbst geschrieben, an die "Bootloader ist fertig"-Stelle.
Wenn du dann das Programm "mit BL" ausliest, steht da der Start in den 
BL drin. Schreibst du das "ohne", fehlt der Resetvektor und der 
Programmstartvektor aus dem BL.
Ergo: mit BL auslesen, wegeditieren und neu flashen knallt.

Axel S. schrieb:
> Wie oft startet man eine µC-Anwendung?

Ja nu, manche Leute wundern sich wenn $Gerät nach dem Einschalten 
erstmal 3 Sekunden braucht bis es reagiert. $Entwickler weiß es, $Kunde 
ist genervt.

Axel S. schrieb:
> Das Problem hat man immer und es wird durch setzen der Fuses

Ja eben. Ein Codeprotect kann durch den Bootloader verunmöglicht sein, 
und das will man u.U. nicht kommerziell ausliefern.
Kann auch sein das es geht, aber das wissen wir nicht.

Axel S. schrieb:
> Dieser Satz kein Sinn.

Dieser Satz kein Verb. ;)
Lies nochmal im Zusammenhang meine Antwort drei Zeilen höher.

Axel S. schrieb:
> Wenn man
> den Bootloader nicht haben mag, übersetzt man den halt nochmal ohne
> Bootloader.

Joa, das ist normal so. OP ist aber auf einem anderen Pfad unterwegs, 
warum auch immer.

Axel S. schrieb:
> PIC Assembler
> ist der sicherste Weg, schnell verrückt zu werden.

Och, ich komm seit ~30 Jahren bestens auf PIC Asm klar. Leicht und 
einfach zu verstehen, logisch nachzuvollziehen, überschaubar in der 
Fehlersuche.
Ja, gibt bequemeres, aber viele kleine Hilfsprojekte habe ich über die 
Jahre mal eben auf einen PIC12F675 gehackt, keine 100 Zeilen und ein 
leichteres Leben.
Mittlerweile mach ich es aber mit Arduinos, und  das nur aus dem Grund 
das man da via USB live einen Update fahren kann.
Wenn ich nach 10 Jahren einen Update auf einer meiner Basteleien fahre 
und aus einem 100-Zeilen-PIC-Programm (also auch ~100 Words 
Speicherbedarf) werden 100 Zeilen C, aber mit 3kB Speicherbedarf, dann 
tränen mir die Augen. Aber man bekommt für unbenutztes Flash ja kein 
Geld zurück...

Axel S. schrieb:
> PIC24 ist eine reguläre µC-Architektur. Und PIC32 ist eigentlich MIPS.

Beides keine PICs, nur mit dem Namensschild drauf. Jeder 
PIC-Programmierer hasst die, und kommt auch nicht damit klar, weil die 
ganzen Strukturen vollkommen un-PIC-ig sind.
Muss man in C machen und dann könnte man auch ARM nehmen.

(prx) A. K. schrieb:
> Die archaische Mnemotechnik erinnert an Rechner aus grauer Vorzeit und
> weicht von den mittlerweile gängigen Architekturen deutlich ab.

Ja, PICs waren ja auch eigentlich ganz anders geplant. Etwa sowas wie 
der Blitter im Amiga.
Dann kam ein BWLer und hat gesagt "das könnte man doch auch auf dem 
Markt verkaufen?!"

von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> Die Register bei AVR die man nicht benutzen darf weil "das muss immer 0
> sein"

Ich kenne das nur als Konvention des Compilers, nicht in der Architektur 
der Hardware.

von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> Dann kam ein BWLer und hat gesagt "das könnte man doch auch auf dem
> Markt verkaufen?!"

Tja, was soll man dazu sagen: Der BWLer hatte recht! :)

von Jens M. (schuchkleisser)


Lesenswert?

(prx) A. K. schrieb:
> Ich kenne das nur als Konvention des Compilers, nicht in der Architektur
> der Hardware.

Das weiß ich nicht.
Ich habe mal ein paar Versuche mit AVR-Asm gemacht und bin darüber 
gestolpert, aber eine Erklärung dafür habe ich nie gesehen.
Zugegeben aber auch nicht direkt gesucht.
Ich hab ein bissle C eingegeben, compiliert, mir den Code angesehen, 
habe geweint wie viel Kram aus den einfachsten Befehlen erzeugt wird und 
hab wie vom PIC gewohnt das Programm mit nur dem nötigsten 
zusammengestöpselt.
Klein, einfach, schnell, aber unheimlich unbequem zu schreiben, weil man 
so wahnsinnig viele Befehle und Adressierungsarten kennen muss, nix für 
Anfänger.

: Bearbeitet durch User
von Axel S. (a-za-z0-9)


Lesenswert?

(prx) A. K. schrieb:
> Axel S. schrieb:
>> Mit dieser krampfhaften Umbenennerei von Architekturen
>
> Der erste PIC ist von 1976. Damals waren bei den verschiedenen
> Architekturen die Namen und die Syntax von Befehlen noch Kraut und
> Rüben.

Ja, mag sein. Aber andere Hersteller hatten das doch deutlich besser 
drauf. Der Motorola 6800 ist sogar noch älter als PIC (von 1974) und da 
macht man sich bei der Programmierung nicht so einen Knoten ins Hirn.

> Allmählich vereinheitlichte sich das jedoch, auch erkennbar an
> der Migration vom 8080 Stil zum Z80 Stil.

Vielleicht doch die Gnade der späten Geburt. Mein erster µP war der Z80 
(als U880), später hab ich mich eingehend noch mit dem Z8 (sehr elegant) 
und dann mit dem 6502 (eigentlich 6510, im C64) auseinandergesetzt. Und 
der letztere ist ja im Prinzip eine leicht abgespeckte Variante des 
6800. Man sieht natürlich die Evolution zum Z80. Viel mehr Register, 
Stack frei im RAM positionierbar, mehrere 16-Bit Indexregister, usw. 
Aber der PIC wirkt auch im Vergleich zum 6502 wie Steinzeit.

von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> Das weiß ich nicht.

Aber ich. Bei RISC Architekturen ist es recht verbreitet, dass eine 
bestimmte Registernummer für den Wert 0 steht und ein reingeschriebener 
Wert verloren geht. Das vereinfacht die Implementierung. Meist ist das 
naheliegenderweise R0, aber in RISC-V ist es R31.

GCC für AVR bildet das einfach nach. Befehle mit Konstante gibts ja nur 
für R16-R31 und der Wert 0 ist einfach zu wichtig.

: Bearbeitet durch User
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

> Ich hab ein bissle C eingegeben, compiliert, mir den Code
> angesehen, habe geweint wie viel Kram aus den einfachsten
> Befehlen erzeugt wird und hab wie vom PIC gewohnt das
> Programm mit nur dem nötigsten zusammengestöpselt.
Das ist aber kein PIC- oder AVR-Problem, sondern das erlebt man bei 
allen Hochsprachen, wenn man sich das Programm nach dem Compilieren in 
Assembler anschaut. Gerade das macht Assembler ja so interessant, man 
bekommt sehr hohe Geschwindigkeit mit wenig Speicherbedarf.

von Axel S. (a-za-z0-9)


Lesenswert?

>(prx) A. K. schrieb:
>> Jens M. schrieb:
>>> Die Register bei AVR die man nicht benutzen darf weil "das muss immer 0
>>> sein"
>>
>> Ich kenne das nur als Konvention des Compilers, nicht in der Architektur
>> der Hardware.
>
> Ich habe mal ein paar Versuche mit AVR-Asm gemacht und bin darüber
> gestolpert, aber eine Erklärung dafür habe ich nie gesehen.

Wie gesagt, das ist eine Konvention(!) des C-Compilers. In Assembler 
gibt es diese Einschränkung nicht. Nur wenn man C und Assembler mischen 
will. Und sogar dann kann man das Zero-Register benutzen, solange man 
nicht in den C-Code (vom C-Compiler generierten Maschinencode) 
zurückkehrt. Und sei es in Form einer ISR. Aber eigentlich stellt sich 
das Problem nicht. Man hat ja 32 Register. Sind dann halt nur noch 31, 
wenn man das Zero-Register ausläßt.

von (prx) A. K. (prx)


Lesenswert?

Axel S. schrieb:
> Z8 (sehr elegant)

Aber für eng begrenzten Adressraum optimiert. Bei mehr als den grob 200 
Bytes RAM war Schluss mit Lustig, und die Nachfolgearchitektur liess an 
Übersichtlichkeit schwer zu wünschen übrig.

Dem 8051/52 ging es genauso. Sobald der ursprüngliche Adressraum 
überschritten wurde, wurde es hässlich. Damals peilte man solche Systeme 
für wenige Jahre, um danach eine neue Architektur für mehr Bedarf zu 
bringen. Das war MCS-96 - sehr übersichtlich für Asm-Programmierer, aber 
kennt die heute noch jemand?

: Bearbeitet durch User
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

> Befehle mit Konstante gibts ja nur
> für R16-R31 und der Wert 0 ist einfach zu wichtig.
Eine der wenigen Einschränkungen beim AVR.. aber immerhin bekommt man 
satte 32 Register, davon 16 general purpose und die oberen 6 davon als 
16-Bit-Register nutzbar. Soviel Komfort hat man beim PIC16F bei weitem 
nicht. Die großen ATMegas können 131 AVR-Instructions (ATMega1284), der 
PIC16F677 kann 35. Das will man doch nicht ...

von (prx) A. K. (prx)


Lesenswert?

Ben B. schrieb:
> wenn man sich das Programm nach dem Compilieren in
> Assembler anschaut

Sich den Output eines C Compilers für 8-Bit PICs anzuschauen, ist ein 
Abenteuer der besonderen Art.

von (prx) A. K. (prx)


Lesenswert?

Ben B. schrieb:
> Das will man doch nicht

Befehle zu zählen ist eine brotlose Kunst. Die 8080 hat so gesehen mehr 
Befehle als die Z80, weil bei 8080 jeder Opcode einen eigenen Namen hat, 
während Z80 etliche zusammenfasst. Und MaxQ2000 hat bei geeigneter 
Zählweise nur einen einzigen Befehl mit zwei Adressierungsarten. :)
  move reg2 to reg1
  move constant to reg1

: Bearbeitet durch User
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Ich weiß was Du meinst, aber bei einem Stand von 131:35 ist schon recht 
deutlich, welcher Kern der benutzerfreundlichere ist. Zumindest in 
Assembler, einem Compiler ist sowas egal.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Dann versuche mal, den MaxQ2000 in Assembler zu programmieren. Das ist 
selbst mit aufgedröselter Mnemotechnik schwierig, die aus einem Opcode 
zig Befehle macht. :)

von Jens M. (schuchkleisser)


Lesenswert?

Ben B. schrieb:
> Soviel Komfort hat man beim PIC16F bei weitem
> nicht.

Hab ich nie vermisst.
Was mich stört sind das man ab und zu irgendwie verkehrt rum in den 
Befehlen ist, aber Register hab ich nie benötigt.

Ben B. schrieb:
> Das will man doch nicht

Man braucht nicht mehr.
Der AVR kann Dinge mit einem Befehl, der dann zwei Takte braucht, was 
der PIC in zwei Befehlen machen muss was auch zwei Takte braucht.

(prx) A. K. schrieb:
> Sich den Output eines C Compilers für 8-Bit PICs anzuschauen, ist ein
> Abenteuer der besonderen Art.

Arduino ist auch gut: Alle Variablen auf den Softwarenachgebildetenen 
Stack, call in die Funktion, Alle Variablen wieder runter in die 
Register, Rechnung ausführen, alle Ergebnise wieder zurück auf den 
Stack, return, alle Ergbnisse wieder runter vom Stack, weiterarbeiten.
Arduino auf einer Maschine mit FRAM würde das auch in 3 Stunden 
kaputtschreiben.

Ben B. schrieb:
> bei einem Stand von 131:35 ist schon recht
> deutlich, welcher Kern der benutzerfreundlichere ist.

Der einfacher merkbare ;)

Bitte diesen Thread nicht in eine Linux/Windows-Diskussion, äh, 
PIC/AVR-Diskussion abgleiten lassen. ;)
Die Antwort auf OPs Frage ist in beiden Architekturen "kommt drauf an, 
aber wahrscheinlich nein".

von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> Bitte diesen Thread nicht in eine Linux/Windows-Diskussion, äh,
> PIC/AVR-Diskussion abgleiten lassen. ;)

Der hat eigentlich schon so angefangen. :)

von Peter D. (peda)


Lesenswert?

Jens M. schrieb:
> Ja eben. Ein Codeprotect kann durch den Bootloader verunmöglicht sein,
> und das will man u.U. nicht kommerziell ausliefern.
> Kann auch sein das es geht, aber das wissen wir nicht.

Bei den AVRs hat man getrennte Lockbits für Programmer und Bootloader.
Man kann also den Programmer aussperren und nur noch das Schreiben für 
den Bootloader erlauben. Und wenn der Bootloader kein Rücklesekommando 
unterstützt, ist die Applikation auslesegeschützt.

von Peter D. (peda)


Lesenswert?

Jens M. schrieb:
> Ich hab ein bissle C eingegeben, compiliert, mir den Code angesehen,
> habe geweint wie viel Kram aus den einfachsten Befehlen erzeugt wird und
> hab wie vom PIC gewohnt das Programm mit nur dem nötigsten
> zusammengestöpselt.

Dann bist Du in die Falle des zu kleinen Code getappt.
C hat erstmal einen gewissen Overhead gegenüber Assembler. Aber je mehr 
zu tun ist, umso besser ist der Compiler, bis er dann sogar gewinnt. Der 
kennt viele Tricks, z.B. Register Renaming, Common subexpression 
elimination, wo man sich zu Fuß in Assembler einen abbrechen würde.

von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> Ich hab ein bissle C eingegeben, compiliert, mir den Code angesehen,
> habe geweint wie viel Kram aus den einfachsten Befehlen erzeugt wird und
> hab wie vom PIC gewohnt das Programm mit nur dem nötigsten
> zusammengestöpselt.

Normalerweise liegen lokale Daten von C Funktionen auf dem Stack. 
Vorausgesetzt das geht überhaupt. Alte PICs können das nicht und auch 
die PIC18 können es erst ab einer Revision der Architektur 
einigermassen.

Bei AVR ist das an sich kein Problem, nur muss man dazu am Stackpointer 
rumspielen, und an dieser Stelle hat AVR Mist gebaut und dieser Mist 
stinkt bis heute.

Andere sagen, derjenige Compiler-Hersteller, mit dem Atmel zwecks 
besserer Nutzbarkeit in C zusammenarbeitete, habe AVR verarscht, um 
einen Vorteil gegenüber dem Rest der Welt zu haben. Denn deren Compiler 
macht das mit zwei getrennten Stacks. Einen für Return-Adressen und 
einen für lokale Daten. Das geht besser.

GCC hingegen macht es klassisch und als Folge davon kann der Wasserkopf 
am Anfang und Ende von Funktionen ziemlich hässlich aussehen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jens M. schrieb:
> Und, das allerwichtigste: keine Fuses, die man manuell transportieren
> muss und bei denen jeder Programmer ein anderes Interface hat: Config in
> den Code, die Bytes landen im Hex, eine Datei in der alles steht,
> fertig.

Nur nebenbei: kann man beim AVR genauso haben. Aber dann üblicherweise 
nicht im Hex-File, sondern gleich im ELF-File. Intel-Hex braucht dort 
eigentlich niemand mehr (trotzdem hält es sich sehr hartnäckig).

Ist halt die Frage, ob man auch wirklich bei jeder Iteration die Fuses 
neu flashen möchte …

von Jens M. (schuchkleisser)


Lesenswert?

Peter D. schrieb:
> Und wenn der Bootloader kein Rücklesekommando
> unterstützt, ist die Applikation auslesegeschützt.

Könnte man theoretisch über den BL ein 2. Programm in den AVR laden, das 
sich dann via UART selbst ausliest? ;)

Jörg W. schrieb:
> Nur nebenbei: kann man beim AVR genauso haben. Aber dann üblicherweise
> nicht im Hex-File, sondern gleich im ELF-File.

ELF lesen viele Programmer nicht. Also: ja geht, aber nur in der 
Theorie.
Bei PICs hingegen war es von Anfang an so das Flash, EEPROM und Config 
ganz normal im Adressbereich des Programmers auftauchen.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Ich glaube, die Bootloader beim AVR überschreiben immer das gesamte 
Programm im dafür verwendeten Flash-Bereich. Ich glaube das einzige was 
nicht geht ist, daß sich der Bootloader selbst überschreibt. Aber sich 
selbst auslesen und via UART übertragen könnte er.

Aber die Controller sind da sehr vielseitig, man kann damit eigentlich 
allen Blödsinn machen, den man so will.

: Bearbeitet durch User
von Pandur S. (jetztnicht)


Lesenswert?

Nebenbei. bei AVR kann ein conditional jump nur relativ sein, +-63 
adressen oder so. also BREQ (-60). Bedeutet ohne absolute jumps geht gar 
nichts.

Von einem, der auch mal einen bootloader in ASM schrieb

von Jens M. (schuchkleisser)


Lesenswert?

Bei PICs ist ein Conditional Jump immer nur ein Skip (+1 oder eben 
nicht). :D
Da muss man auch mit umgehen können, plus das absolute Gotos immer nur 
einen Teil der Zeiladresse tragen können und man auf das entsprechende 
Latchregister achten muss, was sich wie Paging anfühlt.
So hat jeder seine Vor- und Nachteile...

von (prx) A. K. (prx)


Lesenswert?

Pandur S. schrieb:
> bei AVR kann ein conditional jump nur relativ sein

Das ist bei Architekturen häufiger zu finden. Es gab aber mit z.B. 8048 
und RCA 1802 ein paar Oldies, die eigentlich kein Banking hatten, aber 
deren kurze Sprünge die unteren 8 Bit des PC ersetzten. Von 01F8 auf 
0201 ging also nicht mit kurzen Sprüngen. Das ist eigentlich nur von 
Vorteil, wenn man gleich Binärcode schreibt. Schon in symbolischem 
Assembler nervt es.

Das nicht minder nervende Gegenstück war der SC/MP, der nur 8-Bit 
relativ springen konnte, sonst nur indirekt über Register. Wie das in 
Code aussieht, der ein paar KB gross ist, kann man sich ausmalen.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Jens M. schrieb:
> Könnte man theoretisch über den BL ein 2. Programm in den AVR laden, das
> sich dann via UART selbst ausliest? ;)

Nur wenn man sich einen speziellen Bootloader selber bastelt, der das 
ermöglicht. Außer bei den USB-AVRs ist ab Werk kein Bootloader drauf.

Üblich schreibt ein Bootloader die Applikation an die Adresse 
Applikation-Start und springt dann dorthin.
Auch wenn man Code hinter den belegten Bereich der Applikation schreiben 
könnte, gäbe es keine Instanz, die ihn aufrufen könnte.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jens M. schrieb:

> Jörg W. schrieb:
>> Nur nebenbei: kann man beim AVR genauso haben. Aber dann üblicherweise
>> nicht im Hex-File, sondern gleich im ELF-File.
>
> ELF lesen viele Programmer nicht. Also: ja geht, aber nur in der
> Theorie.

Geht auch in der Praxis. Alle relevanten Programmer lesen das 
inzwischen, insbesondere hat es schon Atmel selbst so vorgemacht damals 
und Microchip übernommen. AVRDUDE macht es auch. Segger ignoriert AVRs 
offenbar komplett (aber auch ansonsten arbeiten die viel mit ELF).

von (prx) A. K. (prx)


Lesenswert?

Jens M. schrieb:
> Bei PICs hingegen war es von Anfang an so das Flash, EEPROM und Config
> ganz normal im Adressbereich des Programmers auftauchen.

Ganz am Anfang noch nicht, weil weder Flash noch EEPROM noch Config 
existierten. :)
https://bitsavers.org/components/gi/PIC/1983_PIC_Series_Microcomputer_Data_Manual.pdf

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Jens M. schrieb:
> Bei PICs ist ein Conditional Jump immer nur ein Skip (+1 oder eben
> nicht). :D
> Da muss man auch mit umgehen können, plus das absolute Gotos immer nur
> einen Teil der Zeiladresse tragen können und man auf das entsprechende
> Latchregister achten muss, was sich wie Paging anfühlt.

Man kann das PCLATH weit vor dem Sprung laden, da es erst bei CALL/GOTO 
übernommen wird. Das macht den  Quellcode nicht gerade lesbarer und kann 
für Überraschungen sorgen, wenn man z.B. mit einen RETI dahin zurück 
springt.

von Roland E. (roland0815)


Lesenswert?

Peter D. schrieb:
> ...
> Die PIC12/16 mit Hardwarestack, segmentiertem RAM und Flash, ständiger
> Bankumschaltung, RETLW, DECFSZ, PCLATH sind einfach nur gruselig.
>

[ ]Du hast verstanden, was 8Bit sind.
[ ]Du hast verstanden, dass die (kleinen) PICs diese Umstände machen 
(müssen) um effektiv 13Bit Adressraum zu nutzen, trotz 8Bit Architektur.

Oder hast du eine bessere Idee, wie du mit einem 8Bit Arbeitsregister 
1023 Adressen nutzen kannst?

Ich benutze die kleinen 12F675 heute noch für Spielereien auf der MoBa. 
Auch mit dem "grottigen" Assembler. Der eigentlich gar nicht grottig 
ist, sondern einfach nur knallhart geradeaus.

Die C-Compiler für die 12Fs sind ganz große Katastrophe. habe ich einmal 
ausprobiert. Nie wieder....

Und trotz aller Geigeleien mit den Teilen habe ich das kByte Flash noch 
nie voll ausnutzen (müssen).

Ok, ein serielles Display möchte ich damit nicht ansteuern, aber 
Schieberegister für Beleuchtungszwecke oder PWM per BitBang für Servos 
sind überhaupt kein Akt.

Den/die PICs habe ich mir vor etlichen Jahren (Jahrzehnten?) selber 
beigebogen. Damals noch mit serieller Schnittstelle zum programmieren.
Im Studium kam dann MSP430, Arm9 und Cortex (M3). Ging, sind halt übelst 
komplex und die (recht vorbildliche) Doku von Microchip zum PIC hatte 
verwöhnt.

Danach sollte ich mal eine kurze Arbeit mit einem AVR32 machen. 
katastrophe. Doku/Referenzhandbuch des Kerns passt(e) überhaupt nicht 
zum von AVR bereitgestellten Framework und die Kommunity trug die Nase 
in den Wolken. Danke, nie wieder.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

(prx) A. K. schrieb:
> GCC hingegen macht es klassisch und als Folge davon kann der Wasserkopf
> am Anfang und Ende von Funktionen ziemlich hässlich aussehen.

Ich seh jetzt nicht, was man mit einem 2ten Stack einspart.  Wenn Platz 
aufm  Stack gebraucht wird, muss dieser immer noch im Prolog allokiert 
und im Epilog wieder freigegeben werden.

Das eigentliche Problem ist ja, dass man mit den Stackpointer nicht 
wirklich auf den Stack zugreifen kann... außer per PUSH / POP.  Wenn 
also eine Funktion einen Frame erfordert, dann muss man aber irgendwo 
in den Stack greifen, was effektiv ein Pointer-Register (Y oder Z) 
erfordert, samt teurer Initailisierung.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

> Oder hast du eine bessere Idee, wie du mit einem
> 8Bit Arbeitsregister 1023 Adressen nutzen kannst?
Der AVR verwendet dafür ein 16-Bit-Register, welches aus zwei 
8-Bit-Registern zusammengesetzt wird (bspw. Z in ZH:ZL bzw. R31:R30). 
Damit sind bis zu 64k (65.536) Adressen erreichbar.

von Peter D. (peda)


Lesenswert?

Roland E. schrieb:
> Oder hast du eine bessere Idee, wie du mit einem 8Bit Arbeitsregister
> 1023 Adressen nutzen kannst?

Z.B. 8051 oder AVR zeigen Dir, wie man 64kB Daten + 64kB Code linear 
adressieren kann.
https://de.wikipedia.org/wiki/Intel_MCS-51

Es gab auch mal 8051 mit >64kB Code (AT89C51RE2: 128kB Flash). Leider 
ist die Fabrik abgebrannt und die Fertigung nicht wieder aufgenommen 
worden.
Auch der P89C669 (96kB Flash) ist schon lange tot.
Nur den C8051F120-GQ gibt es noch, kann aber nur bis 3,6V.
https://www.digikey.de/de/products/detail/silicon-labs/C8051F120-GQ/819523

von Peter D. (peda)


Lesenswert?

(prx) A. K. schrieb:
> Bei AVR ist das an sich kein Problem, nur muss man dazu am Stackpointer
> rumspielen, und an dieser Stelle hat AVR Mist gebaut und dieser Mist
> stinkt bis heute.

Ja, die meisten 16Bit-Register kann der AVR atomar zugreifen (Timer, 
ADC). Nur ausgerechnet beim SP hat man das "vergessen" und auch nicht 
nachgebessert.

von (prx) A. K. (prx)


Lesenswert?

Johann L. schrieb:
> Ich seh jetzt nicht, was man mit einem 2ten Stack einspart

Der erste AVR, der AT90S1200, hatte seinen Return-Stack in Hardware.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Peter D. schrieb:
> und auch nicht nachgebessert.

Das hat mich seither ziemlich gewundert. So arg schwer wärs nicht 
gewesen. Schon ein add/sub immediate to SP hätte fast alle Fälle 
erledigt.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Johann L. schrieb:
> Wenn Platz
> aufm  Stack gebraucht wird, muss dieser immer noch im Prolog allokiert
> und im Epilog wieder freigegeben werden.

Wenn man ISRs in C aussen vor lässt, müssen diese Operationen nicht 
atomar sein, und ADIW/SBIW kamen schon mit den ersten non-AT90 hinzu.

: Bearbeitet durch User
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Man kann sich den Stackpointer nach X,Y oder Z kopieren und dann mit 
diesem Register arbeiten wenn man sowas wirklich braucht.

Ich programmiere recht viel in Assembler und normalerweise lege ich mir 
den Stackpointer einmal beim Start des Controllers ans obere Ende des 
RAM und fasse ihn danach nie wieder an.

von (prx) A. K. (prx)


Lesenswert?

Ben B. schrieb:
> Man kann sich den Stackpointer nach X,Y oder Z kopieren und dann mit
> diesem Register arbeiten wenn man sowas wirklich braucht.

Der früher übliche Framepointer, der bei anderen Architekturen 
heutzutage oft wegoptimiert wird. Und so macht das GCC ja auch. Aber der 
Transfer von XYZ zum SP ist nicht atomar und das ist bei Interrupts 
entscheidend.

> Ich programmiere recht viel in Assembler

Die Problematik bezieht sich auf C. In Assembler liegen lokale Daten 
selten auf dem Stack, weshalb der Prolog/Epilog-Code zur Allokation von 
Daten auf dem Stack entfällt.

: Bearbeitet durch User
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

> Aber der Transfer von XYZ zum SP ist nicht atomar
> und das ist bei Interrupts entscheidend.
Das sollte eigentlich kein Problem sein, da der AVR beim 
Interrupt-Aufruf weitere Interrupts blockiert. Man kann SPH/SPL also in 
zwei Befehlen kopieren, ohne sich darum zu sorgen, daß sich SP 
dazwischen ändert oder auch SP verändern wenn die Interrupt-Routine aus 
irgendwelchen Gründen einen eigenen Stack benutzen soll. Das muss man 
nur logischerweise vor dem Interrupt Return wieder zurückbiegen. Der 
Interrupt Return hebt automatisch die Blockierung der weiteren 
Interrupts wieder auf, so daß die alle nacheinander abgearbeitet werden 
falls mehrere anstehen.

Oder was wäre ein Szenario, wo das Deiner Meinung zu Problemen führt?

von Peter D. (peda)


Lesenswert?

Ursprünglich war gedacht, den Y-Pointer als Framepointer zu reserviern, 
dann entfällt das Anlegen eines Stackframe.
Allerdings muß man dann vorher genau abschätzen, welche Daten wo liegen 
sollen, sonst krachen Stackbereich und Framebereich ineinander.
Legt man lokale Daten mit in den Stack, dann hat man das Problem nicht. 
Es kracht dann erst, wenn wirklich kein SRAM mehr frei ist.

Benutzt man aber Malloc, dann muß man wieder aufteilen, wieviel SRAM der 
Stack und wieviel das Malloc benutzen darf.
Daher wundert es mich oft, daß viele Programmierer leichtfertig Malloc 
benutzen, ohne das es nötig ist.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Ben B. schrieb:
> Das sollte eigentlich kein Problem sein, da der AVR beim
> Interrupt-Aufruf weitere Interrupts blockiert.

Es geht um den Prolog/Epilog normaler Funktionen. Darin wird SP 
geschrieben und das geht nur in 2 Befehlen. Wenn da ein Interrupt 
reinrutscht, kriegt der einen defekten Wert von SP.

Typisches Szenario:
Prolog:
  push FP
  FP = SP
  SP -= const
Epilog:
  SP = FP oder SP += const
  pop FP

Ist "const" recht klein, ersetzt GCC die +=/-= ggf durch ein paar 
PUSH/POPs oder vielleicht auch -= durch RCALL auf Folgebefehl (2-3 
Bytes, je nach AVR). Das sieht dann einigermassen bizarr aus und 
erschliesst sich nur, wenn man das Problem kennt.

: Bearbeitet durch User
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Naja dann halt
1
CLI
2
MOV R31,SPH
3
MOV R30,SPL
4
SEI
oder so ähnlich.

von (prx) A. K. (prx)


Lesenswert?

Yep, so in der Art, wobei der SEI typischerweise eins vorgezogen wird, 
weil er erst nach dem Folgebefehl wirksam wird. Aber es kommt eben 
insgesamt eine Sequenz zusammen, die auf Assembler-Programmierer 
abschreckend wirkt.

: Bearbeitet durch User
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Hm, ein Assembler-Programmierer, der von 4 (in Worten: vier) Zeilen 
Quellcode abgeschreckt wird? ;) Mein längster Assembler-Quellcode ist 
für meine GSM-Alarmanlage, glaube das waren am Ende um die 340kB Text 
und mehrere tausend Zeilen (für einen ATMega1284)...

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

(prx) A. K. schrieb:
> Johann L. schrieb:
>> Wenn Platz
>> aufm  Stack gebraucht wird, muss dieser immer noch im Prolog allokiert
>> und im Epilog wieder freigegeben werden.
>
> Wenn man ISRs in C aussen vor lässt, müssen diese Operationen nicht
> atomar sein, und ADIW/SBIW kamen schon mit den ersten non-AT90 hinzu.

SBIW / ADIW hat aber nix mit der Atomarität einer SP-Änderung zu tun, da 
SBIW / ADIW auf GPRs operiert (also nicht auf SP).  Außerdem wird 
natürlich SUBI+SBCI falls der Offset größer als 63 ist.

Auf ATxmega ist das Setzen von SP dann entlich atomar realisiert.

...wie auch immer, den Zusammenhang zu 1 Stack vs. 2 Stacks sehe ich 
immer nich nicht.  Oder worauf willst du hinaus?

von (prx) A. K. (prx)


Lesenswert?

Ben B. schrieb:
> Hm, ein Assembler-Programmierer, der von 4 (in Worten: vier) Zeilen
> Quellcode abgeschreckt wird? ;)

Diese 4 Befehle sind nur eine der Prolog/Epilog-Operationen, die ich 
oben skizzierte.

Und stell dir dann noch vor, dass ein Sparfuchs für 6 Bytes lokale Daten 
statt dessen
  rcall 0
  rcall 0
reinschreibt und die arme Sau, die das liest und die Problematik nicht 
kennt, bloss Bahnhof versteht.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Johann L. schrieb:
> SBIW / ADIW hat aber nix mit der Atomarität einer SP-Änderung zu tun, da
> SBIW / ADIW auf GPRs operiert (also nicht auf SP).  Außerdem wird
> natürlich SUBI+SBCI falls der Offset größer als 63 ist.

Ein SBIW/ADIW auf SP wär's für viel Fälle gewesen. Kessel geflickt.

von (prx) A. K. (prx)


Lesenswert?

Johann L. schrieb:
> ...wie auch immer, den Zusammenhang zu 1 Stack vs. 2 Stacks sehe ich
> immer nich nicht.  Oder worauf willst du hinaus?

2 getrennte Stacks sind notwendig, wenn der Return-Stack nicht im RAM 
liegt, sondern als 3 als Stack operierende separate Hardware-Register 
vorliegt. Siehe AT90S1200.

Atmel arbeitet damals mit einem Compiler-Hersteller zusammen, weil keine 
Erfahrung mit dessen Vorlieben.

: Bearbeitet durch User
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

> Und stell dir dann noch vor, dass ein Sparfuchs
> für 6 Bytes lokale Daten statt dessen
>  rcall 0
>  rcall 0
> reinschreibt und die arme Sau, die das liest und die
> Problematik nicht kennt, bloss Bahnhof versteht.
Hehe. Dazu kann ich nur sagen, wenn man auf sowas keine Lust hat, dann 
sollte man lieber bei C bleiben und nicht mit Assembler anfangen. Und 
ansonsten könnte auch ein Kommentar dahinter helfen, wo drinsteht was 
das macht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ben B. schrieb:
>> Und stell dir dann noch vor, dass ein Sparfuchs
>> für 6 Bytes lokale Daten statt dessen
>>  rcall 0
>>  rcall 0
>> reinschreibt und die arme Sau, die das liest und die
>> Problematik nicht kennt, bloss Bahnhof versteht.
> [...]. Und ansonsten könnte auch ein Kommentar dahinter helfen,
> wo drinsteht was das macht.

avr-gcc macht das sogar, falls man mit -dp, -dP oder -fverbose-asm 
compiliert:
1
void fun (int*);
2
3
void bun (void)
4
{
5
    int i;
6
    fun (&i);
7
}

Hier  mit -Os -dp:
1
bun:
2
    push r28         ;  16  [c=4 l=1]  pushqi1/0
3
    push r29         ;  17  [c=4 l=1]  pushqi1/0
4
     ; SP -= 2       ;  21  [c=8 l=1]  *addhi3_sp
5
    rcall . 
6
    in r28,__SP_L__  ;  32  [c=4 l=2]  *movhi/7
7
    in r29,__SP_H__
8
/* prologue: function */
9
/* frame size = 2 */
10
/* stack size = 4 */
11
.L__stack_usage = 4
12
    movw r24,r28     ;  35  [c=4 l=1]  *movhi/0
13
    adiw r24,1       ;  15  [c=8 l=1]  *addhi3_clobber/0
14
    rcall fun        ;  6   [c=0 l=1]  call_insn/1
15
/* epilogue start */
16
     ; SP += 2       ;  27  [c=8 l=2]  *addhi3_sp
17
    pop __tmp_reg__
18
    pop __tmp_reg__
19
    pop r29          ;  28  [c=4 l=1]  popqi
20
    pop r28          ;  29  [c=4 l=1]  popqi
21
    ret              ;  30  [c=0 l=1]  return_from_epilogue

: Bearbeitet durch User
von Jürgen K. (geduld)


Lesenswert?

Hallo liebe Freunde,

als Themenstarter bin ich begeistert wie viele Antworten ich auf meine 
Frage bisher erhalten habe. Auch wenn der eine oder andere etwas vom 
eigentlichen Thema abkommt, so liefert er dennoch für mich wichtige 
Aspekte. Punkte aus ihren eigenen Erfahrungen, welche mir im Fehlerfalle 
sicherlich ebenfalls helfen werden.

Aber ich möchte nochmal auf den Kern meiner Frage zurückkommen. 
Vielleicht nochmal ganz kurz warum ich "nur" das eigentliche Programm 
ohne Bootloader in weitere Controller brennen möchte.

Stellt Euch vor, ich habe z.B. eine tolle kleine Anwendung programmiert 
und verfüge ebenfalls über ein Programmer (STK500, Dragon bzw. PICKit 
3). Da ich die Erfahrung habe, dass man mit einem Programmer nicht nur 
die Software deutlich schneller in den Controller bekommt, sondern auch 
noch selbst die Fuses/Configbits setzen oder überprüfen kann, nutze ich 
in der Regel lieber den Programmer.

Jetzt möchte ich meine tolle Schaltung/Anwendung in 5 - 10 weitere 
Controller programmieren, da ich die Schaltungen an meine Freunde 
verschenken möchte....

Ich würde 5 - 10 neue Controller z.B. ATMega328P im Netz bestellen, von 
denen ich nicht weiß, wie die Fuses stehen und ob überhaupt ein 
Bootloader bereits drauf ist. Somit würde ich natürlich meinen 
Programmer nutzen wollen und an einen Bootloader überhaupt nicht mehr 
denken. Das gleiche entsprechend für PIC z.B. PIC18F23K22. Den 
eigentlichen Quelltext finde ich aus irgendeinem Grunde nicht sofort und 
lese lieber schnell mal einen fertigen Controller von mir aus. 
Extrahiere das hex-File und programmiere schnell die 5 - 10 neuen 
Controller.....

Nun habe ich hier im Thread gelernt, dass es zumindest bei PIC18xxxxxx, 
bei denen der eigentliche Code erst bei 0400hex beginnt, besser nicht 
verschoben werden sollte (absolute Sprünge usw., was mir ja auch schon 
irgendwie klar war). Bei ATMEL-Bootloader würde sich an der Startadresse 
ja nichts ändern, da der Bootloader oberhalb liegt.

Nun wäre es wohl tatsächlich besser, alles (Programm + Bootloder) 
auszulesen und auch komplett in die neuen Controller zu flashen.

Was würde aber passieren, wenn ich bei den PICs den Bereich 0000hex - 
03FFhex frei lasse, d.h. FFhex. Springt dann der Programmcounter des 
Controllers weiter bis er den ersten "sinnvollen" Maschinenbefehl auf 
0400hex findet? Bedeutet FFhex NOP? Dann sollte ja alles funktionieren.

Ich unterstelle mal, dass im Bootloader keine Tricks 
(Kopierschutz/Lizenzen o.ä.) programmiert sind, welche ihn unentbehrlich 
machen.


Eine weitere Frage zu diesem Thema:

Wo im AVR-Studio bzw. MPLAB lege ich denn fest, ob ein Bootloader 
genutzt werden soll? Ich habe bisher noch keine Stelle gefunden, wo ich 
das Konfigurieren könnte. Woher weiß der Compiler dass ich einen 
Bootloder zum Flashen einsetzen möchte? Ich denke da auch durchaus an 
die sogenannte Arduino-IDE.

Aus allem was ich hier bisher gelesen habe, sollte zumindest bei den 
PICs MPLAB einen Code erzeugen, der auf die Adresse 0400hex beginnt, 
falls ich eine Bootloder im Controller nutze. Das bedeutet, es müsste im 
MPLAB konfigurierbar sein.


Eine praktische Frage nebenbei: Wie könnte ich dafür sorgen, dass wenn 
ich einen Controller auslese, einen Hinweis finde, welches 
Programm/Stand ich als letztes geflasht habe?
Immer wenn ich 4 Wochen lang nichts am Thema gemacht habe, habe ich 
völlig vergessen, was der letzte Stand im Controller war oder ob der 
Controller überhaupt mein "Entwicklungs"-Controller oder ein 
Jungfräulicher ist.

Eine Idee ist, irgendwie eine laufende Nummer/Konstante (Datum Version)) 
mit in den Flashspeicher zu schreiben, welche ich natürlich manuell 
nachhalten müsste. Aber diese sonst nicht genutzte Konstante/String 
o.ä., sollte mir der Compiler nicht "weg"optimieren.
Wie macht Ihr dass oder habt Ihr das Problem überhaupt nicht?

Viele Grüße und Danke für die vielen Anregungen!

von (prx) A. K. (prx)


Lesenswert?

Jürgen K. schrieb:
> Eine praktische Frage nebenbei: Wie könnte ich dafür sorgen, dass wenn
> ich einen Controller auslese, einen Hinweis finde, welches
> Programm/Stand ich als letztes geflasht habe?

Vor langer langer Zeit hat man dafür Zettelchen auf die EPROMs geklebt. 
EPROMs sind zwar rar geworden, aber die Zettel gibts noch. :)

Beitrag #7880555 wurde vom Autor gelöscht.
von Jürgen K. (geduld)


Lesenswert?

Habe jetzt mal selber die KI befragt:

Um den Offset für die Anwendung (Application) bei Verwendung eines 
Bootloaders im MPLAB X IDE mit dem XC8-Compiler festzulegen, gehst du 
folgendermaßen vor:

    Projekt-Eigenschaften öffnen:
    Rechtsklick auf dein Projekt im Projektnavigator → „Properties“ 
auswählen.

    XC8 Linker-Optionen auswählen:
    Im linken Menü unter „XC8 Global Options“ den Punkt „XC8 Linker“ 
auswählen.

    Zusätzliche Optionen einstellen:
    In der Kategorie „Additional options“ (Zusätzliche Optionen) das 
Feld für benutzerdefinierte Linker-Parameter suchen.

    Offset angeben:
    Dort trägst du den Parameter

text
--codeoffset=0xXXXX

ein, wobei 0xXXXX für die gewünschte Startadresse der Anwendung steht, 
z.B. --codeoffset=0x1000 für einen Offset bei Adresse 0x1000

    .

    Bestätigen und neu bauen:
    Änderungen übernehmen („Apply“/„OK“) und das Projekt neu bauen.

Dadurch wird die Anwendung ab der angegebenen Adresse im Flash platziert 
und überschreibt nicht den Bootloader-Bereich. Der Bootloader bleibt 
somit im unteren Speicherbereich (z.B. ab 0x0000) erhalten, und die 
Anwendung startet ab dem eingestellten Offset.

Hinweis:
Die genaue Adresse hängt vom verwendeten Bootloader und dem reservierten 
Speicherbereich ab. Typische Werte sind z.B. 0x300, 0x600 oder 0x1000.


So langsam bekomme ich das Gefühl: "Gut dass wir darüber geredet haben!"

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Jürgen K. schrieb:
> Eine praktische Frage nebenbei: Wie könnte ich dafür sorgen, dass wenn
> ich einen Controller auslese, einen Hinweis finde, welches
> Programm/Stand ich als letztes geflasht habe?

Man kann sich eine _version.c schreiben.
Der _ sorgt dafür, daß sie als erstes gelinkt wird und so hinter der 
Interruptvektortabelle zu liegen kommt.
PROJECT_STRING, REVISION_STRING, AUTHOR; müssen entsprechend definiert 
werden.
1
const char Version[] __attribute__((used));
2
const char Version[] PROGMEM = PROJECT_STRING ", "
3
                      "V:" REVISION_STRING ", "
4
                      __DATE__ "\n";
5
6
const char Author[] __attribute__((used));
7
const char Author[] PROGMEM  = AUTHOR "\n";

von Jens M. (schuchkleisser)


Lesenswert?

Jürgen K. schrieb:
> Den
> eigentlichen Quelltext finde ich aus irgendeinem Grunde nicht sofort und
> lese lieber schnell mal einen fertigen Controller von mir aus.

Dann solltest du an der Schlusseligkeit arbeiten... ;)

Jürgen K. schrieb:
> Bei ATMEL-Bootloader würde sich an der Startadresse
> ja nichts ändern, da der Bootloader oberhalb liegt.

Da sind aber dann die Fuses anders.

Jürgen K. schrieb:
> Wo im AVR-Studio bzw. MPLAB lege ich denn fest, ob ein Bootloader
> genutzt werden soll?

Da gibt's keinen Haken "mit Bootloader". Das legst du fest, in dem du 
deinen Code kennst und z.B. entsprechende Linkerscripte benutzt, oder 
auch einfach "org $0400".
Oder, wie bei AVRs: der Bootloader ist transparent, er kann das Programm 
enfach so nehmen wie es kommt, es läuft so und so. Nur die Fuses müssen 
passend stehen. Nur den Speicher des BL darfst du nicht benutzen, aber 
der ist am oberen Ende, da kommt man selten hin, und wenn doch 
programmiert sich der BL nicht kaputt, aber dein Programm ist halt 
kaputt.
Arduino weiß das aber und schreibt ja auch "32256 Bytes Flash", der Chip 
hat aber 32768. Die 512 fehlenden sind der Bootloader.

Jürgen K. schrieb:
> Wie könnte ich dafür sorgen, dass wenn
> ich einen Controller auslese, einen Hinweis finde, welches
> Programm/Stand ich als letztes geflasht habe?

PICs haben dafür 4 Nibbles "ID", die man setzen kann und auch mit 
Protection noch auslesen.

Peter D. schrieb:
> Man kann sich eine _version.c schreiben.

Ist das Standard-C oder nur Arduino/AVR-gcc? Geht das auch mit PIC?
Aber selbst wenn: Im Hex kann man es nicht lesen, im Controller auch 
nicht.

von Jürgen K. (geduld)


Lesenswert?

Jens M. schrieb:
> PICs haben dafür 4 Nibbles "ID", die man setzen kann und auch mit
> Protection noch auslesen.

Diese Idee finde ich interessant. Wo finde ich diese Nibbles? In den 
sogenannten ConfigBits?

von Peter D. (peda)


Lesenswert?

Jens M. schrieb:
> Ist das Standard-C oder nur Arduino/AVR-gcc?

PROGMEM ist speziell AVR-GCC, damit die Variablen keinen SRAM belegen.

Jens M. schrieb:
> Im Hex kann man es nicht lesen, im Controller auch
> nicht.

Viele Betrachter zeigen neben dem Intel-Hex auch noch die ASCII 
Darstellung.
Im Controller könnte man diese Variablen z.B. nach dem Einschalten auf 
einem LCD anzeigen oder über ein Interface ausgeben.

von Jürgen K. (geduld)


Lesenswert?

Ich gebe mir dank KI mal selbst die Antwort;-) ggf. auch für andere von 
Interesse.

Die „ID“-Nibbles bei PIC-Mikrocontrollern (meist als „User ID“ oder „ID 
Locations“ bezeichnet) sind spezielle Speicherstellen, die zur 
individuellen Kennzeichnung eines Chips verwendet werden können. Sie 
sind unabhängig vom Programmspeicher und dienen z. B. dazu, eine 
Seriennummer, Versionsnummer oder einen Urheber-Hinweis im Chip zu 
hinterlegen.

Wo findest du die User-ID-Nibbles?

    Die User-ID-Bereiche befinden sich typischerweise an festen Adressen 
im Flash-Speicher des PIC, die im jeweiligen Datenblatt des Controllers 
dokumentiert sind.

    Bei vielen PICs (z. B. PIC16, PIC18) sind diese „ID Locations“ 4 Bit 
breit, also ein Nibble pro Speicherstelle

    .

    Die Anzahl der User-ID-Nibbles variiert je nach PIC-Modell, häufig 
stehen 4 bis 8 Nibbles (also 16 bis 32 Bit) zur Verfügung.

    Die Adressen liegen meist direkt nach dem Programmspeicher, oft ab 
Adresse 0x200000 und aufwärts (bei neueren PICs), oder an anderen, im 
Datenblatt spezifizierten Stellen.

Wie werden sie programmiert?

    Die User-ID-Nibbles können beim Programmieren des Chips mit dem 
Programmer oder über die IDE (z. B. MPLAB X) gesetzt werden.

    In MPLAB X kannst du sie im „Memory Views“-Fenster oder im 
Programmer-Dialog unter „User ID Memory“ oder „ID Locations“ eintragen.

    Sie werden nicht vom Programmcode überschrieben und bleiben 
unabhängig von Firmware-Updates erhalten, solange sie nicht gezielt 
gelöscht oder neu programmiert werden.

Zusammengefasst:
Die User-ID-Nibbles findest du bei PICs an speziellen Adressen im 
Flash-Speicher, meist als „ID Locations“ bezeichnet. Sie sind 4 Bit 
breit und werden zur individuellen Kennzeichnung genutzt. Die genaue 
Adresse und Anzahl entnimmst du dem Datenblatt deines PIC-Modells.

: Bearbeitet durch User
von H. H. (hhinz)


Angehängte Dateien:

Lesenswert?

Jürgen K. schrieb:
> Jens M. schrieb:
>> PICs haben dafür 4 Nibbles "ID", die man setzen kann und auch mit
>> Protection noch auslesen.
>
> Diese Idee finde ich interessant. Wo finde ich diese Nibbles? In den
> sogenannten ConfigBits?

Es sind 4 x 7 Bit üblich, nach dem Programmspeicher.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wird sowas nicht auch von neueren AVRs geboten in der User Signature 
Row?

Hier zum Beispiel ATtiny1614/6/7 (1- Series):

> 6.6 **User Row**
>
> In addition to the EEPROM, the ATtiny1614/1616/1617 has one extra
> page of EEPROM memory that can be used for firmware settings,
> the User Row (USERROW). This memory supports single byte read and
> write as the normal EEPROM. The CPU can write and read this memory
> as normal EEPROM and the UPDI can write and read it as a normal
> EEPROM memory if the part is unlocked. The User Row can also be
> written by the UPDI when the part is locked. USERROW is not
> affected by a chip erase.

Wobei ich es blöd finde, dass UPDI Userrow bei gelockten Devices nicht 
ändern kann.  Wäre ein netten Feature zur Konfiguration (MAC-Adresse, 
I²C-Adresse, ...)

: Bearbeitet durch User
von Jens M. (schuchkleisser)


Lesenswert?

Jürgen K. schrieb:
> Wo finde ich diese Nibbles? In den
> sogenannten ConfigBits?

In den IDs ;)

Das funktioniert so ähnlich wie die Config, wie auch immer du die 
einstellst.
Entweder in dem Dialog, oder via Compilerbefehlen, da musst du aber 
dessen Hilfe fragen.

Jürgen K. schrieb:
> Ich gebe mir dank KI mal selbst die Antwort

Viel geredet, nix gesagt.
Im DaBla des Controllers und der Compilerhilfe (oder der der IDE) 
findest du die echte Info.

Johann L. schrieb:
> Wobei ich es blöd finde, dass UPDI Userrow bei gelockten Devices nicht
> ändern kann.

Nicht "LESEN".
Oder verstehe ich

Johann L. schrieb:
> The User Row can also be written by the UPDI when the part is locked.

falsch?
Ist aber wie du sagst eher Config (MAC, Seriennummer), da nicht lesbar.
PICs IDs sind extra dazu da die Software und die Version auch mit 
Protection identifizieren zu können.

: Bearbeitet durch User
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.