Hallo, ich habe einen Assembler-Quellcode Read_Fuses.s und möchte diesen in einem Quellcode .c einbinden und ausführen. Wie kann ich vorgehen? Im C-Code sind verschiedene einzelne Programmteile drin und ich möchte meinen Read_Fuses teil mit einbinden der aber in Assembler geschrieben ist. Vllt irgendwas mit " .global Hauptprogramm.c " ?
:
Bearbeitet durch User
Einfach getrennt übersetzen und dann zusammenlinken... Genaueres könnte man sagen, wenn du den Code zeigen würdest, und dazu auch noch verrätst, für welchen Prozessor und welche tool chain das sein soll. Oliver
Sorry, die boot.h:
1 | #include <avr/boot.h> |
2 | |
3 | uint8_t lo, hi, ex; |
4 | |
5 | lo = boot_lock_fuse_bits_get( GET_LOW_FUSE_BITS ); |
6 | hi = boot_lock_fuse_bits_get( GET_HIGH_FUSE_BITS ); |
7 | ex = boot_lock_fuse_bits_get( GET_EXTENDED_FUSE_BITS ); |
das ist der Assembler Code:
1 | #include <avr\io.h> |
2 | |
3 | /* Define the size of the flash page if not defined in the header files. */ |
4 | #ifndef FLASH_PAGE_SIZE |
5 | #define FLASH_PAGE_SIZE 512 |
6 | #endif /*FLASH_PAGE_SIZE*/ |
7 | |
8 | #define NVM_CMD_READ_FUSES_gc (0x07<<0) // Read fuse byte |
9 | |
10 | .section .text |
11 | .global Hauptprogramm |
12 | ReadFuseByte: |
13 | sts NVM_ADDR0, r24 |
14 | clr r24 |
15 | sts NVM_ADDR1, r24 |
16 | sts NVM_ADDR2, r24 |
17 | ldi r20, NVM_CMD_READ_FUSES_gc |
18 | rcall CommonCMD |
19 | movw r24, r22 |
20 | ret |
21 | |
22 | .section .text |
23 | CommonCMD: |
24 | sts NVM_CMD, r20 |
25 | ldi r18, CCP_IOREG_gc |
26 | ldi r19, NVM_CMDEX_bm |
27 | sts CCP, r18 |
28 | sts NVM_CTRLA, r19 |
29 | lds r22, NVM_DATA0 |
30 | lds r23, NVM_DATA1 |
31 | lds r24, NVM_DATA2 |
32 | clr r25 |
33 | ret |
34 | ; END OF FILE |
Diesen würde ich gerne in einem C-Quellcode ausführen mit void READ_FUSES()
:
Bearbeitet durch User
Dazu muss der verwendete Compiler und der Assembler bekannt sein, diese müssen kompatible object files erstellen können. Im assemblerkode müssen "Funktionen" den selben Aufrufkonventionen wie der C-Code folgen, das heisst alle verwendeten register sichern, reihenfolge der Argumente im stack beachten, ob der Aufrufer oder die Funktion die Argumente aus dem stack entfernt, etc. Ist alles im ABI Des Compilers zu finden. Im grunde genommen muss dann nurnoch ein Objektfile aus dem Assemblercode erstellt werden, in diesem muss das Funktionssymbol vorhanden sein, und dann linkt man es einfach mit Objektfiles zusammen die aus dem C-Code generiert worden sind.
Das ist mir zu kompliziert erklärt versteh ich leider nicht :(
Sercan E. schrieb: > Das ist mir zu kompliziert erklärt versteh ich leider nicht :( Geh zu http://www.nongnu.org/avr-libc/user-manual/index.html Lies dort. Am besten alles, mindestens aber: http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_reg_usage und http://www.nongnu.org/avr-libc/user-manual/group__asmdemo.html Jetzt weißt du in welchen Registern der C-Compiler Argumente an Funktionen übergibt und in welchen Registern er Rückgabewerte erwartet. Jetzt kannst du den Assembler-Code entsprechend schreiben (sofern er nicht bereits korrekt ist - auf den ersten Blick sieht er so aus). Ferner mußt du alle Symbole (Variablen, Funktionen) die von C aus sichtbar sein sollen, im Assembler-Code als .global deklarieren. Und du mußt dir ein .h File schreiben, in dem die Assembler-Funktionen deklariert sind (also Name, Aufrufparameter und Returntyp). Und wenn du das alles hast, brauchst du in C einfach nur das .h File zu #includen und kannst die Funktion von C aus aufrufen. Das Assembler-File mußt du natürlich mit übersetzen und das entstandene Objectcode-File mit dem Rest zusammenlinken. Nicht trivial, aber machbar. Wesentlich weniger aufwendig wird das ganze, wenn du den Rumpf der Assembler-Funktion einfach als Inline-Assembler in eine C-Funktion kopierst. Auch dazu mußt du etwas Doku lesen.
Sercan E. schrieb: > Diesen würde ich gerne in einem C-Quellcode ausführen mit void > READ_FUSES() Wie Peter schon schrieb, warum? Peter D. schrieb: > Sorry, die boot.h: Wenn du nicht nur einfach die Fuse auslesen möchtest, sondern lernen möchtest, wie man Assembler-und C-Programme mixt, dann kannst du das gerne tun. Axel S. schrieb: > Sercan E. schrieb: >> Das ist mir zu kompliziert erklärt versteh ich leider nicht :( Da musst du in dem Fall durch. Oliver
Also, im AVR-Studio fügst Du die .s-Datei erstmal Deinen Projekt-Sourcecodes hinzu. Dann nennst Du das Label genau wie die C-Funktion, also hier könntest Du den Code "ReadFuseByte:" mit einer C-Funktion "ReadFuseByte()" aufrufen. Die Parameter-Übergabe geht bei AVR/GCC über die Register (int16 Über-/Rückgabe hier über R24/R25). Ein Byte wird trotzdem in einem Registerpaar übergeben (LSB in R24) Dann brauchst Du im C-Code noch einen Funktions-Prototypen, z.B.: "uint8_t ReadFuseByte (void);" Und mit ".global" gibst Du in der ASM-Datei die Labels an, die Du Global bekanntmachen willst, hier also z.B. ".global ReadFuseByte" Viel Erfolg!
Sercan E. schrieb: > Das ist mir zu kompliziert erklärt versteh ich leider nicht :( Das liegt daran daß der ganze Sachverhalt und die Zusammenhänge nicht ganz trivial sind und sich sicher nicht erschöpfend mit 3 Sätzen erklären lässt. Wenn die Motivation Dich mit dieser Aufgabenstellung zu befassen darin besteht das zukünftig als Hobby zu betreiben und auch Freude daran haben zu wollen dann wirst Du nicht umhin kommen Dir einen Überblick zu verschaffen und wenigstens in groben Zügen zu verstehen was alles vor sich geht und wie die Zusammenhänge sind wenn aus all den einzelnen C- und Assembler-Dateien am Ende ein lauffähiges Binary herauskommt. Das lernt man nicht an einem einzigen Nachmittag. Da ist viel Lesen angesagt, ausprobieren des gelesenen und beobachten, mal gezielt Fehler einbauen oder Dinge weglassen und sehen ob der daraus resultierende Fehler mit Deinem bisherigen Verständnis der Zusammenhänge in Einklang steht, wenn nicht: weiterlesen, gezielt weiterfragen, etc. Das dauert Monate (oder Jahre, je nachdem wie tief Du einsteigen willst). Aber bei einem Hobby ist Zeit kostenlos und reichlich vorhanden und der Weg ist das Ziel.
Man kann sich auch ganz einfach eine Dummyfunktion in C schreiben und dann nach Assembler compilieren lassen. Dann hat man ein Beispiel, wie Funktionsaufrufe, Argumente und Returnwerte zu deklarieren sind. avrgcc -Os -S -c foo.c
:
Bearbeitet durch User
Peter D. schrieb: > avrgcc -Os -S -c foo.c -S oder -c ? @Sercan: Die Registerverwendung von avr-gcc wird erklärt in http://gcc.gnu.org/wiki/avr-gcc#Register_Layout Dort wird auch ausführlich beschrieben, wie Parameter und Rückgabewerte von Funktionen übergeben werden. Für jede Funktion, die von C aus aufzurufen ist: 1) Für jedes Assembler-Modul, z.B. foo.asm, lege einen C-Header an, z.B foo.h. 2) Das Modul foo.asm wird genauso compiliert wie ein C-Modul auch, d.h. mit avr-gcc und nicht mit avr-as. avr-gcc ist ein Treiberprogramm, das anhand der Endungen erkennt, wie die Datei zu handhaben ist. Assembler-Code, über den vor dem Assemblieren der C-Präprozessor laufen soll, hat Endung .S oder .sx. Bei anderen Endungen wie .asm verwendet man -x assembler-with-cpp foo.asm. 3) Für jede Funktion im Modul, die von C aus aufgerufen werden soll, kommt in die foo.h ein Prototyp:
1 | #ifndef FOO_H
|
2 | #define FOO_H
|
3 | |
4 | #include <stdint.h> // C99 |
5 | |
6 | extern uint16_t /* R23:22 */ ReadFuseByte (uint8_t addr0 /* R24 */); |
7 | |
8 | #endif // FOO_H
|
4) In C-Modulen, welche die Funktion verwenden, includen vor der Verwendung foo.h und rufen die Funktionen so auf wie andere C-Funktionen auch. 5) Jede Funktion, die von C aus aufgerufen wird, sieht ungefähr so aus:
1 | .text |
2 | |
3 | ;; Dokumentation der Funktion |
4 | ;; Dokumentation ihres Interfaces |
5 | .global func |
6 | .type func,@function |
7 | |
8 | func: |
9 | ;; Code |
10 | |
11 | .size func, . - func |
.size unf .type sind lediglich Meta-Info für avr-size, avr-nm etc.
C-Dummy foo.c:
1 | #include <avr/io.h> |
2 | |
3 | uint8_t foo( uint8_t val ) |
4 | {
|
5 | PORTB = val; |
6 | return PINB; |
7 | }
|
avr-gcc.exe -Os -S -c foo.c -mmcu=attiny25 Assembler Output foo.s:
1 | .file "foo.c" |
2 | __SREG__ = 0x3f |
3 | __SP_H__ = 0x3e |
4 | __SP_L__ = 0x3d |
5 | __CCP__ = 0x34 |
6 | __tmp_reg__ = 0 |
7 | __zero_reg__ = 1 |
8 | .text |
9 | .global foo |
10 | .type foo, @function |
11 | foo: |
12 | /* prologue: function */
|
13 | /* frame size = 0 */
|
14 | out 56-32,r24 |
15 | in r24,54-32 |
16 | /* epilogue start */
|
17 | ret
|
18 | .size foo, .-foo |
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.