timerThread wird per pthread_create als eigener Thread gestartet.
-lpthread ist in der Linker-Kommandozeile.
Der Linker erzeugt folgende Fehlermeldung:
1
TLS definition in /lib/x86_64-linux-gnu/libc.so.6 section .tbss mismatches non-TLS reference
errno muss eine Thread-private Variable sein - errno.h sollte eigentlich
dafür sorgen, dass das funktioniert. Tuts aber nicht.
Warum?
Uhu U. schrieb:> timerThread wird per pthread_create als eigener Thread gestartet.> -lpthread ist in der Linker-Kommandozeile.
Eigentlich müsste es -pthread beim Compilieren und Linken sein statt
deiner Variante. Das ändert wohl auch das Handling von errno:
https://stackoverflow.com/questions/2127797/significance-of-pthread-flag-when-compiling> Der Linker erzeugt folgende Fehlermeldung:> TLS definition in /lib/x86_64-linux-gnu/libc.so.6 section .tbss mismatches> non-TLS reference>> errno muss eine Thread-private Variable sein - errno.h sollte eigentlich> dafür sorgen, dass das funktioniert. Tuts aber nicht.
Wie kommst du darauf, dass das daran liegt, dass errno nicht
thread-specific sei?
Rolf M. schrieb:> Eigentlich müsste es -pthread beim Compilieren und Linken sein statt> deiner Variante. Das ändert wohl auch das Handling von errno:
Ich habe pthread in meinem Code::Blocks unter Link Libraries
eingetragen. Daraus wird dann in der Kommandozeile -lpthread.
Das habe ich jetzt mal probeweise gelöscht und dafür unter Other linker
options -pthread eingetragen. Das l ist jetzt auf der Kommandozeile weg,
aber der Fehler bleibt.
Außerdem habe ich noch -D_REENTRANT und -pthread zu den Compileroptionen
gegeben - der Linkerfehler bleibt.
> Wie kommst du darauf, dass das daran liegt, dass errno nicht> thread-specific sei?
Es ist wohl eher ein Längenkonflikt oder sowas in der Art. In der
ausführlichen Liste steht noch eine Erläuterung:
1
/lib/x86_64-linux-gnu/libc.so.6: error adding symbols: Bad value".
Uhu U. schrieb:> /lib/x86_64-linux-gnu/libc.so.6: error adding symbols: Bad value".
Der Pfad zur Libc.so.x sollte eigentlich gar nicht auftauchen in den
Compiler Fehlermeldungen.
Da ist IMHO was oberfaul in den Linker Flags - die LibC gibt man einfach
als "-lc" an.
Rolf M. schrieb:> Dann hab ich aber doch wieder pthread-Funktionen benutzt.
Aber nur die eine fürs Einstellen der Priorität. Dinge wie
Parameter-Übergabe kannst du dann sauber über std::thread abwickeln...
Die Frage ist eher: Warum bist du der Ansicht das einstellen zu müssen.
In ca. 90% der Fälle weis dein Betriebssystem wesentlich besser wie viel
Zeit dein Thread kriegen soll als du. Einen Echtzeit Timer wirst du auch
mit deiner Methode nicht hinkriegen. Das beste was du ohne
Echtzeitkernel machen kannst, ist in regelmäßigen Abschnitten die
aktuelle Systemzeit zu messen und zu vergleichen. Dazu gibt es in
std::chrono auch high precision clocks.
Und zu deiner Frage: std::thread verwenden und nur so minimal viel
pthread direkt verwenden die möglich. Macht den Code für die Zukunft
angenehmer zu verwenden. Die stl wrappt das schon sehr gut.
Dein Problem dürfte eben sein, dass du in Codeblocks, dass nur als
Linkerflag und nicht auch als Compilerflag mitgegeben hast. Vorallem
weißt du auch nicht im Detail wie Codeblock denn eigentlich compiliert.
Das kann auch getrennt Compiler und Linker aufrufen.
Mal die generierten Compiler aufrufe anschauen oder noch besser: sowas
wie Makefile oder CMake oder Meson direkt verwenden
Und auch noch wichtig, nach hinzufügen/ändern/entfernen von Optionen,
die mit den vorherigen nicht kompatibel sind, nicht vergessen alle
generierten Dateien zu löschen, auch Libs, Object files und
vorkompilierte Header. "make clean".
AbcAbc schrieb:> Die Frage ist eher: Warum bist du der Ansicht das einstellen zu müssen.
Weil ich Echtzeit-Anwendungen schreibe.
> Einen Echtzeit Timer wirst du auch mit deiner Methode nicht hinkriegen.
Die funktionieren auf pthread-Basis aber sehr gut bei mir.
> Das beste was du ohne Echtzeitkernel machen kannst, ist in regelmäßigen> Abschnitten die aktuelle Systemzeit zu messen und zu vergleichen.
Ich habe aber einen Echtzeitkernel.
> Dein Problem dürfte eben sein, dass du in Codeblocks, dass nur als> Linkerflag und nicht auch als Compilerflag mitgegeben hast.
Ich bin nicht der Threadstarter. Aber da das mit std::thread bei mir
auch letztens aufkam, hat mich interessiert, ob damit die
Thread-Prioritäten und Realtime-Funktionalitäten auch möglich sind. Wie
sieht es z.B. mit clock_nanosleep() aus? Können die Standard-Funktionen
das genauso gut? Was passiert, wenn die Wartezeit durch ein Signal
unterbrochen wird?
Mit einem Echtzeitkernel sieht das noch mal ganz anders aus. Ja da kann
man das machen wenn man will. Ohne Echtzeitkernel funktioniert ein
Timerthread aber nicht wirkich präzise.
Und zum Thema sleep:
std::this_thread::sleep_for(std::chrono::nanoseconds(...))
Rolf M. schrieb:> Wie> sieht es z.B. mit clock_nanosleep() aus?
Es gibt:
https://en.cppreference.com/w/cpp/thread/sleep_for
Wie das genau in der jeweiligen C++-Bibliothek umgesetzt ist muss man
prüfen. Es wird aber letztendlich genauso den nanosleep-Syscall nutzen.
Rolf M. schrieb:> Was passiert, wenn die Wartezeit durch ein Signal> unterbrochen wird?https://stackoverflow.com/a/52869260
Alle Details vom Linux-Scheduling wird man mit std::thread natürlich
nicht nachbilden können. Aber wenn man es so viel wie möglich verwendet,
vereinfacht man sich ggf. später die Portierung, und std::thread fügt
sich besser in C++-Anwendungen als das pthread-API ein.
AbcAbc schrieb:> Die Frage ist eher: Warum bist du der Ansicht das einstellen zu müssen.
Die Frage kann man stellen, aber mit dem Thread-Thema hat sie nichts zu
tun - errno braucht man überall…
Grund ist, dass Linux kein suspend/resume für Threads kennt. Ich will
versuchen, diese Klippe dadurch zu umschiffen, dass ich (Timer-)Threads,
die den Haupt-Thread vorübergehend suspendieren müssten, eine höhere
Priorität gebe, und den gesamten Prozess auf einen Kern begrenze.
Ziel der Übung ist die Simulation eines µC, bzw. dessen
Interruptbehandlung.
> Dein Problem dürfte eben sein, dass du in Codeblocks, dass nur als> Linkerflag und nicht auch als Compilerflag mitgegeben hast.
Siehe hier: Beitrag "Re: Linux/c++: errno in multithreaded Code"
CB zeigt natürlich an, was Compiler und Linker treiben - siehe Anhang.
Das Make-System von CB funktioniert ziemlich gut, sofern man nicht die
ausgetretenen Pfade verlässt. Es gibt einige Spezialoptionen, von denen
man besser die Finger lässt, weil sie völlig unausgereift und buggy sind
- aber die brauche ich derzeit nicht.
> Ohne Echtzeitkernel funktioniert ein Timerthread aber nicht wirkich> präzise.
Das tut in meinem Fall nicht weiter weh. Es geht nur darum, die
Parallelität zwischen Hauptprogramm und ISR auf einem ein-kernigen µC
nachzubilden, ohne in den Applikationscode eingreifen zu müssen.
Uhu U. schrieb:> dass ich (Timer-)Threads,> die den Haupt-Thread vorübergehend suspendieren müssten, eine höhere> Priorität gebe, und den gesamten Prozess auf einen Kern begrenze.
Ziemlicher Hack! Kannst du das nicht mit Signalen machen (sigaction)?
Oder vor jedem (Instruktions-)Schritt des Simulators prüfen ob der Timer
abgelaufen ist?
Uhu U. schrieb:> CB zeigt natürlich an, was Compiler und Linker treiben - siehe Anhang.
Warum "-DCONST=/**/" und nicht einfach "-DCONST=" ?
"-D__AVR_ATmega328P__" und "-D__flash" ist gefährlich - Bezeichner,
welche mit __ anfangen, sind in C reserviert. Könnte es vielleicht sein,
dass das die Standard Library durcheinander bringt?
Hast du mal mein o.g. Programm kompiliert? Funktioniert das bei dir?
Niklas G. schrieb:> Hast du mal mein o.g. Programm kompiliert? Funktioniert das bei dir?
Nein, es compiliert nicht: error: ‘nullptr’ was not declared in this
scope
Wenn ich nullptr durch NULL ersetze, compiliert und bindet er.
Wenn ich getrennt compiliere und binde, geht das mit folgenden Kommandos
ebenfalls glatt:
> Ziemlicher Hack! Kannst du das nicht mit Signalen machen (sigaction)?
Nicht unter der Prämisse, dass am zu simulierenden µC kein Jota geändert
werden soll.
Der Mangel liegt eher bei Linux.
> Warum "-DCONST=/**/" und nicht einfach "-DCONST=" ?
Weil der Compiler das nicht anders frißt.
> "-D__AVR_ATmega328P__" und "-D__flash" ist gefährlich - Bezeichner,> welche mit __ anfangen, sind in C reserviert.
Das erste Symbol wird von avr-gcc definiert und das zweite hat den Sinn,
das dem Linux-gcc unbekannte Symbol __flash unschädlich zu machen.
Ich habe die -D*=/**/-Definitionen in den per Kommandozeile überall
includierten Header verschoben - geändert hat es nichts.
Interessant ist jedenfalls, dass der Compiler mit -D__flash= einen
Syntaxfehler produziert. Mit -D__flash=/**/ ist der weg.
> Könnte es vielleicht sein, dass das die Standard Library durcheinander> bringt?
Da muss ich nochmal genau prüfen, was da passiert.
Uhu U. schrieb:> Nein, es compiliert nicht: error: ‘nullptr’ was not declared in this> scope
Kompiliere mit -std=c++11. Wie alt ist dein GCC, dass das nicht
standardmäßig aktiv ist?
Uhu U. schrieb:> Wenn ich nullptr durch NULL ersetze, compiliert und bindet er.
Dann stimmt noch irgendwas anderes an deinem Projekt nicht. Reduziere
dein Projekt schrittweise so weit bis es zu meinem Mini-Programm
identisch ist; auf dem Weg dahin wird es irgendwann von kaputt zu
funktionierend übergehen...
Uhu U. schrieb:> Nicht unter der Prämisse, dass am zu simulierenden µC kein Jota geändert> werden soll.
Sollte hinkommen. Der Prozess wird unterbrochen. Emulierst du den uC,
oder kompilierst du den uC-Code für das Linux neu?
Uhu U. schrieb:> Weil der Compiler das nicht anders frißt.
Bei mir schon. Dann stimmt bei dir was nicht. Beachte dass es "-DCONST="
und nicht "-DCONST" ist.
Uhu U. schrieb:> Das erste Symbol wird von avr-gcc definiert und das zweite hat den Sinn,> das dem Linux-gcc unbekannte Symbol __flash unschädlich zu machen.
Da aber dein Linux-Programm wohl nicht mit dem AVR-GCC kompiliert wird,
ist das hier an der falschen Stelle. Wenn die libc irgendwo ein "#ifdef
__AVR_ATmega328P__" hat...
Uhu U. schrieb:> Ich habe die -D*=/**/-Definitionen in den per Kommandozeile überall> includierten Header verschoben - geändert hat es nichts.
Wenig überraschend.
Niklas G. schrieb:> Wie alt ist dein GCC, dass das nicht standardmäßig aktiv ist?
Ich habe im Moment Linux Mint 17 mit gcc version 4.8.4 (Ubuntu
4.8.4-2ubuntu1~14.04.4)
> Dann stimmt noch irgendwas anderes an deinem Projekt nicht.
Das bezog sich auf dein Testprogramm. Ich benutze in meinem Code nullptr
nicht, insofern ist das kein Problem.
> Sollte hinkommen. Der Prozess wird unterbrochen. Emulierst du den uC,> oder kompilierst du den uC-Code für das Linux neu?
Letzteres. Wenn ich den µC emulieren würde, hätte ich das Problem mit
den echt parallel laufenden Interrupt- und Timerthreads nicht.
Die Idee ist es, den 8-Bit-Code für x86 zu compilieren und dort in
Echtzeit laufen zu lassen. Lediglich die Register der Memory-Mapped-I/O
werden als C++-Objekte implementiert und dem µC-Code durch geschickte
Definitionen und Comlipation als C++ untergejubelt.
Das hätte gegenüber den üblichen emulierenden Simulatoren den Vorteil,
dass es sehr viel schneller läuft und vor allem, dass man mit einem ganz
normalen Linux-Debugger arbeiten kann. Zudem entfällt die doch recht
zeitraubende Flasherei.
Was man damit sicher nicht hinbekommt, ist exakt taktgenaues Verhalten.
Man kann damit aber zumindest die nicht zeitkritischen Algorithmen in
einem µC-Programm in aller Ruhe entwickeln und austesten, bevor man auf
die Hardware geht.
> Da aber dein Linux-Programm wohl nicht mit dem AVR-GCC kompiliert wird,> ist das hier an der falschen Stelle. Wenn die libc irgendwo ein "#ifdef> __AVR_ATmega328P__" hat...
Das _AVR_ATmega328P_ wird in den avr/* Headern benutzt. Es beißt sich
nicht mit den Standard-Bibliotheken. Das Symbol wird gebraucht, um aus
reinen #define-Headern die zum jeweiligen µC-Typ passenden Definitionen
zu selektieren. Der Name ist offensichtlich so gewählt, dass die
Kollisionswahrscheinlichkeit auch mit künftigen Standard-Headern gering
ist.
Uhu U. schrieb:> Ich habe im Moment Linux Mint 17 mit gcc version 4.8.4 (Ubuntu> 4.8.4-2ubuntu1~14.04.4)
Also eine über 4 Jahre alte Version.
Uhu U. schrieb:> Das bezog sich auf dein Testprogramm. Ich benutze in meinem Code nullptr> nicht, insofern ist das kein Problem.
Es ist allgemein keine verkehrte Idee aktuelle Software zu benutzen. Und
nullptr und viele weitere Dinge aus aktuellen C++-Sprachstandards sind
auch sehr sinnvoll.
Uhu U. schrieb:> Was man damit sicher nicht hinbekommt, ist exakt taktgenaues Verhalten.
Und exakt identisches Verhalten bezüglich Integer-Arithmetik oder
Speicherlayouts.
Niklas G. schrieb:> Es ist allgemein keine verkehrte Idee aktuelle Software zu benutzen. Und> nullptr und viele weitere Dinge aus aktuellen C++-Sprachstandards sind> auch sehr sinnvoll.
Das mag ja sein, aber avr-gcc ist auch schon ziemlich alt und das ist
hier "das Maß aller Dinge".
> Und exakt identisches Verhalten bezüglich Integer-Arithmetik oder> Speicherlayouts.
Wenn man konsequent Datentypen mit genau definierter Länge benutzt,
passt das. Bei sehr hardwarenaher Programmierung ist das die Regel. Bei
float/double geht es schief, aber da, wo man es auf einem µC braucht,
kommt es dann eher nicht auf identisches Speicherlayout an - zumindest
wenn das Zielmaschinchen keine entsprechende Hardware hat.
Uhu U. schrieb:> Das mag ja sein, aber avr-gcc ist auch schon ziemlich alt und das ist> hier "das Maß aller Dinge".
avr-gcc ist ein gcc, und daher naturgemäß immer aktuell. Zur Zeit also
in Version 8.3.
Oliver
Oliver S. schrieb:> avr-gcc ist ein gcc, und daher naturgemäß immer aktuell. Zur Zeit also> in Version 8.3.
Das ändert nichts daran, dass er auf dem Stand C99 ist…
Niklas G. schrieb:> Wie das genau in der jeweiligen C++-Bibliothek umgesetzt ist muss man> prüfen. Es wird aber letztendlich genauso den nanosleep-Syscall nutzen.
Nicht nanosleep, sondern clock_nanosleep. Da gibt's zwei wichtige
Unterschiede: Erstens kann man wählen, welche Uhr für die Zeitmessung
verwendet wird, und zweitens kann man den Aufwachzeitpunkt auch absolut
angeben.
Uhu U. schrieb:> Grund ist, dass Linux kein suspend/resume für Threads kennt.
Muss der Thread denn von außen schlafen gelegt werden können? Wenn er
sich auch selber schlafen legen kann, könntest du auch einfach mit
Semaphoren arbeiten.
> Ich will versuchen, diese Klippe dadurch zu umschiffen, dass ich> (Timer-)Threads, die den Haupt-Thread vorübergehend suspendieren müssten,> eine höhere Priorität gebe, und den gesamten Prozess auf einen Kern> begrenze.
Das klingt nach keinem guten Design, um ehrlich zu sein.
> Ziel der Übung ist die Simulation eines µC, bzw. dessen> Interruptbehandlung.Uhu U. schrieb:>> Ohne Echtzeitkernel funktioniert ein Timerthread aber nicht wirkich>> präzise.>> Das tut in meinem Fall nicht weiter weh. Es geht nur darum, die> Parallelität zwischen Hauptprogramm und ISR auf einem ein-kernigen µC> nachzubilden, ohne in den Applikationscode eingreifen zu müssen.
Aber es gibt doch dort gar keine Parallelität. Du willst an sich etwas,
das rein sequenziell abläuft, mit Threads umsetzen und dann erzwingen,
dass diese nicht paralellisiert werden.
Niklas G. schrieb:> Ziemlicher Hack! Kannst du das nicht mit Signalen machen (sigaction)?
Signale sind ja eigentlich das exakte User-Space-Pendant zu Interrupts.
Die sollten sich also ganz gut für die Simulation von ISRs eignen.
Uhu U. schrieb:>> Und exakt identisches Verhalten bezüglich Integer-Arithmetik oder>> Speicherlayouts.>> Wenn man konsequent Datentypen mit genau definierter Länge benutzt,> passt das.
Nicht unbedingt. Berechnungen werden immer mindestens mit int
ausgeführt, auch wenn sämtliche Operanden kleiner sind. Und int ist auf
avr und x86 verschieden groß. Es kann also durchaus Fallstricke geben,
in die man damit läuft, wenn ein Zwischenergebnis auf dem PC noch in int
passt, auf dem AVR aber nicht mehr.
> Bei sehr hardwarenaher Programmierung ist das die Regel.
Hmm, ich nutze sie eigentlich möglichst nur dort, wo wirklich auf
Register oder irgendwelche Schnittstellen zugegriffen wird.
> Bei float/double geht es schief, aber da, wo man es auf einem µC braucht,> kommt es dann eher nicht auf identisches Speicherlayout an - zumindest> wenn das Zielmaschinchen keine entsprechende Hardware hat.
float sollte eigentlich auch gehen, da der AVR meines Wissens die selbe
Repräsentation wie der PC nutzt. Bei double nicht, da das auf dem AVR
"baugleich" mit float ist.
Rolf M. schrieb:> Muss der Thread denn von außen schlafen gelegt werden können? Wenn er> sich auch selber schlafen legen kann, könntest du auch einfach mit> Semaphoren arbeiten.
Ich habe mich gerade durch die Signal-Behandlung gelesen - das scheint
die Lösung zu sein: der Signal-Handler kommt in den Hauptthread, in dem
auch der µC-Code läuft. Die Timer-Threads, die das Zeitverhalten der
Peripherie grob simulieren sollen, schicken nur ein Signal an den
Hauptthread und der Signal-Handler erledigt die Aufgabe dann in
Konkurrenz zum µC-Code.
Nachteil sind allerdings die zwei Latenzzeiten, die auf diesem Weg
entstehen.
> Aber es gibt doch dort gar keine Parallelität. Du willst an sich etwas,> das rein sequenziell abläuft, mit Threads umsetzen und dann erzwingen,> dass diese nicht paralellisiert werden.
Das Problem sind die Timer und Delays, die durch die Hardware verursacht
werden, z.B. beim USART. Letzterer wird ja vom µC-Programm nur über die
zugehörigen I/O-Register gesteuert und der Simulator soll das
Zeitverhealten zumindest grob nachbilden.
> Es kann also durchaus Fallstricke geben, in die man damit läuft, wenn> ein Zwischenergebnis auf dem PC noch in int passt, auf dem AVR aber> nicht mehr.
Für einen 8-Bitter muss man sich sowieso immer überlegen, ob die Breite
für die jeweilige Aufgabe ausreicht - das muss man eben im Simulator
genauso halten.
> Hmm, ich nutze sie eigentlich möglichst nur dort, wo wirklich auf> Register oder irgendwelche Schnittstellen zugegriffen wird.
Das ist generell nicht ratsam. Einfach nur int hinzuschreiben läßt einen
leicht die Grenzen aus den Augen verlieren.
> float sollte eigentlich auch gehen, da der AVR meines Wissens die selbe> Repräsentation wie der PC nutzt. Bei double nicht, da das auf dem AVR> "baugleich" mit float ist.
Das habe ich noch nicht überprüft - eine Stelle habe ich bis jetzt, wo
float ein Problem machen könnte; dort steht ein assert(0), damit ich
darüber fliege, sollte mir das Problem doch in die Quere kommen.
Ich drücke mich aber sowieso um die Fließkommaformate, wo es nur geht.
Uhu U. schrieb:> Nachteil sind allerdings die zwei Latenzzeiten,> die auf diesem Weg entstehen.
Was hast du denn vor, dass die Performance so krass wichtig ist?
Du lässt Code für einen 20 MHz AVR auf einem 2000 MHz PC laufen. Selbst
ein zyklengenauer Simulator sollte eigentlich problemlos einen AVR mit
dreistelligen MHz-Äquivalenten hinbekommen...
S. R. schrieb:> Was hast du denn vor, dass die Performance so krass wichtig ist?
Nichts besonderes.
> Du lässt Code für einen 20 MHz AVR auf einem 2000 MHz PC laufen. Selbst> ein zyklengenauer Simulator sollte eigentlich problemlos einen AVR mit> dreistelligen MHz-Äquivalenten hinbekommen...
Es gibt ja den Simulavr, der wirklich taktgenau auf dem PC simuliert -
der schafft keine Echtzeit.
Uhu U. schrieb:>> Du lässt Code für einen 20 MHz AVR auf einem 2000 MHz PC laufen. Selbst>> ein zyklengenauer Simulator sollte eigentlich problemlos einen AVR mit>> dreistelligen MHz-Äquivalenten hinbekommen...>> Es gibt ja den Simulavr, der wirklich taktgenau auf dem PC simuliert -> der schafft keine Echtzeit.
Das liegt aber daran, dass der Code interpretiert werden muss und das
die Taktgenauigkeit auch Performance kostet. Allerdings denke ich schon,
dass das auch in Echtzeit möglich sein sollte.
Ein Signalhandler jedenfalls wird jetzt keine riesigen Latenzzeiten
erzeugen. Abgesehen davon schafft auch der AVR es nicht, von einem
Takzyklus zum nächsten in der ISR zu sein.
Uhu U. schrieb:> Es gibt ja den Simulavr, der wirklich taktgenau auf dem PC simuliert -> der schafft keine Echtzeit.
Mit ein paar Aktualisierungen schafft der zwar immer noch keine
Echtzeit, da jeder Befehl halt so lange braucht, wie er braucht, aber
einen einstelligen MHz-Takt bekommt man im Mittel schon hin.
Oliver
Hat noch keiner versucht einen "AVR-Emulator" mit
Maschinencode-Erzeugung zu bauen? Praktisch ein AVR->AMD64 oder AVR->ARM
Maschinencode-Transpiler? Das wird doch bei diversen anderen Emulatoren
auch so gemacht.
Eine Abwandlung davon wäre ein AVR->Java Bytecode Umwandler (z.B. mit
der Java ASM Bibliothek) - die JVM übersetzt das dann typischerweise in
nativen Maschinencode. Wäre vermutlich nicht ganz so effizient, aber
dafür portabel.
Das Problem ist doch sowieso, daß einem eine Simulation des reinen
Prozessor-Cores fast nichts nützt. Jedes reales Programm nutzt Timer,
etc. und interagiert mit der Außenwelt.
Oliver
Niklas G. schrieb:> Hat noch keiner versucht einen "AVR-Emulator" mit> Maschinencode-Erzeugung zu bauen? Praktisch ein AVR->AMD64 oder AVR->ARM> Maschinencode-Transpiler? Das wird doch bei diversen anderen Emulatoren> auch so gemacht.
Wozu? C-Programme kann man doch auch auf dem PC compilieren und wenn man
die Peripherie des µC nachbildet, dann hat man einen Simulator - genau
das, woran ich hier bastele…
Oliver S. schrieb:> Das Problem ist doch sowieso, daß einem eine Simulation des reinen> Prozessor-Cores fast nichts nützt. Jedes reales Programm nutzt Timer,> etc. und interagiert mit der Außenwelt.
Eben. Mit der Peripherie kommt das Zeitverhalten ins Spiel und dann
wirds kompliziert. Das reale Zeitverhalten des PC ist dabei relativ
unwichtig, so lange er den µC nicht in Schneckentempo nachbildet.
Schwierig wird es, die PC-Zeit (gemessen in Maschinentakten!) halbwegs
korrekt ins Verhältnis des Periperie-Timings zu bringen.
Wenn man den µC nicht wirklich taktgenau emulieren will, muss man sich
was einfallen lassen, wie man die Stimulus-Generierung mit der
"Geschwindigkeit" des Prozessors synchronisieren kann.
Uhu U. schrieb:> Schwierig wird es, die PC-Zeit (gemessen in Maschinentakten!) halbwegs> korrekt ins Verhältnis des Periperie-Timings zu bringen.>> Wenn man den µC nicht wirklich taktgenau emulieren will, muss man sich> was einfallen lassen, wie man die Stimulus-Generierung mit der> "Geschwindigkeit" des Prozessors synchronisieren kann.
Na ja, es kommt darauf an, was man will. Einen vollständigen Emulator,
den man an Stelle des Originals in eine Hardware einbauen kann, oder
einen reinen Softwaresimulator, der wie SimulAVR Takte genau zählt,
dessen Arbeitsgeschwindigkeit aber egal ist.
Kaufen könnte man beide Versionen, wenn man wollte.
Oliver
Uhu U. schrieb:> Wozu? C-Programme kann man doch auch auf dem PC compilieren
Aber eben nicht 100% identisch. Bei einer Emulation des Prozessors kann
man die Takte zählen (um die Peripherie damit zu synchronisieren) und
auch zwischen den Instruktionen in ISRs springen, ohne Signale oder
mehrere Threads oder solche Hacks.