gcc auf dem pc ausführen

#7824343
Lesenswert?

hallo,

ich arbeite an einer Steuerung für einen Wechselrichter. Daten per modbus einlesen, Regelung berechne, regeln mit atmega 328 nano.

Ich würde gerne einen Teil der c-code-Entwicklung auf den pc auslagern - am liebsten mit c#, weil das debugging und testen des codes etwas umständlich ist. Messen und Regeln per modbus geht genau so gut auf dem ps wie auf dem nano.

Problem ist eigentlich nur die unterschiedliche Variablen-Definition. Wenn es in c# #defines gäbe wäre das kein Problem. also etwa #defines u8 byte

gibt es aber wohl nicht.

Ich gehe mal davon aus, dass es für meine Anforderungen fertigem Lösungen gibt. also z.B.

1
void wr_on(void)
2
{
3
wr_off();
4
wait;
5
wr_status_0off_1on=1;
6

7
    {
8
    u8 buffer[8]={0x00, 0x10, 0x00, 0x50, 0x00, 0x01, 0x01, 0x00, 0x01, 0x96, 0x50};
9
    }
10
    wr_write(0x001000,0x5000010100019650);
11

12
_delay_ms(500);//rx abwarten
13

14
sub_protocoll(2);
15

16
}

in c# programmieren und in c# ausführen und dann auf den m328 übertragen.

Kann natürlich auch was anderes als c# sein- Grafische Oberfläche zum testen des lcd wäre aber schön.

Persönliche Seite #7824349
Lesenswert?

Wie wäre es mit C oder C++ statt C#? Dann ist die Syntax identisch. Achja, das geht dann sogar mit dem GCC. Der normale x86 GCC eben statt des AVR-GCC. Das kann man auch gut debuggen.

Allerdings ist es insbesondere unter Windows i.A. einfacher, Visual Studio ("Community" Version ist gratis) statt GCC zu nehmen, weil da alles praktisch integriert ist, auch ein guter Debugger. Der C-Support ist dort etwas vernachlässigt/veraltet, aber C++ geht gut (wobei GCC das noch besser kann). Dass du Typen wie "byte" nutzt klingt als würdest du Arduino nutzen - das ist ja auch sowieso C++, nicht C.

Statt "u8" oder "byte" kannst du einfach "uint8_t" nutzen, das gibt es auf beiden Plattformen ohne "#define" Gebastel (typedef wäre sowieso besser).

#7824370
Lesenswert?

Karl K. schrieb:

Ich würde gerne einen Teil der c-code-Entwicklung auf den pc auslagern

Kann es sein, daß du noch nie von der Existenz von Cross-Compilern gehört hast? Und wo entwickelst du denn dann für den AVR, wenn nicht am PC?

am liebsten mit c#

AFAIK gibt es in der gcc (GNU Compiler Collection) keinen C# Compiler für das AVR backend. Insofern geht C# auf AVR erstmal nicht.

Wenn es in c# #defines gäbe wäre das kein Problem. also etwa #defines u8 byte

u8 und byte sind keine Standardtypen. uint_8t hingegen schon. Tu dir selber einen Gefallen und verwende diesen. Definiert sind diese Typen in stdint.h. Übrigens: ein Byte ist im Kontext von C etwas anderes als das was du glaubst.

https://stackoverflow.com/questions/11868211/does-sizeof-return-the-number-of-bytes-or-the-number-of-octets-of-a-type-in-c

#7824372
Lesenswert?

Sehe ich auch so. Die gängige Verfahrensweise ist, die Applikationslogik von der Hardwareansteuerung zu trennen und plattformunabhängig zu implementieren. Dann nimmt man sich ein beliebiges Testframework her - für den Anfang gerne etwas kleines übersichtliches wie https://github.com/mity/acutest - und schreibt Testfälle mit denen man die Applikationslogik als PC-Programm ohne Hardware testen und debuggen kann. Die benötigten Hardwarefunktionen müssen natürlich trotzdem als Fake implementiert werden, aber halt nur mit so viel Funktionalität wie für den jeweiligen Testfall benötigt (Stubs).

