Hallo,
ich möchte eine switch/case anweisung in Assmebler realisieren und habe
auch den entsprechenden Beitrag dazu gelesen:
Beitrag "switch case mit assembler?"
soweit ist das auch klar. Ich habe allerdings das Problem, das die
Adressen meiner Sprungtabelle nicht linear hintereinander liegen, und
ich somit die Sprungadresse nicht vernünftig berechnen kann.
Generell sieht es bei mir wie folgt aus :
1
table_ARITH:
2
AJMPCPUTEST_ARITH0
3
AJMPCPUTEST_ARITH1
4
AJMPCPUTEST_ARITH2
5
AJMPCPUTEST_ARITH3
6
AJMPCPUTEST_ARITH4
7
AJMPCPUTEST_ARITH5
8
AJMPCPUTEST_ARITH6
9
AJMPCPUTEST_ARITH7
10
AJMPCPUTEST_ARITH8
11
AJMPCPUTEST_ARITH9
12
13
MOVdptr,#table_ARITH
14
MOVA,R1
15
JMP@a+dptr
wenn ich mir die Adressen der Sprungmarken in der *.map betrachte, haben
die meist eine Differenz von ca. 20(dec) aber eben nur ca. wie kann ich
diese nun linear anordnen?
MFG
Wo ist das Problem?
Du arbeitest mit Labels, also ist es vollkommen wurscht, wohin
gesprungen wird. Der Assembler ersetzt dann schon das Label durch die
richtige Adresse.
Bei AJMP muß das Ziel nur in der selben 2k Page sein.
Aber Du solltest den Index *2 nehmen, da ein AJMP 2 Byte benötigt:
Das Problem besteht darin, dass R1 quasi ein Counter ist, der immer um
eine erhöht wird und anhand dessen dann immer zum entsprechnenden
CPUTEST_ARITH gesprungen werden soll. Momentan werden die Marken
Durcheinander bzw garnicht aufgerufen.
M.W. schrieb:
> Das Problem besteht darin, dass R1 quasi ein Counter ist, der immer um> eine erhöht wird und anhand dessen dann immer zum entsprechnenden> CPUTEST_ARITH gesprungen werden soll. Momentan werden die Marken> Durcheinander bzw garnicht aufgerufen.
Hat R1 tatsächlich den Wert, den du denkst das es haben sollte?
Die 'Multiplikation' mit 2 hast du in Peters Code gesehen?
M.W. schrieb:
> Das Problem besteht darin, dass R1 quasi ein Counter ist, der immer um> eine erhöht wird ...
Dann hab ich ja die Lösung schon vorhergesehen.
> Momentan werden die Marken> Durcheinander bzw garnicht aufgerufen.
Ja.
Peter
Die Komplette Assembler Fuktion wird über ein C- Programm aufgerufen und
dieser wird der Zählwert einer For-Schleife übergeben.Und bei jedem
erneuten Aufruf wurde im Debugger R1 um eins erhöht. das müsste also
passen.Und eben anhand dieser Zählvariablen soll entschieden werden,
welche Marke aufgerufen werden soll. Bei den ersten beiden Malen klappt
es auch.Aber denn geraten die Aufrufe aus dem "Rythmus", der Zähler
inkrementiert aber weiterhin um eins.
M.W. schrieb:
> Die Komplette Assembler Fuktion wird über ein C- Programm aufgerufen und> dieser wird der Zählwert einer For-Schleife übergeben.
Ähm. Mir stockt der Atem.
Warum um alles in der Welt machst du das nicht in C selber?
Immer diese bescheuerte 'Ich kann das in C nicht richtig schreiben also
mach ichs in Assembler' Denkweise. Das ist doch Unsinn! Die Lösung
lautet nicht, wegen jedem Furz auf Assembler auszuweichen (den man
offensichtlich auch nicht gut genug kann), sondern C vernünftig zu
lernen.
Das musste ich jetzt einmal loswerden. In letzter Zeit häufen sich hier
nämlich genau diese Fälle, in denen Programmierer denken sie könnten
besser Assembler als ihr Compiler und wenn man sich den Code ansieht,
ist es offensichtlich nicht der Fall.
Mein erster Lösungsweg war die reinen Tests mit Inline Assembler zu
machen und das Switchkonstukt komfortabel in C zu machen aber so war
eben nicht die Aufgabenstellung.Wie gesagt meine Assemblerroutine
bekommt eine Variable übergeben anhand dieser ich auswerten muss welcher
Test ausgeführt werden soll.
Klaus schrieb:
> Gibt Karl Heinz einfach mal die Email Adresse vom Cheffe ;-)
Manchen Chefs sollte man wirklich mal die Leviten lesen.
Was soll das für einen Sinn haben?
Ich denke, die oberste Aufgabe eines Chefs ist es auch, sich um die
Finanzen zu sorgen. In der Zeit, in der hier an dem Assembler-Problem
gearbeitet wird, wäre es in C schon 3-mal fertig.
Normalerweise hat man eher den umgekehrten Fall: Der Chef hält einen
davon ab, ein Problem auf die 'interessante' Weise zu lösen anstatt auf
die banale Art, die zwar in den vom Chef überlegten 2 Sonderfällen
funktioniert (und das auch nur so lala) aber in allen anderen Fällen
grauslich abschmiert :-) Da kannst du dann auf die Typen einreden wie
auf eine kranke Kuh um ihm klar zu machen, dass er wieder mal viel zu
naiv denkt.
M.W. schrieb:
> Mein erster Lösungsweg war die reinen Tests mit Inline Assembler zu> machen und das Switchkonstukt komfortabel in C zu machen aber so war> eben nicht die Aufgabenstellung.Wie gesagt meine Assemblerroutine> bekommt eine Variable übergeben anhand dieser ich auswerten muss welcher> Test ausgeführt werden soll.
Problem mit der Registerbreite?
A ist 16 Bit breit?
(Kenn den Prozessor zu wenig)
Wie sieht dein Code jetzt aus? Die Tips von PeDa hast du umgesetzt?
Also das mit dem Faktor *2 hab ich so übernommen, hatte aber lediglich
den effekt, dass der Debugger sich nach dem dritten Aufruf im
Disassembly verrannt hat und immer nur noch MOV R5 ??? ausgeführt hat.
Wenn ich den Faktor 2 weglasse, kann ich zumindest die ersten 4 Tests
aufrufen. Allerdgins immer nur wenn der Zähler ein vielfaches der
gewünschten Marke ist. Sprich Test3 wird gestartet wenn Zähler 9
ist.Aber auch dann verrennt er sich ingendwann im sinnlosen Register hin
und her geschiebe.
M.W. schrieb:
> Also das mit dem Faktor *2 hab ich so übernommen, hatte aber lediglich> den effekt, dass der Debugger sich nach dem dritten Aufruf im> Disassembly verrannt hat
Dann musst du dir im Debugger die Register anzeigen lassen und die Werte
mit den Adressen im Speicher vergleichen.
Das Zeug einfach laufen zu lassen und aus dem Verhalten seine Schlüsse
zu ziehen, führt bei Assembler meistens zu nichts.
Ansehen was im Register steht, ansehen welchen Wert dptr hat. Händisch
addieren und ansehen was dann da raus kommt. Dann ein Single Step im
Debugger und nachsehen, wo der Program Counter beim indirekten Sprung
gelandet ist. Das muss dann in deiner Tabelle sein, wo der nächste,
eigentlich verzweigende Sprung steht. Von dort wieder einen Single Step
und du musst in an der Marke landen.
Und das wieder und immer wieder, beim nächsten Aufruf, mit neuem Wert in
R1 geht dasselbe Spielchen wieder von vorne los. Register ansehen, jedes
Bit kontrollieren.
Hilft nichts. So ist das bei Assmebler. Schönen Gruß an den Chef
M.W. schrieb:
> Sprich Test3 wird gestartet wenn Zähler 9> ist.Aber auch dann verrennt er sich ingendwann im sinnlosen Register hin> und her geschiebe.
Dann hast Du oben gelogen und Du verwendest kein AJMP, sondern LJMP.
LJMP ist 3 Byte groß und dann mußt Du *3 nehmen.
Man sollte allerdings Compiler nicht für blöder halten, als man selber.
Die nehmen ganz von sich aus ne Sprungtabelle bei nen Switch, wenn eine
bestimmte Anzahl aufeinanderfolgender Case überschritten wird.
Ich hatte mal den Fall, daß er im Interrupt ne Tabelle gemacht hat, was
dann teuer wurde durch die zusätzlichen PUSH/POP.
Ich hab ihn dann ausgetrickst mit lückenden Case und dann hat er brav
auf Vergleiche gewechselt, was in diesem Fall der schnelleren Code war.
Peter
P.S.:
Assembler und C zu mixen, heißt die Nachteile von beiden zu addieren.
M.W. schrieb:
> Copy/Paste lügt nie :D>> Könnte daran liegen, das eventuell FLAT-Mode aktiv und dann wären es> 3Byte. Zumindest laut Datenblatt
Sieh im Assembler Listing nach, wieviele Bytes der Assembler generiert
hat. Oder sieh im Debugger nach, ob an der bewussten Adresse der Opcode
für den Jump steht. Debugger können auch normalerweise einen Hex-Dump an
einer Speicheradresse machen. AUch dort müsste man sehen ob jetzt alle 2
oder alle 3 Bytes der Opcode für den Jump steht.
M.W. schrieb:
> Copy/Paste lügt nie :D
Wir reden aber doch vom 8051?
Schau mal ins Assemblerlisting.
Wenn Dein AJMP 3 Byte hat und das erste ist 0x02, dann ist es ein LJMP.
Es soll Assembler geben, bei denen man Befehle umdefinieren kann.
Peter
Hm daran lag es wohl. Ich hab jetzt grad mit 3 "multipiziert" und jetzt
scheint es zu funktionieren.
Lag scheinbar echt einfach nur daran, ob LAGRE oder FLAT. Dafür kenne
ich allerdings den Core nicht gut genug um darauf an anhieb zu kommen.
Thx für die Unterstüzng!!!
M.W. schrieb:
> Hm daran lag es wohl. Ich hab jetzt grad mit 3 "multipiziert" und jetzt> scheint es zu funktionieren.
Du machst hier einen Fehler.
'scheint zu funktionieren' ist in C manchmal gerade noch vertretbar. In
Assembler geht das aber nicht. Solange du nicht exakt nachvollziehen
kannst, wie es zu dem Problem kam, läufst du immer wieder Gefahr in
genau dasselbe Problem zu tappen.
Entweder der Jump hat 2 Byte oder er hat 3 Byte. Du musst in der Lage
sein, dass beim nächsten mal in kurzer Zeit feststellen zu können und
musst wissen worauf du achten musst. Einen Fehler einmal zu machen ist
nicht schlimm. Aber dann muss man dem Fehler bis auf Byteebene nachgehen
und sich Strategien ausdenken, wie man genau diesen Fehler kein zweites
mal macht.
Assembler: Man ist zwar mit jedem Bit auf Du und Du, hat dafür
allerdings auch die volle Verantwortung. Da gibt es kein einziges
Sicherheitsnetz mehr. Wenn du in einem 2 Byte Befehl einen Jump genau
zwischen die beiden Bytes hineinmachst, dann gibt es nichts und
niemanden, der dich daran hindert. Der Prozessor macht das einfach und
interpretiert dann zb ein Datenbyte als Opcode (also als Befehl).
M.W. schrieb:
> Ist jetzt halt echt die Frage ob die Assemblerrealiesierung sooo viel> schlanger und effektiver als eine C realisierung ist.
Ich weiß zwar nicht, was der Code an den jeweiligen Einsprungstellen
macht, aber zu 95% ist das wahrscheinlich nicht schneller oder
effektiver als das was ein C-Compiler erzeugt. Und wenn nicht, dann ist
der vom Compiler erzeugte Code maximal im einstelligen Prozentbereich
schlechter.
Die Jungs von der Compilerbaufraktion sind ja auch nicht auf den Kopf
gefallen. Die kennen die Prozessoren im Regelfall besser als die
Mehrheit der Assemblerprogrammierer.
Auf Assembler weicht man als Hochsprachenprogrammierer nur dann aus,
wenn wirklich jeder Taktzyklus zählt.
Eben da bin ich jetzt dran. Will verifizieren woran es lag. Aber wie
gesagt, dazu ist mir der Core nicht vertraut genug. Werd jetzt erstmal
gucken wie man FLAT und LAGRE behandelt und dann gucken, ob es
tatsächlich und an dem Faktor 3 bzw 3 lag.
M.W. schrieb:
> Eben da bin ich jetzt dran. Will verifizieren woran es lag. Aber wie> gesagt, dazu ist mir der Core nicht vertraut genug. Werd jetzt erstmal> gucken wie man FLAT und LAGRE behandelt und dann gucken, ob es> tatsächlich und an dem Faktor 3 bzw 3 lag.
Wie schon gesagt
Entweder mit dem Assembler Output Listing (in dem die Opcodes samt
Adressen aufgeführt sind) oder mit einem Hex-Dump des Speichers an der
bewussten Stelle lässt sich das ganz schnell verifizieren.
Die interessante Frage lautet dann allerdings:
Wie muss ich das im Assembler Code schreiben, so dass sich der Code
automatisch an FLAT bzw. LARGE anpasst :-)
>Auf Assembler weicht man als Hochsprachenprogrammierer nur dann aus,>wenn wirklich jeder Taktzyklus zählt.
Oder wenn Cheffe das als Weiterbildungsmaßnahme vorschreibt.
Oliver