Forum: Mikrocontroller und Digitale Elektronik Makros in C und ASM nutzen


von Paul S. (paul_s)


Lesenswert?

Hallo!

In meinem Projekt habe ich etwas Assembler-Code und viel C Code. In 
beiden Teilen gibt es Makro-Definitionen, oft für das Selbe:

Assembler:
#set      DEVICE       MB96346RxA;
#set      CLOCK_SPEED  CPU_24MHZ_CLKP2_12MHZ

C:
#define   PROZESSORTYP 96348
#define   F_SYSTEM     24000000             // CPU-Takt in Hz

Die Beispiele sind jetzt nicht perfekt, weil die Sachen nicht ganz 
identisch sind, aber ich wollte auch nur klarstellen, wofür das sein 
soll.

Ich suche einen Weg, z.B. die Taktfrequenz nur einmal zu definieren, und 
diese Definition (per include?) sowohl in Assembler als auch in C zu 
benutzen.
Hat das schon jemand hinbekommen? Ich hoffe auf kreative Vorschläge!

Viele Grüße

Paul

von Andreas B. (Gast)


Lesenswert?

Der C Präprozessor verarbeitet Text und hat in Wirklichkeit von C keine 
Ahnung. Also kann man auch Assembler Quelltext durchjagen und so 
dieselben Includes verwenden.

Meist wird man noch dem cpp ein "#define ASSEMBLER" (beim GNU cpp auf 
der Kommandozeile Option -DASSEMBLER) oder ähnlich mitgeben, dann kann 
man per #ifdef Teile, die nicht für den Assembler geeignet sind, 
ausklammern.

Ruft man den Assembler über gcc auf, verwendet der automatisch den 
Präprozessor wenn die Dateiendung .S oder .sx (statt .s) ist.

von Arnold (Gast)


Lesenswert?

Hallo Paul,

kannstDu nicht ein #define auf ein #set machen? Also ein #define auf ein 
#define sozusagen? In C geht das jedenfalls.

in etwa so...

Assembler:
#set      DEVICE       MB96346RxA;
#set      CLOCK_SPEED  CPU_24MHZ_CLKP2_12MHZ

C:
#define   PROZESSORTYP DEVICE
#define   F_SYSTEM     CLOCK_SPEED             // CPU-Takt in Hz


Gruß
Arnold

von 123 (Gast)


Lesenswert?

aber ein

#ifdef C_COMPILER
  #define   PROZESSORTYP DEVICE
  #define   F_SYSTEM     CLOCK_SPEED             // CPU-Takt in Hz
#else
  #set      DEVICE       MB96346RxA;
  #set      CLOCK_SPEED  CPU_24MHZ_CLKP2_12MHZ
#endif

wobei C_COMPILER entweder beim Aufruf des C Compiler mit vermutlich -D 
übergebenes Define ist.

Oder der C Compiler hat ein spezielles Define, an dem man erkennen kann 
das es sich um diesen compiler haldelt. bzw der ASM eines.

von Klaus W. (mfgkw)


Lesenswert?

1
__GNUC__
2
__STDC__

oder:
1
__ASSEMBLER__

von Karl H. (kbuchegg)


Lesenswert?

Ich denke aber doch, das das alles am eigentlichen Kern des Problems 
vorbei geht.
Insofern hat der TO ein schlechtes Beispiel geliefert.

Er will

#set   CLOCK_SPEED   8000000

und

#define CLOCK_SPEED   8000000


irgendwie so zusammenführen, dass der Zahlenwert nur 1-mal auftritt.

AFAIK und IMHO geht das aber nicht. Mit dem C-Preprozessor ist es nicht 
möglich, Ersetzungen so vorzunehmen, dass sich neue 
Preprozessorstatements ergeben. Ob das mit dem Assembler möglich ist, 
hängt dann vom Assembler ab. Erwarten würde ich das aber nicht.

d.h. der 'Weg'
1
#ifdef ASSEMBLER
2
#set     PRE_RPOC_COMMAND    #set
3
#else
4
#define  PRE_PROC_COMMAND    #define
5
#endif
6
7
PRE_PROC_COMMAND CLOCK_SPEED  8000000

bei dem ja nach 'Übersetzer' einmal ein #set und das andere mal ein 
#define auftaucht, das wird es so nicht spielen.

Wenn Assembler und C unterschiedliche Preprozessor-Direktiven zum 
festlegen von Makro-Substitutionen benutzen, dann bist du weg vom 
Fenster.

Das einzige was gehen könnte:
Man könnte sich den C-Preprozessor 'ausborgen', damit er sich ein 
Assemblerfile vorab vornimmt. Wie das aber aussehen soll, weiss ich auch 
noch nicht.

von Klaus W. (mfgkw)


