Forum: Compiler & IDEs Von Assembler nach C


von Ingmar H. (bolliq)


Lesenswert?

Hallo Leute,

bin grad dabei ein Assembler-Projekt in ein C-Projekt umzuprogrammieren. 
Da ich nicht so der Assemblerkünstler bin habe ich da meine probleme. 
Ich bräuchte ein paar tipps wie ich am besten anfangen soll bzw. dann 
auch weitermachen. Hab jetzt schon mittlerweile die ganzen .equ,..., 
usw. als makros in C und fange jetzt an die ganzen Funktionen zu 
übersetzen.
Das Assembler-Projekt läuft auf einem ATmega169 Controller und soll auch 
in C auf diesem Controller laufen.

Jede art von Rat und Hilfe sind mir willkommen



ingmar

von Peter II (Gast)


Lesenswert?

Ingmar H. schrieb:
> Jede art von Rat und Hilfe sind mir willkommen

man sollte verstehen was Programm macht und es dann NEU in C schreiben. 
eine umsetzung von ASM zu C macht wenig sinn auf codebasis.

von Ingmar H. (bolliq)


Lesenswert?

was das programm macht versteh ich schon... ich hab jetzt z.B. probleme 
den
code richtig zu übersetzen weil es doch so ein paar unterschiede gibt.

Beispiel:

         PUSH  AKKU_1
   PUSH  AKKU_2
   LD  AKKU_1, X
   INC  XL
   LD  AKKU_2, X
   DEC  XL
   CALL  DISP_HEX
   POP  AKKU_2
   POP  AKKU_1
********************************************************************

          LDI  ZL, LOW(ST_OFFSET*2)
    LDI  ZH, HIGH(ST_OFFSET*2)
***********************************************************************

PUSH und POP kann ich verachlässigen oder??
wie würde   LD  AKKU_1, X    und
LDI  ZL, LOW(ST_OFFSET*2) in C aussehen?

von EGS_TI (Gast)


Lesenswert?

Ingmar H. schrieb:
> was das programm macht versteh ich schon

Ja also, dann kannst du ja wohl auch die Funktionalität in C 
programmieren.

von Oliver (Gast)


Lesenswert?

Ingmar H. schrieb:
> LD  AKKU_1, X

http://www.atmel.com/Images/doc0856.pdf

Im übrigen: Vergiß es.

Peter II schrieb:
> eine umsetzung von ASM zu C macht wenig sinn auf codebasis.

So ist es.

Oliver

von Ralf (Gast)


Lesenswert?

Ich schließe mich den Vorrednern an. In Assembler arbeitest du mit 
Registern, dem Akku (sofern vorhanden) und ein paar Speicherstellen).
In C arbeitest du mit Variablen (= Speicherstellen), und nicht mit den 
Registern. Das nimmt dir der C-Compiler ab.

Du sagst du weisst was das Programm macht. Dann notiere dir dazu den PAP 
(Programm-Ablauf-Plan) oder etwas äquivalentes, was dir eben den Ablauf 
passiert, aber auf Basis des "was passiert", nicht "wie's passiert".

An deinem o.g. Code-Auszug wäre das dann also nicht "Lade Akku nach...", 
etc., sondern "Zeige auf Display in Hex-Darstellung" (dem Call nach zu 
urteilen).
Wenn du das gemacht hast, dann hast du eine von der Sprache unabhängige 
Beschreibung des Programms. Und das wiederum setzt du dann in C um:
1
void DisplayHex(unsigned char Value) {
2
  //extrahiere High-Nibble
3
  //wandle Nibble in ASCII-Zeichen um
4
  //stelle ASCII-Zeichen auf Display dar
5
  //dasselbe für's Low-Nibble
6
}

Ralf

von Programmierer (Gast)


Lesenswert?

Ingmar H. schrieb:
> PUSH und POP kann ich verachlässigen oder??
> wie würde   LD  AKKU_1, X    und
> LDI  ZL, LOW(ST_OFFSET*2) in C aussehen?

Falls es dir noch nicht klar ist: Du musst die Funktionalität 
nachbilden, nicht den Maschinencode. Der hier gezeigte Codeausschnitt 
könnte mit der Standardfunktion printf() nachgebildet werden, odet du 
linkst deine uart Bibliothek dazu und verwendest deine uart_putc() 
Funktion oder ... du verstehst wie ich's meine?!