Alternativ oder zusätzlich lässt man das mit dem PC-Programm bleiben und baut ein Hardware-In-the-Loop Testsystem mit dem man die Hardware direkt als Blackbox testen kann. Dafür bildet man die Umgebung deiner Steuerung so nach dass man ihn so testen kann als wäre er richtig eingebaut. Das ist in meinen Augen am Ende wertvoller weil näher an der Realität aber mit hohem initialen Zeitaufwand verbunden. On-Chip debugging ist nicht viel weniger komfortabel als debuggen auf dem PC. Und man braucht es eh.

Wie auch immer, am Ende ist das wichtigste dass man seinen Kram irgendwie (automatisiert) getestet bekommt. Software ohne Testabdeckung ist wie klettern ohne Seil.

Ob der Atmega für deinen Anwendungsfall noch zeitgemäß ist? Ich verwende für alle Steuerungsaufgaben zu Hause mittlerweile den esp32. Die direkte Anbindung ans wlan gepaart mit der Möglichkeit zum Firmwareupdate over-the-air ist Gold wert und spart unglaublich viel Zeit.

Und wenn deine Anwendung nicht all zu zeitkritisch ist, gäbe es auch micropython für den esp32. Das macht die SW Entwicklung noch mal eknfacher.

#7824375
Lesenswert?

Axel S. schrieb:

Übrigens: ein Byte ist im Kontext von C etwas anderes als das was du glaubst.

Nee, ist es nicht. Zwar erlaubt der Standard da beliebige Größen, in der Praxis gibt's aber bis auf ein paar ganz seltene abstruse Exotenhardwares nur 8 Bit.

Ansonsten ist die Idee, auf dem PC in C# und auf dem Zielsystem C zu benutzen, nicht sonderlich sinnvoll.

PC ja, aber auch in C.

Oliver

#7824540
Lesenswert?

Niklas G. schrieb:

Wie wäre es mit C oder C++ statt C#? Dann ist die Syntax identisch. Achja, das geht dann sogar mit dem GCC. Der normale x86 GCC eben statt des AVR-GCC. Das kann man auch gut debuggen.

