Forum: Mikrocontroller und Digitale Elektronik Switch/case in Assembler mit Sprungtabelle


von M.W. (Gast)


Lesenswert?

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
      AJMP CPUTEST_ARITH0
3
      AJMP CPUTEST_ARITH1
4
      AJMP CPUTEST_ARITH2
5
      AJMP CPUTEST_ARITH3
6
      AJMP CPUTEST_ARITH4
7
      AJMP CPUTEST_ARITH5
8
      AJMP CPUTEST_ARITH6
9
      AJMP CPUTEST_ARITH7
10
      AJMP CPUTEST_ARITH8
11
      AJMP CPUTEST_ARITH9
12
13
      MOV dptr, #table_ARITH
14
      MOV  A,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

von Peter D. (peda)


Lesenswert?

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:
1
      MOV dptr, #table_ARITH
2
      MOV  A,R1
3
      add  a, r1
4
      JMP @a+dptr


Peter

von M.W. (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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?

von Peter D. (peda)


Lesenswert?

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

von M.W. (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von M.W. (Gast)


Lesenswert?

Cheffe will das so haben, da fang ich sicherlich keine Diskussion an, 
was einfacher ist :(
Kannst mir glauben ich würds auch lieber in C machen

von Klaus (Gast)


Lesenswert?

Gibt Karl Heinz einfach mal die Email Adresse vom Cheffe ;-)

von M.W. (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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?

von M.W. (Gast)


Lesenswert?

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.

von M.W. (Gast)


Lesenswert?

Kann es sein das die "Weite" der Sprünge ein Problem darstellt?

von Karl H. (kbuchegg)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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.

von M.W. (Gast)


Lesenswert?

Copy/Paste lügt nie :D

Könnte daran liegen, das eventuell FLAT-Mode aktiv und dann wären es 
3Byte. Zumindest laut Datenblatt

von Karl H. (kbuchegg)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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

von M.W. (Gast)


Lesenswert?

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!!!

von M.W. (Gast)


Lesenswert?

Ist jetzt halt echt die Frage ob die Assemblerrealiesierung sooo viel 
schlanger und effektiver als eine C realisierung ist.

von Karl H. (kbuchegg)


Lesenswert?

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).

von Karl H. (kbuchegg)


Lesenswert?

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.

von M.W. (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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 :-)

von Oliver (Gast)


Lesenswert?

>Auf Assembler weicht man als Hochsprachenprogrammierer nur dann aus,
>wenn wirklich jeder Taktzyklus zählt.

Oder wenn Cheffe das als Weiterbildungsmaßnahme vorschreibt.

Oliver

von M.W. (Gast)


Lesenswert?

Wenn ich es rausgefunden habe poste ich es :D

von Matthias L. (Gast)


Lesenswert?

>Oder wenn Cheffe das als Weiterbildungsmaßnahme vorschreibt.

In der heutigen ist asm-Programmierung eine WEITERbildung?

Kommt das vom Arbeitsamt?

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.