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 " ?
Warum nimmst Du nicht die fuse.h?
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
Wie genau könnte ich die da einfügen?
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()
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
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.
|