Hat allerdings den Nachteil, dass die Datentypen unterschiedlich groß sind, insbesondere int (wäre natürlich bei C# auch nicht besser - da wären zusätzlich auch noch die Konvertierungsregeln anders). Dadurch können sich gewisse Fehler einschleichen (Stichwort integer-promotion).

Axel S. schrieb:

Wenn es in c# #defines gäbe wäre das kein Problem. also etwa #defines u8 byte

u8 und byte sind keine Standardtypen. uint_8t hingegen schon.

uint8_t.

Oliver S. schrieb:

Axel S. schrieb:

Übrigens: ein Byte ist im Kontext von C etwas anderes als das was du glaubst.

Nee, ist es nicht. Zwar erlaubt der Standard da beliebige Größen, in der Praxis gibt's aber bis auf ein paar ganz seltene abstruse Exotenhardwares nur 8 Bit.

So abstrus sind die nun auch wieder nicht. Zum Beispiel irgendwelche DSPs, bei denen es nix kleineres als 24 Bit gibt. Das dann in C auf die üblichen 8, 16, 32, 64 Bit abzubilden würde C auf sowas komplett unbrauchbar machen.

Ansonsten ist die Idee, auf dem PC in C# und auf dem Zielsystem C zu benutzen, nicht sonderlich sinnvoll.

PC ja, aber auch in C.

Ja.

Arduino F. schrieb:

Niklas G. schrieb:

ohne "#define" Gebastel (typedef wäre sowieso besser).

using, nicht typedef.

Wenn wir hier schon in der C++ Welt sind.

Ich finde typedef trotzdem besser. Einzig der Name ist unglücklich gewählt, weil man damit keinen Typ definiert.

Peter schrieb:

Karl K. schrieb:

wr_write(0x001000,0x5000010100019650);

Das müßte ja auch ein uint64_t sein. Arbeiten die kleinen AVRs überhaupt mit solchen Zahlen? Und die wr_write() Funktion?

Dem AVR ist das egal, der kann eh nix größeres als 8 Bit. Da kümmert sich der Compiler drum. Allerdings ist der Umgang mit so großen Datentypen mitunter nicht sehr effizient. Man sollte das daher nur tun, wenn man auch wirklich so große Zahlen braucht.

(Firma: Gast) #7824624
Lesenswert?

Rolf M. schrieb:

Ich finde typedef trotzdem besser. Einzig der Name ist unglücklich gewählt, weil man damit keinen Typ definiert.

Auch die Syntax ist ein wenig quer. Mir schmeckt zB. nicht, dass das zu definierende manchmal mitten im Ausdruck erscheint, erscheinen muss.

Beispiele:

1
typedef ParameterType MeinArray[42];
2
typedef AusgabeType (*CallBackType)(ParameterType);

Vielleicht gehts nur mir so, aber ich muss da schon manchmal einen Gedanken mehr drauf verschwenden: "Was wird da überhaupt definiert?"

1
using MeinArray = ParameterType[42];
2
using CallBackType = AusgabeType (*)(ParameterType);

Die using Variante erscheint mir da ein wenig eingängiger/offensichtlicher zu sein.

Moderator #7824649
Lesenswert?

Rolf M. schrieb:

Niklas G. schrieb:

Wie wäre es mit C oder C++ statt C#? Dann ist die Syntax identisch. Achja, das geht dann sogar mit dem GCC. Der normale x86 GCC eben statt des AVR-GCC. Das kann man auch gut debuggen.

Hat allerdings den Nachteil, dass die Datentypen unterschiedlich groß sind

Wenn man anstelle des GCC einen 16-Bit-Compiler (bspw. Watcom) nimmt, ist dieser Nachteil beseitigt.

Arduino F. schrieb:

Rolf M. schrieb:

Ich finde typedef trotzdem besser. Einzig der Name ist unglücklich gewählt, weil man damit keinen Typ definiert.

Auch die Syntax ist ein wenig quer. Mir schmeckt zB. nicht, dass das zu definierende manchmal mitten im Ausdruck erscheint, erscheinen muss.

Die Syntax entspricht der von Variablendeklarationen, nur dass der Variablenname durch den Namen des Typ-Alias ersetzt wird. Da C++ nach wie vor die Variablendeklarationssyntax von C benutzt, wirkt es recht komisch, wenn ausgerechnet für Typ-Aliase (die ja viel seltener als Variablendeklarationen benötigt werden) eine andere Syntax verwendet wird.

#7824773
Lesenswert?

Yalu X. schrieb:

Die Syntax entspricht der von Variablendeklarationen, nur dass der Variablenname durch den Namen des Typ-Alias ersetzt wird. Da C++ nach wie vor die Variablendeklarationssyntax von C benutzt, wirkt es recht komisch, wenn ausgerechnet für Typ-Aliase (die ja viel seltener als Variablendeklarationen benötigt werden) eine andere Syntax verwendet wird.

Genau deshalb mag ich typedef lieber. Es weicht nicht von der Syntax von Variablendeklarationen ab. Das finde ich konsistenter.

Arduino F. schrieb:

Beispiele: typedef ParameterType MeinArray[42]; typedef AusgabeType (*CallBackType)(ParameterType);

Variablendeklaration:

1
ParameterType MeinArray[42];
2
AusgabeType (*CallBackFunktion)(ParameterType);

Wenn ich dafür eigene Typ-Aliase will, schreib ich einfach typedef davor, und den Rest kann ich genau gleich lassen. Bei using sieht es deutlich anders aus, also uneinheitliche Syntax.

Vielleicht gehts nur mir so, aber ich muss da schon manchmal einen Gedanken mehr drauf verschwenden: "Was wird da überhaupt definiert?"

So ähnlich ging es mir mal nur bei der Funktion signal(), die einen Funktionszeiger als Parameter bekommt und einen zurückgibt:

1
void (*signal(int sig, void (*func)(int)))(int);

signal selbst ist hier übrigens kein Funktionszeiger. Aber das ist eben eine Funktionsdeklaration. Deren Syntax bleibt also so. (klar kann - und sollte - man sich für den Signalhandler ein eigenes Typ-Alias anlegen)

using MeinArray = ParameterType[42]; using CallBackType = AusgabeType (*)(ParameterType); Die using Variante erscheint mir da ein wenig eingängiger/offensichtlicher zu sein.

Ob jetzt (*)() für den Namen einen Funktionszeiger-Typs besonders eingängig ist, ist Ansichtssache.

#7824790
Lesenswert?

Rolf M. schrieb:

Zum Beispiel irgendwelche DSPs, bei denen es nix kleineres als 24 Bit gibt.

32 Bit auch :) Wenn man nur x86 und AVR kennt dann sind DSPs schon abstruse Exoten ;)