Lesenswert?

Dann bleibt als Alternative, solche Definitionen in einem anderen
PP zu definieren (z.B. m4) und daraus die Headerdateien für C und
Assembler zu generieren.

Ist dafür vielleicht etwas overkill, aber eröffnet gleichzeitig
noch mehr Spielereien.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Eine Möglichkeit besteht noch.

Du nimmt einfach ein einzelnes C-File mit Defines.
Dann noch ein Skript, welches Dir das C-File in eine passende 
Assembler-Syntax umbaut (suchen/ersetzen) - zum Beispiel mit "sed".
Das Skript wird bei jedem Makefile-Aufruf gestartet und baut aus dem 
C-File ein Assembler-File. Danach wird Compiliert und Assembliert - 
alles aus dem gleichen Projekt-Makefile heraus.

von Andreas B. (Gast)


Lesenswert?

Ich versteh euer Problem nicht…

Karl heinz Buchegger schrieb:
> Er will
>
> #set   CLOCK_SPEED   8000000
>
> und
>
> #define CLOCK_SPEED   8000000
>
>
> irgendwie so zusammenführen, dass der Zahlenwert nur 1-mal auftritt.

Also bleibt nur das #define in der gemeinsamen Include-Datei.

> d.h. der 'Weg'
> #ifdef ASSEMBLER
> #set     PRE_RPOC_COMMAND    #set
> #else
> #define  PRE_PROC_COMMAND    #define
> #endif
>
> PRE_PROC_COMMAND CLOCK_SPEED  8000000
>
> bei dem ja nach 'Übersetzer' einmal ein #set und das andere mal ein
> #define auftaucht, das wird es so nicht spielen.

Nein, wozu auch? Wieso muss ein #set erzeugt werden? Ich denke doch es 
geht nur um Konstanten.

Solange der Assembler dieselbe Syntax für Konstanten wie der C-Compiler 
frisst (also etwa Hex-Konstanten mit 0x am Anfang, Bitshifts als 
(1<<BLABLA)) gibt es doch gar kein Problem.

von Karl H. (kbuchegg)


Lesenswert?

Andreas B. schrieb:

> Nein, wozu auch? Wieso muss ein #set erzeugt werden?

Weil vielleicht derjenige, der den Assembler geschrieben hat, sich 
eingebildet hat, dass die Definition von Ersetzungen oder Konstanten 
dort

#set    abcd efgh

lautet.

> Solange der Assembler dieselbe Syntax für Konstanten wie der C-Compiler
> frisst (also etwa Hex-Konstanten mit 0x am Anfang, Bitshifts als
> (1<<BLABLA)) gibt es doch gar kein Problem.

Solange.
Und wenn nicht?

