Guten Tag zusammen, ich beschäftige mich nun seit einiger Zeit mit dem programmieren von Displays im Assembler Code. Das Ganze funktioniert auch soweit ganz gut, also die grundlegenden Befehle habe ich soweit drauf. Nun zum eigentlichen Thema: Ich habe die Aufgabe erhalten ein vorgegebenes Programm von Assembler nach C zu übersetzen (Umfang ~1500 Zeilen Code). Da ich mich noch nicht genug mit Assembler auseinandergesetzt habe um das Programm zu verstehen, fällt es mir ziemlich schwer den Code nach C umzusetzen. Die Funktion des Programms soll, nach der Umsetzung in C, exakt gleich funktionieren. Angesprochene Bedienelemente und/oder Displays etc. sollen ohne Probleme, genau wie vorher, funktionieren. Diese Aufgabe ist aus meiner Sicht ziemlich unmöglich oder es dauert unverhältnismäßig lange. Gibt es die Möglichkeit gegebenen Assembler-Code in C umzusetzen, sodass die Funktionalität weiterhin gegeben ist? Es wird MPLAB X und ein PIC18F46K80 verwendet
:
Verschoben durch Admin
Ohne Verständnis für die Funktion des Programmes wird es wohl kaum gehen. Also Assembler lernen und das Programm analysieren. Es wird ja hoffentlich schon Sourcecode sein, so dass man mit Labelm und Kommentaren etwas anfangen kann. 1500 Zeilen ist ja auch recht harmlos, das bekommt man in 14 Tagen hin. Alternativ kann man die CPU in C nachbilden und das Programm dann in dieser Simulation laufen lassen. Dann wäre zumindest die Aufgabe formal erfüllt.
Talris schrieb: > Die Funktion des Programms soll, nach der Umsetzung in C, exakt gleich > funktionieren. Wenn die Funktion des Assembler-Programms genügend gut dokumentiert ist, lege den Assembler-Code beiseite und programmiere es neu in C - ohne in den Assember-Code zu schauen.
Frank M. schrieb: > lege den Assembler-Code beiseite und programmiere es neu in C - ohne in > den Assember-Code zu schauen. So würde ich es auch machen. Aufschreiben, wann das Programm was und wie macht und dann in C neu aufsetzen.
Talris schrieb: > Ich habe die Aufgabe erhalten ein vorgegebenes Programm von Assembler > nach C zu übersetzen Schmeiß den Assemblercode komplett weg. Du mußt die Funktion der Software kennen, mehr nicht. Dann erstelle einen PAP danach und wenn der PAP logisch richtig funktioniert, setze ihn in C um.
Assemblercode ist immer besser, weil es effizienter ist, aber es ist schwerer das Programm zu erweitern. 1 zu 1 Umsetzung von ASM zu Compiler ist nicht möglich weil jeder Compiler anderen Code erzeugt.
Kenner schrieb: > Assemblercode ist immer besser Bitte nicht schon wieder... Das hatten wir bereits unendlich mal.
Das ist aber die Tatsache, dass Assemblercode besser ist. In Assembler kannst du alles machen was die CPU unterstützt.
Kenner schrieb: > Das ist aber die Tatsache, dass Assemblercode besser ist. In Assembler > kannst du alles machen was die CPU unterstützt. Ja schön. Da hast du was davon, wenn du dir mit Vollgas und mit allem was die CPU kann an allen Ecken und Enden selbst in den Fuss schiesst, weil du wieder mal irgendwo einen Pop zu einem Push vergessen hast oder in einer Subroutine übersehen hast, dass du ein Register, dass 3 Aufrufebenen weiter draussen gebraucht wird, nicht benutzen darfst. Letzten Endes schenkst sich hinreichend komplexer Code in Assembler nichts mehr gegen einen gleichwertigen C Code. Und zwar deshalb, weil man als Programmierer all die Details gar nicht mehr überlicken kann, die man aber wissen müsste um wirklich jeden überflüssigen Taktzyklus loszuwerden. Von der ausufernden Entwicklungszeit reden wir mal gar nicht. Was bei 200 Zeilen Assembler Programmen noch funktioniert, funktioniert bei 200-tausend Zeilen so nicht mehr. Die werden schon wissen, warum sie das Programm neu geschrieben haben wollen. Die meisten Profis hier im Forum haben auch einen hinreichend begründeten Verdacht, was das eigentliche Problem sein wird: Code-Wartung. Die meisten von uns waren alle schon an dem Punkt, an dem ein 3 Jahre alter Assembler-Code hätte erweitert werden sollen und kein Schwein blickt mehr durch.
:
Bearbeitet durch User
Kenner schrieb: > Das ist aber die Tatsache, dass Assemblercode besser ist. Das ist aber nicht Thema dieses Threads. Die Aufgabe ist hier: Assembler-Programm neu zu schreiben in C. Das wird schon seinen Grund haben. Was nützt hier Deine reingekippte "Tatsache"? Nichts. Aber Hauptsache, Du hast es erwähnt.
Ich würde folgendermaßen vorgehen. Den Assemblercode zeilenweise analysieren. Lassen sich Zeilen zusammenfassen, so fügst Du den C-Code in Form eines Kommentars ein. Geht das nicht, so musst Du den Assemblercode in C nachbilden. Anfangen würde ich mit den Unterfunktionen. Sinnvolle Namen wären nicht schlecht. Eine Unterfunktion gleich eine C-Funktion. Im zweiten Schritt würde ich alle Zeilen des Assemblercodes, die ich ersetzt habe, ihrerseits Ausklammern. Am Ende sollte die Datei funktionsleer sein. Den ganzen Kram kannst Du dann in eine C-Datei überführen, die auskommentierten C-Zeilen zu C-Befehlen freigeben und glücklich werden. Natürlich bleibt noch die Möglichkeit, den gesamten Code zu erfassen und direkt in C nachzubilden. Die Chance ist dann aber groß, dass dann der Schlenker in Zeile 122 nicht mehr vorhanden ist.
Der Weg führt über das Verständnis der Funktion, des grundsätzlichen Aufbaus des Programms, dessen funktionale Gruppen und wie und mit welchen Algorithmen Dinge gelöst werden. Das ist wie die Arbeitsweise einer Industrieanlage verstehen zu wollen, indem man sich jede einzelne Schraube und jede Beilagscheibe ansieht. Das bringt nichts. Verständnis kriegt man erst, wenn man all diese Details beiseite lässt und sich erst mal die groben Gruppen ansieht, das Zusammenspiel der Komponenten und erst dann, wenn man weiss, welcher Funktionsblock welche Aufgabe hat, erst dann macht es Sinn sich anzusehen, wie das im Inneren funktioniert - durchaus dann auch runter bis zu der Auslegunsebene auf der man dann auch versteht, warum an dieser Stelle eine M12 Schraube benutzt wurde. Aber mit der M12 Schraube anzufangen bringt dich nicht weiter, wenn du rausfinden willst, wie eine Raffinerie aus Röhol Benzin gewinnt. Das große Problem bei einem Assembler Programm ist natürlich, dass du kein Flugzeug hast um damit ein paar mal über die Raffinierie zu fliegen, sondern immer nur einen kleinen Ausschnitt siehst. Nichts desto trotz musst du es schaffen, aus diesen kleinen Ausschnitten das große Ganze der Maschine zusammenzusetzen, vor der du gerade stehst. Gottlob sind allerdings auch die meisten Assembler Programme nicht bis aufs letzte ausgereizt, so dass man auch dort einzelne funktionale Gruppen recht schnell erkennen kann. So zb wird es mit Sicherheit eine Textausgabe Funktion geben, und auch für den Aufbau eines Menüs und die Auswertung von Eingabeelementen gibt es nicht unendlich viele verschiedene Möglichkeiten. Kennt man die prinzipielle Bedienung, dann findet man vieles davon auch im Code wieder. Schwierig zu erkennen sind des öfteren Querzusammenhänge, wenn zb eine Operation davon abhängt, ob 5 Zeilen davor ein Carry Flag gesetzt wurde oder nicht. Das kann dann schon recht trickreich sein. Dann ist es recht hilfreich, wenn man im Vorfeld schon eine gewisse Vorstellung hat, was in diesem Code Abschnitt eigentlich geschehen müsste. Womit wir wieder beim groben Überblick wären, der schon vorhanden sein sollte.
:
Bearbeitet durch User
Ja, wie gesagt, das ist gar nicht so einfach. Es ist so ählich wie ein Program geschrieben in z.B Basic ins C umzuschreiben, nur noch schwieriger.
Talris schrieb: > Ich habe die Aufgabe erhalten ein vorgegebenes Programm von Assembler > nach C zu übersetzen (Umfang ~1500 Zeilen Code). Da ich mich noch nicht > genug mit Assembler auseinandergesetzt habe um das Programm zu > verstehen, fällt es mir ziemlich schwer den Code nach C umzusetzen. Hey lass dich nicht entmutigen! Das scheint noch machbar zu sein. Wie die anderen schon sagten, DU brauchst den BIG VIEW auf die Software. Wie du das Programm übersetzt ist dir überlassen, mache direkten C-Code daraus oder einen PAP, den man später in C-Code übersetzt. Aus eigenen Erfahrungen würde ich den PAP Weg wählen, denn so kannst du oder ein anderer später deinen Weg besser nach vollziehen. Der Weg über den PAP sollte auch einfacher sein, da du dann den ASM-Code nicht mehr brauchst, wenn du den C-Code erstellst. Nutze SVN oder GIT (usw), damit du eine History hast, wann und wie du den Code(PAP) bearbeitest hast.
Das geht schon, man braucht nur 'ne Weile. Hab' ich früher (m68k) öfter gemacht. Meine Vorgehensweise war eigentlich immer die, Zeile für Zeile in C umzuschreiben. Das geht m.E. am besten, wenn man einen Compiler hat, der Inline Assembler unterstützt. Damit bringt man das Programm (in Assembler mit geschweiften Klammern und einem
1 | main() |
drumrum) erst mal zum Laufen und kann dann im nächsten Schritt Zeile für Zeile nach C umsetzen. Damit erhält man sich die Möglichkeit, zwischendurch immer mal wieder zu testen, ob es noch dasselbe macht wie vorher. Ein Testplan (oder gar Unit Tests) sind in der Phase sehr sinnvoll. Das Ergebnis des ersten "Durchlaufs" ist dann zwar formal C, aber meist noch kein vernünftiges, wartbares Programm. Jetzt kann man aber klassisch Refactoring betreiben und hat trotzdem jederzeit die Möglichkeit zu testen (ein Editor, der Refactoring vernünftig unterstützt, ist dabei Gold wert). Nach ausreichend vielen Wiederholungen kommt irgendwann ein einigermaßen gescheites Programm dabei raus. Mit anderen Ansätzen bin ich regelmäßig gescheitert, wenn ich zu große Brocken auf einmal angefaßt habe, war plötzlich ein Fehler drin und die Fehlersuche dauerte überproportional lang.
:
Bearbeitet durch User
Markus F. schrieb: > wenn ich zu große > Brocken auf einmal angefaßt habe, war plötzlich ein Fehler drin Der Trick an C ist nicht in großen Brocken zu denken, sondern in kleinen Modulen. Wenn ein Brocken nicht funktioniert, mußt Du ihn noch weiter unterteilen und die Teile testen, bis sie funktionieren. Wenn Du einen großen Brocken 1:1 umschreibst, bleibt es ein großer unwartbarer und nicht erweiterbarer Brocken, daran kann C nichts ändern. Wenn Du z.B ein LCD über I2C anschließt, machst Du keinen Brocken daraus sondern schreibst eine I2C-Treiber und einen LCD-Treiber. Und erst wenn Du beide für sich getestest hast, ruft der eine nur noch den anderen auf.
:
Bearbeitet durch User
Meinen Ansatz fußte natürlich darauf, dass kein optimal kommentierter Code vorhanden ist. Bei sauber kommentiertem Assembler sieht die Sache ganz schon ganz anders aus. Das letzte Mal, dass ich sowas gemacht habe, waren es ein ausgelesener Flash bzw. ein disassembliertes Programm. Lang, lang, ist’s her. Da braucht man, am Anfang, in der Hauptsache die Such- und Ersetzfunktionen, um ein paar, halbwegs kommentierbare Sprungmarken zu bekommen, bzw. so etwas wie eine Struktur.
Amateur schrieb: > Bei sauber kommentiertem Assembler sieht die Sache ganz schon ganz > anders aus. Ja, es gibt auch solche Ausnahmen, aber die Praxis sieht oft anders aus. Insbesondere beim PIC mit anfangs stark limitiertem HW-Stack wurden nur ungern Calls verwendet und lieber ellenlang Code hintereinander gepappt. Die ersten AVRs (AT90S1200) hatten auch nur einen HW-Stack, man was hab ich da geflucht.
Hallo und vielen für die zahlreichen Tipps :) Ich bin soweit dass ich die CALL Anweisungen erstmal in kleine C-Funktionen gefasst habe, um dann Stück für Stück das Assembler Programm nach C umzusetzen. Klappt auch ganz gut :D Bei einigen Befehlen komme ich allerdings noch ins straucheln. Wenn man das Ganze zum ersten mal macht, scheint das eine sehr komplizierte Angelegenheit zu sein (und mir wurde gesagt das dieses Programm das leichteste / simpelste ist^^). Aber zum Beispiel bei dieser Funktion hier (schreibe EEPROM):
1 | btfss PIR1,RCIF ; Receive Int. Flag gesetzt? |
2 | goto schreibe_EEPROM3 |
3 | call getRx_data |
4 | |
5 | bank2
|
6 | movfw RX_DATA |
7 | ; movwf DUMMY |
8 | movwf EEDATL |
9 | |
10 | bank3
|
11 | bcf INTCON,GIE |
12 | bcf EECON1, EEPGD |
13 | bsf EECON1, WREN |
14 | movlw 0x55 |
15 | movwf EECON2 |
16 | movlw 0xaa |
17 | movwf EECON2 |
18 | bsf EECON1, WR |
19 | bsf INTCON,GIE |
20 | bcf EECON1, WREN |
21 | bank0
|
Da fällt es mir noch schwer sowas umzusetzen bzw. wie sieht sowas in C aus? Brauch ich das in C überhaupt? Denn C arbeitet nicht mit z.B bank0..bank4. Aber alles in allem ist es doch schon ganz ok. Vielen Dank euch allen :)
Talris schrieb: > Denn C arbeitet nicht mit z.B > bank0..bank4. Das macht dann eben der Compiler für dich. Im Assembler Code hätte man aber auch besser so was wie BANKSEL RX_DATA als bank2 (auf der vermutlich RX_DATA liegt) benutzt. Das Beispiel ist jetzt aber so nicht in einem Stück kopiert, oder? Sieht irgendwie sehr seltsam aus. Was macht getRx_data? Der Ausschnitt ist zu kurz, du müsstest die komplette Funktion posten.
:
Bearbeitet durch User
Talris schrieb: > Aber zum Beispiel bei dieser Funktion hier (schreibe EEPROM): ... Die Codesequenz sieht für mich erst mal einigermaßen sinnvoll aus (ich nehme an, hier werden Daten am seriellen Port empfangen und ins EEPROM geschrieben?). Bei mir würde das (im ersten Ansatz) so aussehen:
1 | if (! (PIR1 & RCIF)) |
2 | {
|
3 | /* nothing on serial port */
|
4 | return; /* nehme an, schreibe_eeprom3 ist der Fehlerausgang? */ |
5 | }
|
6 | |
7 | EEDATL = get_rx_data(); /* fetch a byte from RXDATA (serial port) */ |
8 | |
9 | INTCON &= ~GIE; /* disable all interrupts */ |
10 | EECON1 &= ~EEPGD; |
11 | EECON1 |= WREN; /* enable write to EEPROM */ |
12 | |
13 | EECON2 = 0x55; /* data EEPROM write sequence init */ |
14 | EECON2 = 0xaa; |
15 | |
16 | EECON1 |= WR; /* initiate write */ |
17 | INTCON |= GIE; /* enable interrupts */ |
18 | |
19 | EECON1 &= ~WREN; /* deny EEPROM writes */ |
Da mögen noch einige Fehler drin sein, PIC ist nicht gerade meine Stärke. Jetzt würde ich das mal compilieren und testen. Schöner machen kann man's immer noch. P.S.: ich hab' dafür übrigens ungefähr 5 Minuten gebraucht, obwohl PIC's mir einigermaßen fremd sind. Sagen wir mit Testen zehn, dann müsstest Du nach 2 Arbeitstagen mit 1500 Zeilen durch sein ;)
:
Bearbeitet durch User
Markus F. schrieb: > EECON1 &= ~WREN; /* deny EEPROM writes */ Vorsicht bei solchen Sachen. Es kommt drauf an, ob man bei
1 | bcf EECON1, WREN |
die Bitnummer angibt oder eine Bitmaske. In C (ohne Erweiterungen) gibt man immer eine Bitmaske an. WEnn das also im Assembler eine Bitnummer ist, dann schreibt sich das als
1 | EECON1 &= ~( 1 << WREN ); /* deny EEPROM writes */ |
Ob die Angabe WREN im Assemblercode eine Bitnummer oder eine Bitmaske ist, lässt sich am einfachsten feststellen, indem man in der Assembler Doku den Abschnitt über BCF aufschlägt und ganz einfach nachliest.
Karl H. schrieb: > Vorsicht bei solchen Sachen. > > Es kommt drauf an, ob man bei bcf EECON1, WREN > die Bitnummer angibt ... Ja, das ist eine Nummer. Bei den aktuellen MCHP Compilern wäre das in C:
1 | EECON1bits.WREN = 0; // bcf -> bit clear (in) file |
Karl H. schrieb: > Es kommt drauf an, ob man bei bcf EECON1, WREN > die Bitnummer angibt oder eine Bitmaske. Stimmt, da muß man aufpassen. Die MPLAB-Compiler verwenden Bitfelder. Ich verwende für PIC den SCC und habe eigene Includes, die Bitmasken definieren.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.