Rolf M. schrieb:

1
> void (*signal(int sig, void (*func)(int)))(int);

C Programmierer sind schon ein wenig masochistisch weil sie sich so etwas antun. Ich glaube alleine wegen obigen Konstrukt wurde typedef erfunden ;)

#7824799
Lesenswert?

900ss schrieb:

Rolf M. schrieb: void (*signal(int sig, void (*func)(int)))(int); C Programmierer sind schon ein wenig masochistisch weil sie sich so etwas antun. Ich glaube alleine wegen obigen Konstrukt wurde typedef erfunden ;)

Möglicherweise. Mit typedef sieht's auch schon bedeutend übersichtlicher aus:

1
typedef void (*sighandler_t)(int);
2

3
sighandler_t signal(int signum, sighandler_t handler);

Yalu X. schrieb:

Wenn man anstelle des GCC einen 16-Bit-Compiler (bspw. Watcom) nimmt, ist dieser Nachteil beseitigt.

Aber kann man das auf heutigen PCs und deren Betriebssystemen noch nativ ausführen und debuggen? Darum ging es ja schließlich. Man könnte natürlich einen Emulator nehmen wie DosBox, aber dann könnte man auch gleich den AVR emulieren.

#7824802
Lesenswert?

Axel S. schrieb:

u8 und byte sind keine Standardtypen. uint_8t

du meinst uint8_t? c#-Programm geschrieben. beides probiert. beides kennt c# nicht?

typedef ParameterType MeinArray[42]; typedef AusgabeType (*CallBackType)(ParameterType);

using MeinArray = ParameterType[42]; using CallBackType = AusgabeType (*)(ParameterType);

using und typedef kennt c# auch nicht. Fehlt ein Verweis?

Nachtrag: using u8 = System.Byte; scheint doch zu gehen.

#7824814
Lesenswert?

Karl K. schrieb:

Axel S. schrieb:

u8 und byte sind keine Standardtypen. uint_8t

du meinst uint8_t? c#-Programm geschrieben. beides probiert. beides kennt c# nicht?

Damit zeigst du ja selber, warum C# für dein Vorhaben nicht geeignet ist.

using und typedef kennt c# auch nicht. Fehlt ein Verweis?

Hmm, using hätte es eigentlich kennen müssen soweit ich weiß.

Moderator #7824887
Lesenswert?

Rolf M. schrieb:

Yalu X. schrieb:

Wenn man anstelle des GCC einen 16-Bit-Compiler (bspw. Watcom) nimmt, ist dieser Nachteil beseitigt.

Aber kann man das auf heutigen PCs und deren Betriebssystemen noch nativ ausführen und debuggen?

Je nachdem, welches Betriebssystem man nativ laufen hat ;-)

Darum ging es ja schließlich. Man könnte natürlich einen Emulator nehmen wie DosBox

