c't

c't-Projekte - Mailinglisten


[Voriger (Datum)] [Nächster (Datum)] [Voriger (Thread)] [Nächster (Thread)]
[Nach Datum][Nach Thread]

Re: [ct-bot] Basic-Interpreter (für c't - Bot)

Absender: Timo Sandmann
Datum: Fr, 03.12.2010 18:47:38
In-reply-to: <4CF809BA.3070600@xxxxxxx>
References: <1ac236efdb2ae353dba0652e0009d0d7.squirrel@xxxxxxxxxxxxxxxxxxx> <BDD47587-412D-4D50-AC42-4B488A95575E@xxxxxxxxxxxxxxx> <4CF809BA.3070600@xxxxxxx>


Hallo,

Am 02.12.2010 um 22:03 schrieb Uwe Berger:
> naja, auch 4kB bzw.16 kB SRAM sind nicht unendlich viel. Selbst ein kurzes Basic-Programm könnte leicht diesen RAM dynamisch "zumüllen", je nach der Komplexität eines Ausdrucks (gerade hier wird intensiv mit Rekursionen gearbeitet). ... und es gibt bestimmt auch Dinge die ihr programmieren wollt und SRAM verbrauchen.

es ging mir eigentlich nur um den zusätzlichen RAM Bedarf durch den Puffer für eine Zeile. Dessen Größe ist bekannt und nicht dynamisch.

> 10ms sind fast eine Ewigkeit, aber das Anliegen ist mir schon verständlich. Wenn der Basic-Interpreter vernünftig, und so wie gedacht eingebaut wird, wird nach jeder Programmzeile die Kontrolle wieder an das "Hauptprogramm" übergeben.

Aber (soweit ich weiß) nur, solange kein Sprung ausgeführt wird. Und wenn nun das Programm nach Zeile X abgesucht wird, fällt es IMHO schon ins Gewicht, ob man pro Zeichen oder pro Zeile Daten nachlädt. 

> Frage, gerade diese wichtigen Funktionen, wie Sensorzustandwechsel, sind nicht in Interrupt-Routinen verpackt?

Nein, das macht beim vorhandenen Verhaltenssystem aus verschiedenen Gründen keinen Sinn. Die angesprochenen Abgrundsensoren sind außerdem analog, ihre Daten müssen also auch erst noch vom ADC verarbeitet werden. 

> sagen wir es mal so, gerade sinnvoll implementierte Routinen zum Schreiben/Lesen von SD-Karten sollten intern einen Bufferspeicher verwenden, auf den in der Regel ein Block (meist 512 Byte bei FATxx) von der Karte eingelesen wird und sämtliche Zugriffsroutinen (Lesen, Schreiben, Positionieren) arbeiten auf diesem Buffer.

Ja, ist auch so implementiert.

> Warum sollte dann also noch ein weiterer Buffer vorhanden sein, wir arbeiten doch schon im RAM...

Weil der Zeilenanfang nicht auf die Blockgröße ausgerichtet ist in einer Textdatei. 

> Mit der Bemerkung zu atoi und strcmp hast du natürlich recht. Aus diesem Grund ist ersteres ganz aus dem Code verschwunden (Zahlen werden jetzt von Hand und sind wahrscheinlich Maschinencode-sparender umgesetzt). strcmp existiert natürlich noch, da eine eine eigene Implementierung nicht so effektiv wäre, und da gibt es noch einen kleinen Buffer (;-)), der so groß, wie die maximale Befehlswortlänge ist (tokenizer.c; Routine get_next_token()).
> 
> Achso, mit dem Zeilenbuffer wird auch wieder eine künstliche Beschränkung geschaffen, die max. Basic-Zeilenlänge ist begrenzt (ich gehe davon aus, dass kein malloc verwendet wird)...