von Christian B. (casandro)


Lesenswert?

Wenn Du grundlegende Probleme mit Assembler hast, solltest Du Dich 
vielleicht erst mal in einen Assembler einarbeiten, bevor Du C 
programmierst. C ist keine Hochsprache, es ist eine Art 
"Makro-Assembler". Arrays gibts in C nicht, das sind nur Zeiger, und 
wenn Du über das Ende hinaus zugreifst, greifst Du auf was auch immer 
dahinter liegt zu. Wenn Dein Array auf dem Stack liegt (z.Bsp. bei 
lokalen Variablen) so liegt nach dem Array die Rücksprungadresse.

Falls Du aber wirklich eine 1:1 Umsetzung haben willst, dann scheibe Dir 
doch einfach ein Programm, welches das macht.
Im Prinzip musst Du nur das Programm zeilenweise einlesen, und die 
Kommentare entfernen, sowie den #includes folgen. #defines kannst Du als 
Makros übersetzen.
Zeilen mit
.cseg
und
.dseg
Schalten zwischen Programmspeicher und Datenspeicher um. Abhängig davon 
musst Du bei Labels entweder Sprunglabels in C oder Variablen anlegen.

Gut ist das dann nicht, aber die Aufgabe wäre erfüllt. Ich würde aber in 
Deiner Situation mir 90% der Zeit nehmen den existierenden Code zu 
verstehen, und ihn in der restlichen Zeit neu implementieren. Danach 
wirst Du besseren C-Code schreiben als vorher.

von Karl H. (kbuchegg)


Lesenswert?

onno und Christian Berger.

Könnt ihr euch bitte mit eurem Halbwissen über C verziehen? Das gilt 
ganz besonders für onno.

Danke.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ingmar H. schrieb:
> was das programm macht versteh ich schon... ich hab jetzt z.B. probleme
> den
> code richtig zu übersetzen weil es doch so ein paar unterschiede gibt.
>
> Beispiel:
>
>    PUSH  AKKU_1
>    PUSH  AKKU_2
>    LD  AKKU_1, X
>    INC  XL
>    LD  AKKU_2, X
>    DEC  XL
>    CALL  DISP_HEX
>    POP  AKKU_2
>    POP  AKKU_1

Das lässt sich so nicht "übersetzen".  Hier wird ein 16-Bit Wert 
indirekt über X geladen und vermutlich an DISP_HEX übergeben.

Ob der Wert übergeben wird — d.h. in DISP_HEX verwendet wird — ist an 
dem Code nicht zu sehen, ebenso ob DISP_HEX etwas zurückliefert oder 
Seiteneffekte hat.

Die Registerzuordnung in einem C-Programm erledigt der Compiler.  Das 
ist ja auch einer der Gründe, eine Compiler einzusetzen :-)

Einen 16-Bit Wert aus dem RAM zu lesen und damit eine Funktion 
aufzurufen sieht in C so aus:
 
1
#include <stdint.h>
2
3
extern void disp_hex (uint16_t);
4
5
void f1 (uint16_t *addr)
6
{
7
    disp_hex (*addr);
8
}

und avr-gcc übersetzt das zB so:
 
1
f1:
2
  movw r30,r24   ; , addr
3
  ld r24,Z   ; , *addr_1(D)
4
  ldd r25,Z+1   ; , *addr_1(D)
5
  jmp disp_hex
 
Du kannst also versuchen, dieses kleine C-Beispiel zu verstehen und auf 
deinen Fall anzupassen oder in eine größere Funktion einzubette.

>     LDI  ZL, LOW(ST_OFFSET*2)
>     LDI  ZH, HIGH(ST_OFFSET*2)

Dieses Beipiel ist mindestend genauso übel.

Ist der nach Z geladene Wert eine Adresse?
Oder eine Konstante, die zur Compilezeit bekannt ist?
Oder der Index in ein Array aus 16-Bit Werten?

Im einfachsten Fall ist der C-Code
 
1
#define ST_OFFSET (12345-123)
2
3
uint16_t f2 (void)
4
{
5
    return 2 * ST_OFFSET;
6
}

und wird zu:
 
1
f2:
2
  ldi r24,lo8(124)
3
  ldi r25,lo8(95)