Ja, das ist eine einfach aufzusetzende Möglichkeit, den 16-Bit-Code zu testen.

Ich selber benutze das Kompilieren auf dem PC vor allem, um etwas kompliziertere Berechnungen oder Algorithmen vorab ausgiebig mit verschiedenen reproduzierbaren Eingabedatensätzen zu testen, weil das auf dem Target-Mikrocontroller meist sehr mühsam ist. Erst wenn diese Tests erfolgreich sind, wird das Programm auf das Target geflasht. Dort kann ich mich dann voll auf das Testen der I/O-Funktionen und des Echtzeitverhaltens konzentrieren (was wiederum auf dem PC kaum möglich ist), weil ich weiß, dass der ganze Rest bereits fehlerfrei ist.

Das Testen mit einem 16-Bit-Compiler (OpenWatcom) habe ich erst vor Kurzem ausprobiert, da ich mich gefragt habe, wie man auch Fehler auf Grund von Integer-Überläufen bereits beim Testen auf dem PC erkennen kann.

aber dann könnte man auch gleich den AVR emulieren.

Ja, das geht natürlich auch, nur ist es damit nicht so einfach, den Eingabedatenstrom von einer Datei zu lesen und die Ergebnisse wieder in eine Datei zu schreiben, um sie genauer analysieren zu können.

Persönliche Seite #7824963
Lesenswert?

Yalu X. schrieb:

Das Testen mit einem 16-Bit-Compiler (OpenWatcom) habe ich erst vor Kurzem ausprobiert, da ich mich gefragt habe, wie man auch Fehler auf Grund von Integer-Überläufen bereits beim Testen auf dem PC erkennen kann.

aber dann könnte man auch gleich den AVR emulieren.

Ja, das geht natürlich auch, nur ist es damit nicht so einfach, den Eingabedatenstrom von einer Datei zu lesen und die Ergebnisse wieder in eine Datei zu schreiben, um sie genauer analysieren zu können.

Für rein algorithmische Tests (also keine SFRs oder IRQs involviert), verwende ich AVRtest als Simulator.

Als ich zum Beispiel eine 64-Bit double Implementation gemacht have, war das sehr hilfreich -- das auf einem komplett anderen System mit bereits funktionierender double-Arithmetik zu testen wäre ziemlich sinnlos gewesen...

Daten aus AVRtest raus bekommen ist einfach: Im einfachsten Falle per printf (was auf dem stdout des Hosts landet), oder per spezieller Syscalls, die den Overhead von printf vermeiden.

Daten von Platte zu lesen geht prinzipiell auch, ist aber wegen des Designs der AVR-LibC etwas umständlich. AVRtest stellt dafür ein Target-Modul zur Verfügung, das man nur noch in die AVR-Applikation reinzulinken brauch; und dann funktioniert alles wie per stdio.h.

AVRtest ist auch einigermaßen fix. Beispielsweise folgender Test, der ca. 2*16000000 24-Bit Multiplikation testet

1
#include <stdint.h>
2

3
void test_mul16 (void)
4
{
5
    uint16_t a = 0;
6
    do
7
    {
8
        uint8_t b = 0;
9
        do
10
        {
11
            __uint24 ab1 = (__uint24) a * b;
12
            __asm ("" : "+r" (a), "+r" (b));
13
            __uint24 ab2 = (__uint24) b * a;
14

15
            if (ab1 != ab2)
16
                __builtin_abort ();
17
        } while (++b);
18
    } while (++a);
19
}
20

21
int main (void)
22
{
23
    test_mul16 ();
24
    return 0;
25
}

Simuliert werden 436470188 Cycles in ca. 3.5 Sekunden, das entspricht einem AVR auf 125 MHz.

#7825037
Lesenswert?

Arduino F. schrieb:

Array Bezeichner zerfallen automatisch zu einem Zeiger auf das erste Element. Da brauchts kein define für.

