Liebe Gemeinde,
habe ein Projekt in AVR-Assembler begonnen, da ich noch ein paar Atmega8
rumliegen hatte und diese genügend Pins haben.
Mein Code funzt eigentlich, bis ich eine Routine aufrufen wollte, in
Abhängigkeit des Carry-Flags.
Ich schaff's einfach nicht.
Mit brcc hab ich etwas halbwegs Funktionierendes zusammengebrutzelt,
aber die Sprungweite ist glaube ich auf 64PC beschränkt und ich weiss
nicht, ob der Stack bei dieser Instruktion beeinflusst wird.
Ich möchte eine rcall-Routine aufrufen, am Schluss dieser Routine ret
und dann im Programm Weiterfahren.
Kann mir jemand helfen?
freundliche Grüsse Picfan
spess53 schrieb:> Hi>>>ob der Stack bei dieser Instruktion beeinflusst wird.>> Sprünge beeinflussen keine Flags.>> MfG Spess
Das war überhaupt nicht seine Frage!
Er will in Abhängigkeit von einem Flag einen Sprung machen.
Und er will wissen, ob der Stack beeinflusst wird.
picfan schrieb:> Mit brcc hab ich etwas halbwegs Funktionierendes zusammengebrutzelt,> aber die Sprungweite ist glaube ich auf 64PC beschränkt und ich weiss> nicht, ob der Stack bei dieser Instruktion beeinflusst wird.> Ich möchte eine rcall-Routine aufrufen, am Schluss dieser Routine ret> und dann im Programm Weiterfahren.
entweder du machst branch also Sprünge ohne Stacknutzung!
Das wäre oneway!
oder du willst jump subroutine dann wird die Rücksprungadresse auf den
Stack gelegt!
Das wäre mit return.
Am LH5803 vom PC1500 hatte ich relokatibel programmieren wollen, also
schied jsr jump subroutine aus, ergo hatte ich den PC gelesen die
Rücksprungadresse berechnet auf den Stack gelegt und mit branch vor oder
zurück die "Sub" angesprungen, durch die Berechnung vom aktuellen PC war
es dann egal wo der Code im EEPROM lag.
Also jsr ersetzt durch PC auf Stack + Korrektur dann branch +- byte und
return normal durch Rücksprung (return) vom Stack lesen und Stack wieder
herstellen.
S. Landolt schrieb:> rcall Unterprogramm
bei rcall wird sicher die Rücksprungadresse auf den Stack gelegt was
picfan schrieb:> ob der Stack bei dieser Instruktion beeinflusst wird.
eine Beeinflussung wäre
S. Landolt schrieb:> Ohne den Hintergrund und die Vorstellungen eines 'pic-Fans' zu kennen
so gehts mir auch, was will er was ist sein Ziel?
will er Subs anspringen von mehreren Stellen und wieder zurück ohne
Stackmanipulation?
will er nur immer branch ohne return?
keine Ahnung was er möchte.
eigentlich möchte ich nur stinkeinfach in Abhängigkeit vom C-Flag im
SREG eine rcall Routine aufrufen, etwa so:
start:
ldi r16,0x80
ldi R17,0x90
sub R16,R17 ;r16 wird von r17 abgezogen, C-Flag müsste also gesetzt
;sein, d.h. PORTB,0 sollte = 1 sein, ist es aber nicht!
;meine Led an PORTB,1 leuchtet!
lds R18,SREG
sbrc r18,0
rcall ein
nop
sbrs r16,0
rcall aus
nop
rjmp start
aus:
sbi DDRB,1
sbi PORTB,1
ret
ein:
sbi DDRB,0
sbi PORTB,0
ret
picfan schrieb:> sub R16,R17 ;r16 wird von r17 abgezogen, C-Flag müsste also gesetzt> ;sein, d.h. PORTB,0 sollte = 1 sein, ist es aber nicht!
Doku lesen. ;-)
Es gibt zwei Arten zu subtrahieren. Die einen subtrahieren, dann kommt
im Beispiel hier für ein Borrow ein C=1 raus. Die anderen, wie AVR,
addieren statt dessen das Einerkomplement. Dann kommt für ein Borrow ein
C=0 raus.
>Auch den Atmega8 kann man LOCKER in C schreiben.
Vielleicht, weil Assembler wesentlich übersichtlicher und vor Allem
nicht so "geheimnisvoll" wie "C" ist? In Assembler passiert das -und
nur das, was der Programmierer hinschreibt. Da wird nichts
wegoptimiert und Datentypen sind kein Lottospiel.
A. schrieb:> Warum tut man sich das heutzutage noch an? Also ein ganzes Programm in> Assembler schreiben. Auch den Atmega8 kann man LOCKER in C schreiben.
Nicht schon wieder... Kannst du nicht zur Abwechslung mal einen Streit
um Linux vs Windows anzetteln?
A. schrieb:> Warum tut man sich das heutzutage noch an? Also ein ganzes Programm in> Assembler schreiben. Auch den Atmega8 kann man LOCKER in C schreiben.
Ja, im nachhinein gesehen wär's einfacher gewesen, habe aber einen
fertigen, alten Assembler-code hervorgeholt, in der Hoffnung, diesen mit
ein paar klicks an meine Bedürfnisse anzupassen......
picfan schrieb:> habe ein Projekt in AVR-Assembler
Ich habe über viele erfolgreich Jahre in Assembler programmiert.
Irgendwann kamen leistungsfähigere Prozessoren und mehr Memory.
Seitdem Programmiere ich nur in Hochsprache. Assembler heutzutage
ist etwas für Masochisten.
> ist kürzer und schneller.
ich muss insgesamt 8 Routinen aufrufen, da Branch den Stack nicht
bedient,
habe ich Angst, irgendwo ins Nivana zu springen.
Ich glaube ich mach's lieber etwas umständlich, so weiss ich sicher,
dass es funzt. Zeitkritisch ist das Projekt nicht.
Aber vielen Dank für Deine Bemühungen!
Nogger Dir Einen schrieb:> Vielleicht, weil Assembler wesentlich übersichtlicher und vor Allem> nicht so "geheimnisvoll" wie "C" ist?
Das verstehe ich nicht? Assembler ist doch nicht übersichtlicher?
Wie gesagt, etwas für Masochisten ;)...
A. schrieb:> Das verstehe ich nicht? Assembler ist doch nicht übersichtlicher?
Für dich!
Aber ich gebe ihm insofern recht, wenn er sagt, bei Assembler tut der µC
genau das, was geschrieben steht. Bei einer Hochsprache bestimmt
letztendlich der Compiler, was der µC macht...
Sumo schrieb:> A. schrieb:>> Das verstehe ich nicht? Assembler ist doch nicht übersichtlicher?>> Für dich!>> Aber ich gebe ihm insofern recht, wenn er sagt, bei Assembler tut der µC> genau das, was geschrieben steht. Bei einer Hochsprache bestimmt> letztendlich der Compiler, was der µC macht...
Ich habe ja Anfangs auch Assembler programmiert. Heute erwische ich mich
manchmal, wenn ich so vor mich hin programmiere folgendes:
"Hättest du jetzt das alles in Assembler programmiert (STM32 mit 10000
Zeilen Code), dann hättest du für diese kleine Änderung womöglich Tage
gebraucht und 1000 Folgefehler eingebaut. In C war es nun ein
fehlerloses Klick, 1 Minute".
Ich würde nicht mal mehr den kleinsten PIC in Asembler programmieren.
Soweit ich mich erinnere hat so ein AVR sowieso seltsame
Verzweigungsbefehle. Man muss die Beschreibung eines bedingten Sprunges
genauestens durchlesen, denn er kann bisweilen auf Bedingungen reagieren
die nicht so offensichtlich sind. Ich habe den Sprung damals einfach aus
einem Netz-Beispiel übernommen, genau verstanden habe ich es aber nicht
- war auch mies beschrieben.
Genau schrieb:> Soweit ich mich erinnere hat so ein AVR sowieso seltsame> Verzweigungsbefehle.
Es gibt eine Branchenkonvention, an die sich aber nicht alle halten:
lower/higher = unsigned,
less/greater = signed.
picfan schrieb:> A. schrieb:>> Warum tut man sich das heutzutage noch an? Also ein ganzes Programm in>> Assembler schreiben. Auch den Atmega8 kann man LOCKER in C schreiben.>> Ja, im nachhinein gesehen wär's einfacher gewesen, habe aber einen> fertigen, alten Assembler-code hervorgeholt, in der Hoffnung, diesen mit> ein paar klicks an meine Bedürfnisse anzupassen......
Wenn du weißt, was in diesem Assembler Code genau passiert, dann wäre es
bestimmt leicht diesen schnell in C zu programmieren. Weniger Zeilen,
lesbarer und in Zukunft schnell portierbar.
Genau schrieb:> Man muss die Beschreibung eines bedingten Sprunges> genauestens durchlesen, denn er kann bisweilen auf Bedingungen reagieren> die nicht so offensichtlich sind.
Das SREG hat 8 Bits und daher gibt es 16 bedingte Sprungbefehle.
Wenn Dir die Namen zu kompliziert sind, kannst Du im Sprungbefehl auch
die Bitnummer (0..7) hinschreiben.
BRBC 0, Ziel
BRBS 7, Ziel
Beachten muß man natürlich, daß nur bestimmte Befehle Bits setzen.
Z.B. überlebt das C den INC-Befehl und das H den ADIW-Befehl.
In der Praxis kann es daher passieren, daß der Sprung einige Befehle
später erfolgt.
Peter D. schrieb:> Das SREG hat 8 Bits und daher gibt es 16 bedingte Sprungbefehle.
Wobei dieser direkte Zusammenhang zwischen SREG Bits und
Sprungbedingungen eine Besonderheit der AVR Architektur ist. Andere
Architekturen mit Statusregister haben kein S-Flag und müssen daher (N ⊕
V) als Teil des Sprungbefehls auswerten.
Umgekehrt bedeutet es, dass andere Architekturen auch Bedingungen
implementieren können, die AVR mangels passender SREG-Bits nicht
beherrscht, wie etwa <= und > signed/unsigned. Die kamen u.U. ebenfalls
auf 16 Bedingungen, aber ohne Zusammenhang mit dem Aufbau des
Statusregisters.
c-hater schrieb im Beitrag #5310420:
> Das Problem ist, dass Atmel (wohl zum Aufpushen der Zahl unterstützter> Instruktionen) fiktive Branch-Befehle für ihren Assembler erfunden hat,> die es in der Realität der Opcodes überhaupt nicht gibt.
Das ist durchaus vernünftig. So entspricht beim AVR
BRSH (same or higher) = BRCC, C=0
während der dazu äquivalente Befehl beim ARM
BHS (higher or same) = BCS, also C=1
ist.
Meint man den Vergleich ohne Vorzeichen, wird die Sprungrichtung bei
BRSH/BHS sofort eindeutig, während man bei BRCC/BCS erst einmal über die
unterschiedliche Arbeitsweise der Subtraktion nachdenken muss.
A. K. schrieb:> c-hater schrieb im Beitrag #5310420:>> Das Problem ist, dass Atmel (wohl zum Aufpushen der Zahl unterstützter>> Instruktionen) fiktive Branch-Befehle für ihren Assembler erfunden hat,>> die es in der Realität der Opcodes überhaupt nicht gibt.>> Das ist durchaus vernünftig. So entspricht beim AVR> BRSH = BRCC, C=0> während der dazu äquivalente Befehl beim ARM> BHS = BCS, also C=1> ist.>> Meint man den Vergleich ohne Vorzeichen, wird die Sprungrichtung bei> BRSH/BHS sofort eindeutig, während man bei BRCC/BCS erst einmal über die> unterschiedliche Arbeitsweise der Subtraktion nachdenken muss.
???
Am Thema vorbei.
Es geht um die Branches, bei denen in der vorhergehenden arithmetischen
Operation Quell- und Ziel-Register getauscht werden müssen, damit das
dem Namen nach zu erwartende Ergebnis bei der Verzweigung herauskommt...
c-hater schrieb:> Es geht um die Branches, bei denen in der vorhergehenden arithmetischen> Operation Quell- und Ziel-Register getauscht werden müssen, damit das> dem Namen nach zu erwartende Ergebnis bei der Verzweigung herauskommt...
???
c-hater schrieb im Beitrag #5310420:
> Das Problem ist, dass Atmel (wohl zum Aufpushen der Zahl unterstützter> Instruktionen) fiktive Branch-Befehle für ihren Assembler erfunden hat,> die es in der Realität der Opcodes überhaupt nicht gibt.
Selten so einen Quatsch gelesen. Natürlich gibt es die Opcodes. Wie
sollte die Instruktion denn auch sonst ausgeführt werden? Und wie man
auf so eine verquere Idee kommen kann, dass das Marketing den
Befehlssatz festgelegt hätte, ist mir schleierhaft.
Welchen Sinn hätte es denn gehabt, wenn man zwei separate Opcodes hat,
die das selbe tun, vor allem, wo der Platz dafür eh recht knapp bemessen
ist?
Es gibt für den selben Opcode mehrere Mnemonics, daran ist doch nichts
schlimmes. Niemand muß Mnemonics benutzen, wenn er sie nicht mag.
Deswegen muß man doch kein riesen Faß aufmachen. Aber so kennen wir
unseren Hater. Der sieht Probleme, wo gar keine sind.
Rolf M. schrieb:> c-hater schrieb im Beitrag #5310420:>> Das Problem ist, dass Atmel (wohl zum Aufpushen der Zahl unterstützter>> Instruktionen) fiktive Branch-Befehle für ihren Assembler erfunden hat,>> die es in der Realität der Opcodes überhaupt nicht gibt.>> Selten so einen Quatsch gelesen. Natürlich gibt es die Opcodes. Wie> sollte die Instruktion denn auch sonst ausgeführt werden? Und wie man> auf so eine verquere Idee kommen kann, dass das Marketing den> Befehlssatz festgelegt hätte, ist mir schleierhaft.
Vor allem ist das schon immer so, daß man auch mal zwei oder gar noch
mehr Mnemonics für den gleichen Opcode hat. Die bedingten Sprungbefehle
sind geradezu prädestiniert dafür, weil ein und das selbe Flag logisch
durchaus etwas anderes bedeuten kann, je nachdem welche Operation das
Flag gesetzt hat.
Für das Zero-Flag gibt es typisch Mnemonics wie JREQ (Jump Relative when
EQual) - sinnvoll zu verwenden nach einem Vergleich. Alternativ JRZ
(Jump Relative on Zero) - z.B. nach dem Dekrementieren eines
Schleifenzählers. Konkret sind das Menmonics für den Z8. Aber auch in
6502 Assembler gibt es das.
Auch ganz nett ist CLR r als alternative Schreibweise für XOR r,r.
Gestandene Assemblerprogrammierer kennen zwar diesen Trick, ein Register
auf 0 zu setzen, aber beim Lesen des Codes ist der CLR Mnemonic
eingängiger, weil er die Intention des Codes besser wiedergibt. Und
der ganze Sinn der Assemblerprogrammierung mit Mnemonics statt der
Opcodes (z.B. in Hexadezimal) ist ja Lesbarkeit
Weniger nett sind allerdings CBR/SBR als Zweitverwertung von ANDI/ORI.
Da wäre es besser gewesen, in Analogie zu CBI/SBI eine Bitnummer
anzugeben, statt einer Maske. So wie jetzt kann ich nur empfehlen, diese
Befehle nicht zu verwenden, um sich nicht versehentlich in den Fuss zu
schiessen.
Zu Assembler gegen C:
Ich habe in einem youtube-Video gesehen dass ein freier COmpiler einen
zusätzlichen PUSH-Befehl bei einem 8086-Programm in das
Assembler-Ergebnis einbaute.
Kann es sein dass man mit dieser extra-Nichtoptimierung
Patent-Streitigkeiten aus dem Weg gehen will ?
Bla schrieb:> Kann es sein dass man mit dieser extra-Nichtoptimierung> Patent-Streitigkeiten aus dem Weg gehen will ?
Wohl kaum. Du hast bei einem Compiler eine Anspruch auf korrekt
umgesetzten Code, aber keinen Anspruch auf perfekt optimierten Code.
Axel S. schrieb:> Für das Zero-Flag gibt es typisch Mnemonics wie JREQ (Jump Relative when> EQual) - sinnvoll zu verwenden nach einem Vergleich. Alternativ JRZ> (Jump Relative on Zero) - z.B. nach dem Dekrementieren eines> Schleifenzählers. Konkret sind das Menmonics für den Z8. Aber auch in> 6502 Assembler gibt es das.
Beim x86 ist das auch nicht anders. Da heißen sie JZ (jump if zero) und
JE (jump if equal).
> Auch ganz nett ist CLR r als alternative Schreibweise für XOR r,r.
Ein anderes Beispiel wäre der Linksshift, für den man sich auch eine
extra Opcode sparen konnte, da eine Addition eins Registers mit sich
selbst das gleiche Ergebnis liefert. LSL rX ist daher identisch mit ADD
rX, rX. Auch hier verbessert es die Lesbarkeit, wenn man das als Shift
hinschreiben kann, statt als Addition.
A. K. schrieb:> Weniger nett sind allerdings CBR/SBR als Zweitverwertung von ANDI/ORI.
Jo, da denkt der "normale" Programmierer eher in Masken und And und Or.
> Da wäre es besser gewesen, in Analogie zu CBI/SBI eine Bitnummer> anzugeben, statt einer Maske.
CBR/SBR können aber mehr als nur ein Bit auf 0/1 zu setzen. Bei Angabe
von Bits bei SBR Rd,0xaa müsste man SBR Rd,1,3,5,7 hinschreiben.
> So wie jetzt kann ich nur empfehlen, diese> Befehle nicht zu verwenden, um sich nicht versehentlich in den Fuss zu> schiessen.
ACK. In diesem Falle ist der semantische Zucker überflüssig, stört aber
auch nicht.
Um ein Register zu Löschen schreiben wohl jeder CLR Rn Zucker anstatt
EOR Rn,Rn sowie ROL Rn anstatt ADC Rn,Rn für Links-Rotieren.
Johann L. schrieb:> CBR/SBR können aber mehr als nur ein Bit auf 0/1 zu setzen. Bei Angabe> von Bits bei SBR Rd,0xaa müsste man SBR Rd,1,3,5,7 hinschreiben.
Könnte man macher, aber ANDI/ORI ist ja nicht verboten, bloss weil es
CBR/SBR gibt.
A. K. schrieb:> ???
OK, du warst der einzige, der ohne die Hass-Reflexe der Nixwisser
einfach nur die eigene Unkenntnis eingestanden hat. Also kriegst du auch
eine sinnvolle Antwort. Es geht um das Problem, was ich im Anhang rot
hervorgehoben habe.
De facto gibt es die Hälfte der markierten Instruktionen nicht. Wie
schon gesagt: das trifft auch noch auf viele weitere Instruktionen zu,
aber hier, im Falle der conditionals ist es wirklich beschämend und
unwürdig, denn hier kann nicht durch reine Assemblermagie am Ende doch
das erwartete Ergebnis rauskommen, sondern man muss in der
vorhergehenden Operation die Operanden tauschen.
Das allein ist schon höchst fragwürdig, wäre aber vielleicht (je nach
Leidensfähigkeit des Programmierers) für cp/cpc noch irgendwie
akzeptabel (für cpi schon nicht mehr, denn da kann man die Operanden
nicht einfach tauschen).
Es ist aber vollkommen inakzeptabel für subi/sbci/sub/sbc, denn für die
immediate-Varianten geht wiederum der Trick mit dem Operandentausch
nicht, und bei dem Rest werden dann zwar die Flags entsprechend der
Erwartungen gesetzt, aber es kommt numerisch schlicht das falsche
Ergebnis raus (nämlich das Zweierkomplement des richtigen Ergebnisses).
Und das ist ganz sicher vollkommen inakzeptabel.
Zumal Atmel in seiner unerforschlichen Weisheit keine 'cpci'-Operation
spendiert hat, man also beim Vergleich gegen Konstanten mit mehr als
Byte-Größe sogar gezwungen ist, die potentiell destruktive Subtraktion
zu benutzen.
c-hater schrieb:> De facto gibt es die Hälfte der markierten Instruktionen nicht.
Diese Tabelle kannte ich überhaupt nicht. ;-).
Die Mnemonics in der Tabelle gibts aber alle, nur die darin
beschriebenen Sprungbedingungen gibts nicht alle. So gibts kein >/<=
signed/unsigned. Die Tabelle bietet für diese Fälle nur eine
Hilfestellung, was du tun musst, um diese Bedingungen dennoch nutzen zu
können. Sie beschreibt keine Befehle. Und sie bezieht sich
ausschliesslich auf Reg-Reg Vergleiche, da gibts diese Alternativen
stets.
> Zumal Atmel in seiner unerforschlichen Weisheit keine 'cpci'-Operation> spendiert hat,
Tja, und die Moral von der Geschicht: Atmel hat nicht geschummelt,
sondern hat nicht alle Befehle implementiert, die du gerne hättest. Für
die fehlenden Bedingungen hätte es angesichts der Struktur der beiden
einzigen echten bedingten Sprungbefehle BCLR/BSET ein 10 Bit
Statusregister gebraucht. Eine Entscheidung der Basisarchitektur, nicht
vom Marketing. Pech für die Kuh Elsa.
So unerforschlich ist das übrigens nicht. In 16 Opcodebits passen keine
17 Bits rein. Reg-Immediate haben 12 Bits an Daten drin, weshalb jeder
einzelne Befehl davon 1/16 des Opcode-Space frisst. Irgendwann ist voll:
https://en.wikipedia.org/wiki/Atmel_AVR_instruction_set#Instruction_encoding
A. K. schrieb:> Die Mnemonics in der Tabelle gibts aber alle
Sie tuen nur nicht, was man erwarten dürfte. Jedenfalls nicht ohne
massive Verbiegungen bei vorhergehenden Operationen und den Seiteneffekt
des komplett falschen numerischen Ergebnisses, wenn man diese
Verbiegungen tatsächlich unternimmt.
Und genau das ist das Problem: es widerspricht dem Grundkonzept von
Assembler. Das ist mehr sowas wie C. Irgendwas wird schon rauskommen,
man muss nur hinreichend fest glauben, dass es auch richtig ist, dann
passt das schon...
c-hater schrieb:> Sie tuen nur nicht, was man erwarten dürfte.
Ich fürchte, dass du diese Tabelle völlig missverstehst. Sie beschreibt
keine Befehle, keine Mnemonics. Sie beschreibt nur Bedingungen, mit
denen man in Programmen mitunter zu tun hat.
Die erste Spalte "Test" ist der Schlüssel der Tabelle, zusammen mit
"Comment" für signed/unsigned. Der Rest ist eine sehr kurz gefasste
Hilfestellung, mehr nicht. Besonders gelungen ist diese Darstellung
allerdings wirklich nicht.
Denk dir diese Tabelle einfach weg, reiss sie aus dem PDF raus. Dir geht
dabei nichts verloren.
A. K. schrieb:> Sie beschreibt keine Befehle. Und sie bezieht sich> ausschliesslich auf Reg-Reg Vergleiche, da gibts diese Alternativen> stets.
Wo steht übrigens, dass sich diese Tabelle nur auf Register-*Vergleiche*
bezieht? Die Stelle im DB musst du mir zeigen!
OK, ich muss aber immerhin zugeben, dass das Immediate-Problem
tatsächlich nicht von der Tabelle erfasst wird, denn sie setzt
tatsächlich explizit auf Rd/Rr ab. Ist das gut? Wohl eher nicht, ist
eher ein Armutszugnis für den Assembler. Der müsste dann nämlich
konsequenterweise die Anwendung der entsprechenden Vergleiche als Fehler
melden, wenn zuvor immediate-Operationen liefen. Das kann er nicht
zuverlässig realisieren. Allein diese Tatsache zeigt die Unsinnigkeit
dieser fiktiven Instruktionen!
Und ganz sicher löst diese Einschränkung auch nicht das Hauptproblem des
falschen numerischen Ergebnisses...
c-hater schrieb:> OK, du warst der einzige, der ohne die Hass-Reflexe der Nixwisser> einfach nur die eigene Unkenntnis eingestanden hat.
Du hättest natürlich auch gleich dazuschreiben können, auf was du dich
beziehst, statt erstmal so geheinminsvoll zu tun und irgendeinen Unsinn
über Marketing-Verschwörungen zu verbreiten.
c-hater schrieb:> De facto gibt es die Hälfte der markierten Instruktionen nicht.
Dir ist aber aufgefallen, dass da einfach die selben Instruktionen
zweimal stehen? Da wird also nirgends irgendeine Zahl an Instruktionen
"aufgeputscht". Man hätte das allerdings wirklich in der Tabelle
weglassen sollen - es verwirrt mehr, als dass es hilft.
> Zumal Atmel in seiner unerforschlichen Weisheit keine 'cpci'-Operation> spendiert hat, man also beim Vergleich gegen Konstanten mit mehr als> Byte-Größe sogar gezwungen ist, die potentiell destruktive Subtraktion> zu benutzen.
Das ist nicht "unerforschlich", sondern einfach der Tatsache geschuldet,
dass man so eine Instruktion einfach nicht mehr hätte unterbringen
können, bzw. man hätte dafür dann was anderes weglassen müssen.
Du musst bedenken, dass bis auf ein paar wenige Ausnahmen alle
Instruktionen 16 Bit breit sind, d.h. der - ich nenne es mal
"Instruktionenraum" ist begrenzt (Ich meine damit die insgesamt 65.536
verschiedenen möglichen Kombinationen aus Opcode und Operanden). Gerade
die Befehle mit Immediate-Werten belegen davon einen immens großen Teil,
weil die Operanden soviel Platz in der Instruktion brauchen.
Nehmen wir mal z.b. SUBI. Das wurde schon begrenzt auf die Hälfte der
Register, weil es sonst überhaupt nicht mehr gepasst hätte. Es braucht
damit 8 Bit für den übergebenen Immediate-Wert und 4 Bit für die
Registerauswahl, also 12 Bit für die Operanden. Es bleiben lediglich 4
Bit für den Opcode. Das heißt diese eine Instruktion belegt 1/16 des
gesamten Instruktionenraums. Man kann also nur eine begrenzte Menge
davon unterbringen.
Bei den Branch-Befehlen wurden 7 Bit für das Ziel reserviert und 3 Bit
für die Art der Bedingung. Damit lassen sich also 8 verschiedene
Branch-Befehle implementieren, und genau soviele gibt es auch.
Bevor man über solche Begrenzungen schimpft, sollte man sich mal
überlegen woher sie kommen, bzw. wie man es denn selber besser machen
würde. Meist fällt einem dann auf, dass es durchaus Gründe gibt, warum
es so ist.
c-hater schrieb:> Wo steht übrigens, dass sich diese Tabelle nur auf Register-*Vergleiche*> bezieht?
In der ganz linken Spalte. Da steht zu jeder Zeile, auf welchen
Registervergleich sie sich ganz konkret bezieht. Oder was meinst du, was
z.B. "Rd ≤ Rr" bedeutet?
c-hater schrieb:> Wo steht übrigens, dass sich diese Tabelle nur auf Register-*Vergleiche*> bezieht? Die Stelle im DB musst du mir zeigen!
Eben in besagter erster Spalte. "Rd > Rr". R=Register. Klar, steht auch
"Zero" drin, aber da gibts auch kein Problem. Ich sag ja, die Tabelle
ist etwas unglücklich dargestellt, weil sie versucht, 2 Fliegen mit
einer Klappe zu erschlagen. Und dabei versehentlich dich erwischt. ;-)
> eher ein Armutszugnis für den Assembler. Der müsste dann nämlich> konsequenterweise die Anwendung der entsprechenden Vergleiche als Fehler> melden, wenn zuvor immediate-Operationen liefen.
Tut er doch auch, gewissermassen. Weil du schlicht nicht in der Lage
bist, einen Vergleich <= oder > überhaupt in Assembler zu formulieren.
Weil es kein Mnemonic dafür gibt. Spätestens wenn du sowas wie BRSL/BRLE
für <= unsigned/signed hinschreibst, wird der Assembler dir sagen, dass
es diese Mnemonics beim AVR nicht gibt. So würden sie vielleicht
heissen, wenn es sie gäbe.
A. K. schrieb im Beitrag #5310994:
> Programmiere lieber nicht in Assembler, wenn dich> solche einfachen Tabellen komplett aus der Kurve werfen. Nimm C. ;-)
Hahaha, der ist gut. ;-)
A. K. schrieb im Beitrag #5310988:
> Bring mir bitte ein Beispiel dafür, das wird mir zu abstrakt. Ich bin> nämlich nicht in der Lage, hinter> SUB r1,r2> einen bedingten Sprungbefehl zu schreiben, der bei <= springt, egal ob> signed oder unsigned. Es existieren keine Befehle dafür, keine> Mnemonics. Nichts, wogegen ein Assembler etwas tun könnte oder sollte.>> Allerdings bin ich in der Lage, das umzudrehen. Also> SUB r2,r1> BRGE target> Und genau das will dir die Tabelle sagen.
Ja. Am Ende hast du richtig vezweigt, aber das falsche Ergebnis und
obendrein im falschen Register...
Ist dieses Mnemnonic das wert? Ich sage: es sollte dieses Mnemnonic
überhaupt nicht geben. Genau das ist doch der Punkt. Es tut nur unter
diversen Randbedingungen, was es tun soll und der Assembler ist nicht in
der Lage, die Einhaltung dieser Randbedingungen zu kontrollieren. ->
weniger als nutzlos->kontraproduktiv->überflüssig.
Und weil mir vorgeworfen wurde, dass ich Marketing-Verschwörungstheorien
erfinden würde: wer liefert den logisch zweifelsfreien Beweis für den
Nutzen der fiktiven Mnemnonics. Ich bin bereits hochgespannt...
c-hater schrieb:> Ist dieses Mnemnonic das wert? Ich sage: es sollte dieses Mnemnonic> überhaupt nicht geben.
Welchen? BRGE? Das wäre blöd. Wie mache ich dann einen Sprung, wenn ein
Registerwert größer oder gleich einem anderen ist?
> Genau das ist doch der Punkt. Es tut nur unter> diversen Randbedingungen, was es tun soll und der Assembler ist nicht in> der Lage, die Einhaltung dieser Randbedingungen zu kontrollieren. ->> weniger als nutzlos->kontraproduktiv->überflüssig.
BGRE macht nicht das falsche, sondern genau das, was es soll. Die
Tabelle sagt auch nicht, dass es etwas anderes tut, sondern sie sagt
lediglich: Es gibt kein BRLE, also wenn du einen Vergleich auf kleiner
oder gleich brauchst, nimm stattdessen BRGE mit vertauschten Operanden.
Mehr will dir die Tabelle damit gar nicht sagen.
c-hater schrieb im Beitrag #5311012:
> Die schlichte Tatsache, das jeder Vergleich numerischer Werte implizit> eine Subtraktion ist.
In Assembler ja. In der linken Spalte der Tabelle steht aber eine
mathematische Darstellung, und da ist das nicht das gleiche.
c-hater schrieb:> A. K. schrieb im Beitrag #5310988:>>> Bring mir bitte ein Beispiel dafür, das wird mir zu abstrakt. Ich bin>> nämlich nicht in der Lage, hinter>> SUB r1,r2>> einen bedingten Sprungbefehl zu schreiben, der bei <= springt, egal ob>> signed oder unsigned. Es existieren keine Befehle dafür, keine>> Mnemonics. Nichts, wogegen ein Assembler etwas tun könnte oder sollte.>>>> Allerdings bin ich in der Lage, das umzudrehen. Also>> SUB r2,r1>> BRGE target>> Und genau das will dir die Tabelle sagen.
Wenn du bitte die Güte hättest, hier nicht offen rumzulügen! Gib deinen
Code als deinen Code aus, nicht als meinen. Das Bisschen copy&paste
ist wohl zumutbar.
sumo schrieb im Beitrag #5311016:
> Wenn das mal keine Gesprächskultur ist, dann weiss ich auch nicht! ;-)
Wenn man mit dem diskutiert, muss man sich wohl an solchen verbalen
Dünnpfiff gewöhnen. Ich hatte überlegt, an der Stelle abzubrechen, aber
mir war grad langweilig, also ignoriere ich die Entgleisungen mal
ausnahmsweise.
Rolf M. schrieb:>> Ist dieses Mnemnonic das wert? Ich sage: es sollte dieses Mnemnonic>> überhaupt nicht geben.>> Welchen? BRGE? Das wäre blöd. Wie mache ich dann einen Sprung, wenn ein> Registerwert größer oder gleich einem anderen ist?
Vielleicht sollte es wirklich bloss BCLR und BSET geben und keinerlei
verwirrende Aliase welcher Art auch immer. Das ist dann unzweifelhaft
eindeutig. Und Assembler-Programmierung ist dann endlich wieder nur was
für Experten wie ihn. ;-)
A. K. schrieb:> Wenn du bitte die Güte hättest, hier nicht offen rumzulügen! Gib deinen> Code als deinen Code aus, nicht als meinen. Das Bisschen copy&paste> ist wohl zumutbar.
Hätte mir aber mehr Arbeit gemacht. Ich bin faul. Aber deine allergische
Reaktion zeigt doch überdeutlich, was ich zeigen wollte: Das ist
Bullshit.
Und es wäre genauso Bullshit, wenn ich korrekt zitiert hätte...
Kannst du wenigstens das zugeben? Oder muss ich wirklich korrekt
zitieren, die entprechenden Änderungen anbringen und dann sagen, dass
das Ergebnis zeigt, dass diese Scheisse einfach nur Scheisse ist?
c-hater schrieb:> De facto gibt es die Hälfte der markierten Instruktionen nicht.
Die Instruktionen gibt es schon, nur eben nicht immer eine 1:1 Umsetzung
von A <op> B zu Compare A,B + Branch<op>.
> im Falle der conditionals ist es wirklich beschämend und> unwürdig, denn hier kann nicht durch reine Assemblermagie am Ende doch> das erwartete Ergebnis rauskommen, sondern man muss in der> vorhergehenden Operation die Operanden tauschen.
"Reine Assemblermagie" kann eben nicht alle Probleme lösen. Hier ist
man mit Hochsprache komfortabler.
Zudem gibt es keinen Grund, eigens neue Opcodes einzuführen, wenn
Compare B,A oder Compare A,const+1 oder Compare A,const-1 das Gewünschte
auszudrücken vermag.
Hier auf unnötige Opcodes zu verzichten ist weder "beschämend" noch
"unwürdig", sondern gutes ISA-Engineering. Wenn dein Assembler über
einen guten Präprozessor verfügt (wie z.B. der GNU-Assembler) kann
dieser einen Großteil erledigen. Keine Not dafür neue Instruktionen
oder Opcodes einzuführen und Silizium zu verpulvern.
Ich geh mal davon aus, dass du als Assembler-Profi eine ungefähre
Vorstellung davon hast, wie dicht oder dünn die AVR Opcode-Matrix
besetzt ist. Genau. Und genau das ist auch der Grund, warum es zum
Beispiel kein ADI oder ADCI gibt: Anstatt eine Konstante zu Addieren
kann man deren Komplement subtrahieren = X+const = X-(-const) und -const
aus const zu berechnen kostet nix da es nicht zur Laufzeit geschieht.
> Das allein ist schon höchst fragwürdig, wäre aber vielleicht (je nach> Leidensfähigkeit des Programmierers) für cp/cpc noch irgendwie> akzeptabel (für cpi schon nicht mehr, denn da kann man die Operanden> nicht einfach tauschen).
Braucht man auch nicht:
a <= const ist gleichbedeutend mit a < const+1
a >= const ist gleichbedeutend mit a > const-1
a < const ist gleichbedeutend mit a <= const-1
a > const ist gleichbedeutend mit a >= const+1
Ausnahme sind die Intervallgrenzen: a <= 0xff ist a < 0x100, aber wenn a
ein unsigend 8-Bit Wert ist dann ist der Vergleich trivial (dito für
andere Werte an Intervallgrenzen).
> Es ist aber vollkommen inakzeptabel für subi/sbci/sub/sbc, denn für die> immediate-Varianten geht wiederum der Trick mit dem Operandentausch> nicht,
Siehe oben.
> und bei dem Rest werden dann zwar die Flags entsprechend der> Erwartungen gesetzt, aber es kommt numerisch schlicht das falsche> Ergebnis raus (nämlich das Zweierkomplement des richtigen Ergebnisses).> Und das ist ganz sicher vollkommen inakzeptabel.
Wenn es "vollkommen inakzeptabel" ist dann wirst du auf dieser Ebene
nicht operieren da "vollkommen inakzeptabel". Also erübrigt sich jede
inhaltliche Diskussion für dich und du kannst dich entspannt
zurücklehnen.
> Zumal Atmel in seiner unerforschlichen Weisheit keine 'cpci'-Operation> spendiert hat,
Abermals: Es ist nicht beliebig viel Platz in der Opcode-Matrix, und
Instruktionen mit Konstante wie ORI fressen 12 Bits d.h. 1/16 der
Matrix! Alleine ANDI, ORI, SUBI, SBCI, CPI, RJMP, RCALL, LDD, STD,
IN+OUT belegen jeweilt 1/16, zusammen also 10/16 > 60% aller Opcodes!
> man also beim Vergleich gegen Konstanten mit mehr als> Byte-Größe sogar gezwungen ist, die potentiell destruktive Subtraktion> zu benutzen.
Mit CPI+SBCI bleibt zumindest das LSB erhalten, oder man nimmt
LDI+CPI+CPC. Irgendeinen Tod muss man sterben bei so einer kleinen
Matrix...
Johann L. schrieb:> Hier auf unnötige Opcodes zu verzichten ist weder "beschämend" noch> "unwürdig", sondern gutes ISA-Engineering.
Ich forderte nicht den Verzicht auf unnötige Op-Codes, sondern den
Verzicht auf unnötige und fehlerhafte Mnemnonics!
> Ich geh mal davon aus, dass du als Assembler-Profi eine ungefähre> Vorstellung davon hast, wie dicht oder dünn die AVR Opcode-Matrix> besetzt ist.
Da kannst du tatsächlich getrost von ausgehen. Also von der Tatsache,
dass mir nur zu bewußt ist, dass diese Matrix eben nicht gerade dünn
besetzt ist. Ganz so, wie es bei einem RISC-Core auch sein sollte...
> Genau. Und genau das ist auch der Grund, warum es zum> Beispiel kein ADI oder ADCI gibt ...
Laber, laber, sülz. Erklärt alles nicht die fiktiven Branch-Ops! Genau
das ist der Punkt, an dem meine "Verschwörungstheorie" als einzige
mögliche Erklärung über bleibt, weil die Dinger halt tatsächlich
keinerlei praktischen Nutzen haben, sondern eher kontraproduktiv sind.
Und das hat mit der Besetzungsmatrix der tatsächlichen Opcodes auch
absolut nix zu schaffen. Weil halt der Assembler fieserweise den Befehl
auf den instruction space abbildet, der tatsächlich existiert, ohne aber
zu kontrollieren, dass die Randbedingungen dafür eingehalten wurden.
: Anstatt eine Konstante zu Addieren
> kann man deren Komplement subtrahieren = X+const = X-(-const) und -const> aus const zu berechnen kostet nix da es nicht zur Laufzeit geschieht.>>> Das allein ist schon höchst fragwürdig, wäre aber vielleicht (je nach>> Leidensfähigkeit des Programmierers) für cp/cpc noch irgendwie>> akzeptabel (für cpi schon nicht mehr, denn da kann man die Operanden>> nicht einfach tauschen).>> Braucht man auch nicht:> a <= const ist gleichbedeutend mit a < const+1> a >= const ist gleichbedeutend mit a > const-1> a < const ist gleichbedeutend mit a <= const-1> a > const ist gleichbedeutend mit a >= const+1>> Ausnahme sind die Intervallgrenzen: a <= 0xff ist a < 0x100, aber wenn a> ein unsigend 8-Bit Wert ist dann ist der Vergleich trivial (dito für> andere Werte an Intervallgrenzen).>>> Es ist aber vollkommen inakzeptabel für subi/sbci/sub/sbc, denn für die>> immediate-Varianten geht wiederum der Trick mit dem Operandentausch>> nicht,>> Siehe oben.>>> und bei dem Rest werden dann zwar die Flags entsprechend der>> Erwartungen gesetzt, aber es kommt numerisch schlicht das falsche>> Ergebnis raus (nämlich das Zweierkomplement des richtigen Ergebnisses).>> Und das ist ganz sicher vollkommen inakzeptabel.>> Wenn es "vollkommen inakzeptabel" ist dann wirst du auf dieser Ebene> nicht operieren da "vollkommen inakzeptabel". Also erübrigt sich jede> inhaltliche Diskussion für dich und du kannst dich entspannt> zurücklehnen.>>> Zumal Atmel in seiner unerforschlichen Weisheit keine 'cpci'-Operation>> spendiert hat,>> Abermals: Es ist nicht beliebig viel Platz in der Opcode-Matrix, und> Instruktionen mit Konstante wie ORI fressen 12 Bits d.h. 1/16 der> Matrix! Alleine ANDI, ORI, SUBI, SBCI, CPI, RJMP, RCALL, LDD, STD,> IN+OUT belegen jeweilt 1/16, zusammen also 10/16 > 60% aller Opcodes!>>> man also beim Vergleich gegen Konstanten mit mehr als>> Byte-Größe sogar gezwungen ist, die potentiell destruktive Subtraktion>> zu benutzen.>> Mit CPI+SBCI bleibt zumindest das LSB erhalten, oder man nimmt> LDI+CPI+CPC. Irgendeinen Tod muss man sterben bei so einer kleinen> Matrix...
c-hater schrieb:> Erklärt alles nicht die fiktiven Branch-Ops!
Kann es auch nicht, denn die sind nur in deinem Kopf und sonst nirgends
auf der Welt. Damit trifft "fiktiv" es immerhin ganz gut, denn du
bildest dir sie nur ein. Du bist aber der einzige, der die sieht.
> Weil halt der Assembler fieserweise den Befehl auf den instruction space> abbildet, der tatsächlich existiert, ohne aber zu kontrollieren, dass die> Randbedingungen dafür eingehalten wurden.
Wenn du einen BRGE hinschreibst, bildet er auch den genau ab. Es gibt
weder irgendeinen anderen Mnemonic, der auf den selben Opcode abgebildet
wird, noch gibt es irgendeinen anderen Opcode, auf den BRGE abgebildet
wird. Deine "fiktiven Instruktionen" bildest du dir wie gesagt nur ein!
Rolf M. schrieb:> Kann es auch nicht, denn die sind nur in deinem Kopf und sonst nirgends> auf der Welt. Damit trifft "fiktiv" es immerhin ganz gut, denn du> bildest dir sie nur ein. Du bist aber der einzige, der die sieht.
Ähemm. Atmel selber sah es so und dokumentierte es explizit. Nämlich in
genau dem Ding, was ich geposteted habe.
Du verweigerst hier aber ganz schon die Realität, wenn du nichtmal die
Original-Dokumentation des Herstellers des Zielsystems gelten läßt...
c-hater schrieb:>> Kann es auch nicht, denn die sind nur in deinem Kopf und sonst nirgends>> auf der Welt. Damit trifft "fiktiv" es immerhin ganz gut, denn du>> bildest dir sie nur ein. Du bist aber der einzige, der die sieht.>> Ähemm. Atmel selber sah es so und dokumentierte es explizit. Nämlich in> genau dem Ding, was ich geposteted habe.
Nein! Da sind weder fiktive Befehle dokumentiert, noch welche, die was
anderes tun als man erwarten würde. Wie gesagt: Einbildung deinerseits.
> Du verweigerst hier aber ganz schon die Realität,
Du merkst offenbar nicht, dass du der einzige hier bist, der das tut.
Mir gehen aber langsam die Ideen aus, wie ich dir das klar machen
könnte. Ich hab's jetzt mehrmals versucht, aber das prallt wohl einfach
nur ab.
Wolfgang schrieb:> Der hater redet sich wiedermal um Kopf und Kragen. Herrlich.
Ja, ganz großes Kino. Da geht man mal für ein paar Stunden an die
frische Luft und verpaßt sowas :)