von Andreas B. (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Weil vielleicht derjenige, der den Assembler geschrieben hat, sich
> eingebildet hat, dass die Definition von Ersetzungen oder Konstanten
> dort
>
> #set    abcd efgh
>
> lautet.

Die Idee ist doch, den C-Präprozessor die Ersetzungen machen zu lassen. 
Ist doch völlig schnurz wie das im Assembler gemacht werden würde so man 
denn dessen Funktionen einsetzen täte.


> Solange.
> Und wenn nicht?

Dann muss man aufpassen und kompatible Definitionen verwenden (dezimal 
wird der Assembler wohl mindestens können). Oder man machts halt doch 
kompliziert und schreibt ein Programm, das äquivalente Definitionen aus 
der Vorlage eines Includes erzeugt.

von Karl H. (kbuchegg)


Lesenswert?

Andreas B. schrieb:
> Karl heinz Buchegger schrieb:
>> Weil vielleicht derjenige, der den Assembler geschrieben hat, sich
>> eingebildet hat, dass die Definition von Ersetzungen oder Konstanten
>> dort
>>
>> #set    abcd efgh
>>
>> lautet.
>
> Die Idee ist doch, den C-Präprozessor die Ersetzungen machen zu lassen.
> Ist doch völlig schnurz wie das im Assembler gemacht werden würde so man
> denn dessen Funktionen einsetzen täte.


Du verstehst es immer noch nicht.

Die Idee ist es, ein und denselben Code so aufzubereiten, dass

* die Assembler Syntax eingehalten wird
* die C Snytax eingehalten wird
* Alle vom Programmierer einstllbaren Konstanten trotzdem
  nur ein einziges mal vorkommen


Die Idee ist es, ein Konfigurationsfile zu haben, welches sowohl von C 
als auch von Assembler aus benutzt (inkludiert) werden kann, und alle 
reelvanten Dinge in der jeweiligen Zielsyntax bereitstellt. Aber nur 1 
File und jede Konstante soll nur 1 mal vorkommen.

> Dann muss man aufpassen und kompatible Definitionen verwenden (dezimal
> wird der Assembler wohl mindestens können).

Es geht nicht um Zahlen und deren Darstellung.

Es geht darum, zwei verschiedene Syntaxen unter einen Hut zu bringen.

So wie wenn du ein und denselben Source Code so schreiben willst, dass 
ein C Compiler damit glücklich ist und derselbe Source Code, ohne 
Änderungen, auch durch einen Fortran Compiler durchgejagt werden kann 
und auch dort ein Programm erzeugt, das sich dann auch noch identisch 
verhält.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Das "Problem" könnte ja auch sein, dass der Assembler kleinen 
C-Präprozessor verwendet. Er kann also mit eine #ifdef nichts anfangen. 
Natürlich könnte man diesen dem Assembleraufruf auch vorschalten. Dieser 
erzeugt dann als Ausgabedatei eine für den Assembler verständliche 
Syntax.

von Andreas B. (Gast)


Lesenswert?

Christian H. schrieb:
> Das "Problem" könnte ja auch sein, dass der Assembler kleinen
> C-Präprozessor verwendet. Er kann also mit eine #ifdef nichts anfangen.
> Natürlich könnte man diesen dem Assembleraufruf auch vorschalten. Dieser
> erzeugt dann als Ausgabedatei eine für den Assembler verständliche
> Syntax.

Das sagte ich ja gleich zu Beginn, man soll den Assembler Quelltext 
durch den C-Präprozessor jagen. Der Assembler wird nie ein #ifdef sehen.

Das ist eine derart weit verbreitete Lösung, dass es der gcc, wie ich 
schon erwähnte, automatisch machen kann.


Oder nochmal in langsam:

defs.h:
1
#define FOO  123

beispiel.c:
1
#include "defs.h"
2
3
int blah()
4
{
5
        return FOO;
6
}

asm.S:
1
#include "defs.h"
2
3
asm_blah:
4
        mov     r0, #FOO
5
        ret


Und wenn mir das jemand noch immer nicht glaubt:
1
$ cpp asm.S
2
# 1 "asm.S"
3
# 1 "<built-in>"
4
# 1 "<command-line>"
5
# 1 "asm.S"
6
# 1 "defs.h" 1
7
# 2 "asm.S" 2
8
9
asm_blah:
10
        mov r0, #123
11
        ret

Wenn der Assmbler die Zeilenmarker nicht interpretieren kann, gibts die 
Option -P. Dann stimmen in Fehlermeldungen die Zeilennummern aber nur 
für die Ausgabe des Präprozessors.

von Karl H. (kbuchegg)


Lesenswert?

Andreas B. schrieb:

> Und wenn mir das jemand noch immer nicht glaubt:

Wir glauben dir das doch. Die Lösung mit dem cpp ist ja nun schon oft 
genug in diesem Thread gefallen.

Aber gibt es auch eine Lösung, die ohne cpp auskommt?

von Erich (Gast)


Lesenswert?

Vielleicht sollte man sich für ein (das) Projekt einig werden,
ob nun in C oder in ASM programmiert wird.

Damit verschwindet dieses "Problem" ganz von alleine.

von Paul S. (paul_s)


Lesenswert?

Hallo,

danke für die zahlreichen Antworten. Für mich ist das Problem gelöst, 
viel einfacher als ich dachte. Mein Fujitsu-Assembler versteht die 
C-Präprozessor Makros. Ich war nur nicht auf die Idee gekommen, weil die 
nicht drinstanden und immer #set statt #define benutzt wurde. Es geht 
aber bei diesem(!) Assembler beides.

Aus dem Handbuch:
The #set instruction can be executed for the same macro name as many 
times as necessary.
The difference from the #define instruction is that the #set instruction 
allows the macro name to be used
as a variable.

Warum Fujitsu im Beispielcode dann z.B. den Prozessortyp mit #set und 
nicht mit #define festlegt ist mir nicht ganz klar, ich habe noch nicht 
gehört, dass sich der Prozessortyp im Betrieb ändert...

Auf jeden Fall habe ich jetzt einfach ein zusätzliches konfig.h File, in 
dem Prozessortyp, Frequenz und Debugmodus definiert werden, und sowohl 
ASM als auch C-Files includen das und benutzen den Inhalt, z.B.

im ASM:
#if PROZESSORTYP == 96348
#if PROZESSORVARIANTE == A
#set      DEVICE    MB96348RxA      ; <<< select device
#else
#set      DEVICE    MB96348RxB      ; <<< select device
#endif
#endif

Mehr wollte ich gar nicht.
Ich bin gespannt, ob es doch noch eine geniale Lösung für Assembler 
gibt, die solche Direktiven nicht verstehen.

Paul

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.