Na ja, eine Beschränkung der maximalen Zeilenlänge gab es eh schon im Code, die habe ich daher auch einfach als Obergrenze für den Puffer genommen. Ohne Begrenzung der Zeilenlänge wäre es natürlich schöner, das stimmt.
Ich fand es außerdem auch zum Debugging ganz hilfreich, immer die aktuelle Zeile in einem Puffer zu haben. 

> bei den 3 Varianten handelt es sich, wie auch einleitend bemerkt, um BEISPIELE, die ich zum Testen verwendet habe. Sie sollen nur aufzeigen, wie diese Defines in tokenizer_access.* gemeint sind! Aber gerade das 3.Beispiel zeigt, dass man diese Defines auch mit eigenen Funktionen bestückn kann. fread, fseek sind durch die Routinen zu ersetzen, die die gleiche bzw. ähnliche Funktionalität für eure SD-Karten-Zugriffe haben. Mir ist schon klar, dass es keine libc für den Bot gibt!

Das ist schon klar. Der Hintergrund ist einfach, dass die Version, die Frank hier veröffentlicht hat, das komplette Programm in einen statischen Puffer geladen hat. Das war für den Bot ungünstig, daher habe ich es leicht umgebaut, so dass das Bot-Dateisystem verwendet werden kann. Dieses liest dann eine Zeile in den Puffer, das erschien mir am passendsten, zumal wir die Routinen dafür auch an anderer Stelle benutzen können. Die Hauptmotivation, das so umsetzen, lag darin, möglichst wenig am Code ändern zu müssen. 

> (Nebenbei, da ich es leid war, ständig meinen mega16 zu flashen, gibt es die Linux-Versionen des Interpreters und ist auch dann letztendlich der Antrieb dafür, dass er plattformunabhängig ist und bleibt. Wahrscheinlich analog eurem Simulator....)

Im Bot-Code läuft er jetzt übrigens einwandfrei unter Linux, Mac OS X und Windows. 

> wahrscheinlich könnte man dies auch in die Defines in tokenizer_access.* verpacken, es muss ja nicht unbedingt p++, *p, fread, fseek o.ä. drinstehen. Es zählt nur das Ergebnis des jeweiligen Defines, dahinter könnte sich auch eine ausgeklügelte Speicherverwaltung verbergen, solange die "Schnittstellen-Defintionen" eingehalten werden.

Ja, wenn jemand Lust und Zeit hat, das entsprechend umzubauen, so dass es direkt mit der neuen Basic-Version funktioniert, sehr gern. Solange der Code auf dem Bot dann noch genauso gut funktioniert wie jetzt, übernehme ich einen entsprechenden Patch selbstverständlich auch ins SVN. 
Ich hatte meine Änderungen (die nur sehr gering waren) so vorgenommen, wie sie jetzt sind, weil es mir so am geeignetsten (aus Bot-Sicht) erschien und Frank meinte, das Basic-Projekte werde derzeit nicht weiterentwickelt. Das Ganze muss im Bot-Code aber nicht so bleiben, erstens befindet es sich sowieso "nur" in einer Art Beta-Version ("Devel-Zweig") und zweitens sind Änderungen, die etwas bringen, natürlich immer willkommen.

> hatte ich mir bis jetzt geschenkt, da es sich nicht lohnte (Speicherverbrauch klein)

Genaue Zahlen habe ich nicht mehr im Kopf, aber es brachte eine ganze Menge an Ersparnis. Vermutlich weil Frank recht viele C-Variablen (alle Bot-Sensordaten) in die Liste aufgenommen hat.

> und Stichwort Plattformunabhängigkeit, ich hätte auch dort einen Define-Konstrukt einbauen müssen..., naja, kommt vielleicht doch noch.

Das Problem kenne ich sehr gut, wir haben aber eh schon globale #defines wie #define strcmp_P stcmp oder #define pgm_read_byte(_addr) *(_addr) usw. im Code, falls für PC compiliert wird. Von daher funktionierte das out-of-the-box ohne weiteren Umstand.

Wünsche ein schönes Wochenende,
Timo