4
  ret
 
Die Registerzuordnung ist wie gesagt Aufgabe des Compilers.

Ist ST_OFFSET ein Index in ein 16-Bit Array, und wird auf dem Array an 
dieser Stelle gelesen, dann:
 
1
extern uint16_t array[];
2
3
uint16_t f3 (void)
4
{
5
    return array[ST_OFFSET];
6
}
 
und das compiliert zu
 
1
f3:
2
  ldi r30,lo8(array+24444)
3
  ldi r31,hi8(array+24444)
4
  ld r24,Z   ; , array
5
  ldd r25,Z+1   ; , array
6
  ret
 
Als erstes musst du also das Programm abstrahieren und von der konkreten 
Registerverwendung, den Instruktionen, etc. loskommen und dir klarmachen

• Welche (globalen) Objekte und Datenstrukturen gibt es?
• Welche Funktion erfüllt welche Aufgaben?
• Welche Parameter bekommen die Funktionen?
• Und was geben sie zurückgeben?
• Welche globalen Variablen werden sie (falls überhaupt)
• Wie werden asynchrone Ereignisse (IRQs) verdaut?
• Was ist eine sinnvolle Strukturierung von alledem?

von Ingmar H. (bolliq)


Lesenswert?

Danke ich werds versuchen umzusetzen....

von R2D2 (Gast)


Lesenswert?

@ Christian Berger

Seit wann ist C keine Hochsprache ?

Eine Hochsprache ist jede Programmiersprache die über Assembler 
hinausgeht.

Arrays als Datenstruktur gibt es sehr wohl in C.
Man kann aber beispielsweise einen C-String in Form eines Arrays anlegen
1
char hallo[] = "halloWelt";
 zum durchlaufen index inkrementieren bzw. dekrementieren (Index 
entspricht Speicheradresse).
oder so:
1
 char *hallo = "halloWelt";
 hier pointer inkrementieren bzw. dekrementieren.

über sizeof(hallo)/sizeof(char) überlauf abfangen.

gruß R2D2

von asmhobbyist (Gast)


Lesenswert?

Man kann wie oben schon geschrieben, einfach nur die Funktionalität 
nachahmen, ohne groß auf den Assemblercode zu gucken.

Wenn man aber z.B. wissen möchte, welcher Algorithmus eingesetzt wird, 
oder ob Hardware"tricksereien" (Hardwareverständnis) im Spiel sind o.ä. 
dann sollte man möglichst den Algo kennen, wie auch Assemblergrundlagen 
zum Lesen des Asm-Codes.

Ich würde die Gelegenheit beim Schopfe packen, und gleich 
Assemblergrundlagen lernen und mit der Aufgabe vertiefen.
Und man versteht den Assemblercode oft sehr viel besser, wenn man weiß, 
um was es geht. Assembler lernt sich normalerweise leicht und schnell, 
weil ja kaum Abstrakta im Spiel sind. Nur ein wenig Zeit sollte man sich 
geben und die ein oder andere, grundlegende Lowlevelsubroutine 
verstanden haben.

Einzelne Funktionen kann man sich isoliert im Debugger angucken und 
versuchen, besser zu verstehen.

Und auch im Manual des jeweiligen Assemblers lassen sich meist wertvolle 
Hilfen zum Programmverständnis oder Programmiertechniken finden.

)Und wenn die Assemblerroutine sehr gut ist, warum dann nicht drinlassen 
und von C aus aufrufen?
--> hier spielt auch das "Warum" von Asm nach C eine gewisse Rolle und 
in dem gleichen Zusammenhang auch die Nützlichkeit von C zurück nach 
Asm)

von Ulli N. (Gast)


Lesenswert?

Peter II schrieb:
> man sollte verstehen was Programm macht und es dann NEU in C schreiben.
> eine umsetzung von ASM zu C macht wenig sinn auf codebasis.

Abgesehen von der Rechtschreibung, ist das die einzig richtige 
Einschätzung der Sachlage.

von asmhobbyist (Gast)


Lesenswert?

Es gab auch mal einen generellen Dr. Dobbs Guru Blog Artikel von Walter 
Bright zu diesem Thema, die Seite finde ich gerade nicht, aber hier der 
betreffende Inhalt:
http://www.allhatter.com/archive/index.php/t-33853.html

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.