kannst du das erklären - mit u8* bekomme ich in c# eine Fehlermeldung - mit u8[] kommt die Fehlermeldung bei gcc?

von J. S. (jojos)▼ C# wäre mir auch zu weit weg für so eine Emulation. Und gerade der kritische Teil mit dem Modbus wird kaum kompatibel mit der µC Software sein. Außer vielleicht Modbus über TCP, aber das passt nicht zum Nano.

Der Modbus-Teil ist relativ einfach

1
        private void x_main()
2
        {
3
            u8[] wr_test = { 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x85, 0xdb };
4
         serial_tx(wr_test, 8);
5

6
}
7
//c#:
8
          void serial_tx(u8[] array, u8 ct)
9
          {
10
              serialPort1.Write(array, 0, ct);
11
          }
12

13
//avr
14
      void serial_tx(u8* array, u8 ct)
15
      {
16
         // serialPort1.Write(array, 0, ct);
17

18
          for (u8 i = 0; i < ct; i++)
19
          {
20
    while(!(UCSR0A & (1<<UDRE0)));
21
  UDR0 = buf[i];
22
          }
23
      }

Ich hänge ja nicht an c# - eher an gccc. Womit geht es denn leichter? Wichtig wäre eine grafische Oberfläche um ein lcd zu simulieren und serial tx/rx.

Persönliche Seite #7825039
Lesenswert?

Karl K. schrieb:

eher an gcc

Den GCC gibt's auch für ARM oder ESP32, wäre also kein Hindernis zum wechseln...

Karl K. schrieb:

Wichtig wäre eine grafische Oberfläche um ein lcd zu simulieren und serial tx/rx.

Das können so gut wie alle Programmiersprachen/Systeme. Wie gesagt, Visual Studio würde sich anbieten; identischer C/C++ Code, GUI Kram dran flanschen.

#7825054
Lesenswert?

Yalu X. schrieb:

Das Testen mit einem 16-Bit-Compiler (OpenWatcom) habe ich erst vor Kurzem ausprobiert, da ich mich gefragt habe, wie man auch Fehler auf Grund von Integer-Überläufen bereits beim Testen auf dem PC erkennen kann.

Da wäre ein gcc für aktuelle PC-Systeme praktisch, bei dem aber die Typen entsprechend denen vom AVR definiert sind. Aber das wäre wohl etwas komplizierter, weil das dann nicht mehr mit den bestehenden Bibliotheken (inklusive libc) funktionieren würde.

Karl K. schrieb:

wie bekomme ich den Austausch mit einem #define hin? u8[] zu u8* hin?

Gar nicht. Ich weiß, du willst das nicht hören, aber hier nochmal in aller Deutlichkeit: C und C# sind zwei gänzlich verschiedene Sprachen. Es macht keinen Sinn, zum Testen C-Code als C# übersetzen zu wollen. Zum einen müsstest du es dann irgendwie hinbekommen, haufenweise derartige Fälle zu mappen, zum anderen hast du am Ende trotzdem kein aussagekräftiges Ergebnis.

#7825055
Lesenswert?

Karl K. schrieb:

Ich hänge ja nicht an c# - eher an gccc. Womit geht es denn leichter? Wichtig wäre eine grafische Oberfläche um ein lcd zu simulieren und serial tx/rx.

Wie geschrieben, schaue dir Wokwi an.

Serial.write ist aber nur die halbe Miete bei Modbus, da gibt es Timeouts die so nicht beachtet werden. Modbus schreibt in Register, das wird hier mit einer fertigen Sequenz versteckt.

Es ist keine Schande für so eine Anwendung Arduino und eine fertige Modbus Lib zu nehmen, genauso wie für das Display. Und eben lieber einen ESP32, der kostet ja auch nix im Vergleich zum gesamten Aufwand für so ein Projekt. Nebenbei kann der einen Webserver per WLAN bereitstellen um z.B. den Status anzuzeigen.

Persönliche Seite #7825056
Lesenswert?

Yalu X. schrieb:

Das Testen mit einem 16-Bit-Compiler (OpenWatcom) habe ich erst vor Kurzem ausprobiert, da ich mich gefragt habe, wie man auch Fehler auf Grund von Integer-Überläufen bereits beim Testen auf dem PC erkennen kann.

Macht es Sinn sich bei sowas auf so eine exotische Software zu verlassen...?

Man könnte auch in C++ den uint16_t durch eine eigene Klasse ersetzen welche das exakte Promotion&Overflow Verhalten des AVRs emuliert sodass man es auf dem PC verifizieren kann. Ist zwar langsam aber spielt da ja keine Rolle. Wäre aber etwas fummelig das Verhalten wirklich korrekt zu implementieren.

(Firma: Gast) #7825089
Lesenswert?

Karl K. schrieb:

kannst du das erklären - mit u8* bekomme ich in c# eine Fehlermeldung - mit u8[] kommt die Fehlermeldung bei gcc?

Ähmmm... Damit ich dich richtig verstehe: Du möchtest das gleiche Programm wahlweise mit einem c oder C++ Compiler übersetzen und mit C# ?

C und C++ bekommt man ja gerade noch so einigermaßen unter einen Hut. Aber c# ist da eine etwas andere Welt.

Ich rate davon ab. So beschäftigst du dich mehr mit den Sprachunterschieden, als mit der Programmfunktionalität.

Stattdessen: Wähle C oder C++, die laufen auf quasi jedem Kesselchen. Und wenn Arduino, dann bist du sowieso in der C++ Welt.

Moderator #7825148
Lesenswert?

Niklas G. schrieb:

Yalu X. schrieb:

Das Testen mit einem 16-Bit-Compiler (OpenWatcom) habe ich erst vor Kurzem ausprobiert, da ich mich gefragt habe, wie man auch Fehler auf Grund von Integer-Überläufen bereits beim Testen auf dem PC erkennen kann.

Macht es Sinn sich bei sowas auf so eine exotische Software zu verlassen...?

So arg exotisch ist OpenWatcom ja auch wieder nicht. Das ist immerhin ein aktiv gepflegtes Produkt (letzte Version vom Dezemeber 2024), das für mehrere Betriebssysteme (DOS, Windows, OS/2 und Linux) verfügbar ist.

Oder man bleibt beim (AVR-)GCC und verfolgt den Vorschlag von Johannes:

Johann L. schrieb:

Für rein algorithmische Tests (also keine SFRs oder IRQs involviert), verwende ich AVRtest als Simulator.

Man könnte auch in C++ den uint16_t durch eine eigene Klasse ersetzen welche das exakte Promotion&Overflow Verhalten des AVRs emuliert sodass man es auf dem PC verifizieren kann.

Nur uint16_t anzupassen, reicht nicht. Man müsste entsprechendes auch mit int tun, um bspw. zu bewirken, dass 1000*1000 nicht 1000000, sondern 16960 ergibt. Das geht aber nicht, da int in C++ ein feststehender Datentyp ist.

Persönliche Seite #7825151
Lesenswert?

Yalu X. schrieb:

Das geht aber nicht, da int in C++ ein feststehender Datentyp ist.

Man muss eben alle Literale direkt in die eigene Klasse stecken sodass kein "normaler" Int draus wird. Man braucht mehrere Klassen für die diversen Typen und muss die Rechenregeln entsprechend implementieren. Wie gesagt, recht aufwendig aber möglich

Persönliche Seite #7825198
Lesenswert?

Yalu X. schrieb:

Rolf M. schrieb:

aber dann könnte man auch gleich den AVR emulieren.

Ja, das geht natürlich auch, nur ist es damit nicht so einfach, den Eingabedatenstrom von einer Datei zu lesen und die Ergebnisse wieder in eine Datei zu schreiben, um sie genauer analysieren zu können.

Mal ein Minimalbeispiel mit AVRtest über stdin / stdout:

in.c

1
#include <stdio.h>
2

3
int main (void)
4
{
5
    while (1)
6
    {
7
        char buf[10];
8
        char *s = fgets (buf, sizeof (buf), stdin);
9
        if (s)
10
            printf ("READ:%s", s);
11
        else
12
            break;
13
    }
14

15
    return 0;
16
}
1
$ avr-gcc -mmcu=atmega128 -Os in.c -o in.elf $AVRTEST/exit-atmega128.o
2
$ avrtest -q in.elf < in.c

Ausgabe:

1
READ:#include READ:<stdio.h>READ:
2
READ:
3
READ:int main READ:(void)
4
READ:{
5
READ:    whileREAD: (1)
6
...

Erklärung:

exit-atmega128.o ist ein Target-Modul, das von AVRtest beim Build erstellt wird und stdin, stdout und stderr auf den PC umleitet. $AVRTEST ist der Pfad wo auch das avrtest Executable liegt.

-q ist quiet Mode, d.h. AVRtest zeigt am Ende keine Zusammenfassung.

< in.c leitet die Textdatei in.c zum stdin des PCs, und AVRtest leitet es weiter zum stdin des simulierten Programms.

Die Ausgabe erscheint auf stdout des PCs, von wo aus sie weiterverarbeitet oder gespeichert werden kann, etwa mit > in.txt

Um einen String direkt einzugeben kann man z.B:

1
$ avrtest -q in.elf <<< "in.c"
2
READ:in.c

Nachteil eines Simulators ist, dass man auf die Resourcen eines AVRs beschränkt ist in Flash- und RAM-Größe. Die Flash-Größe dürfte kein großes Hindernis sein, man simuliert einfach einen AVR, der genug Flash hat.

Und mit der RAM-Größe ist man nicht an die Hardware gebunden, d.h. per Linker-Flags kann man ein größeres RAM darstellen. Man kann etwa einen ATmega4808 nehmen, und ihm knapp 16K RAM verpassen bis 0x4000. (Ab 4000 ist der Flash im RAM-Adressraum sichtbar, man braucht also auch kein PROGMEM und so Gehampel um RAM zu sparen, da .rodata im Flash liegt).

Persönliche Seite #7825236
Lesenswert?

Yalu X. schrieb:

Johann L. schrieb:

Mal ein Minimalbeispiel mit AVRtest über stdin / stdout:

Sehr gut, danke, hab's gerade erfolgreich ausprobiert :)

Weitere Möglichkeit, Daten ins Programm zu bekommen, ist per #include oder #embed. Braucht zwar Flash, ist dafür aber einfacher und schneller als erst alles durch scanf etc. zu wursten.

Oder (Pseudo)-Zufall um Test-Daten (reproduzierbar) zu erzeugen:

1
#include <stdint.h>
2
#include "avrtest.h"
3

4
uint64_t u64_rand (void)
5
{
6
    uint32_t lo = avrtest_prand ();
7
    uint32_t hi = avrtest_prand ();
8
    return (uint64_t) hi << 32 | lo;
9
}
10

11
int main (void)
12
{
13
    for (int i = 0; i < 6; ++i)
14
        LOG_FMT_U64 ("Wert = 0x%016llx\n", u64_rand());
15

16
    return 0;
17
}
1
Wert = 0x161391eacafebabe
2
Wert = 0x3d6bc2c35c3d5af4
3
Wert = 0x7ec540f4f07af5bd
4
Wert = 0x9adcc96a584c6c52
5
Wert = 0xed8934b23b5e0b7f
6
Wert = 0x71e4bc36667f8b1c

Als Option für avr-gcc brauch's dann noch ein -I$AVRTEST, damit der avrtest.h Header gefunden wird, der avrtest_prand() etc. implementiert.

avrtest_prand und LOG_FMT_U64 sind als AVRtest Syscalls implementiert, d.h. die eigentliche Arbeit übernimmt der Simulator. Das macht die Tests merklich effizienter, da man auf printf und rand verzichten kann.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren