%% -*- coding:utf-8; -*- \renewcommand{\reftextbefore}{auf der vorherigen Seite} \renewcommand{\reftextfacebefore}{auf der gegenüberliegenden Seite} \renewcommand{\reftextafter}{auf der nächsten Seite} \renewcommand{\reftextfaceafter}{auf der gegenüberliegenden Seite} \renewcommand{\figurename}{Bild} \begin{document} \title{Forth auf dem Ben NanoNote} \author{David Kühling} \maketitle In der 2+3-Ausgabe der Vierten Dimension berichtete Carsten Strotmann über den OpenMoko-Wikireader, ein portables Gerät mit Open-Source-lizenzierten Bauplänen und Software, das ein Forth enthält. Nun möchte ich euch in diesem Artikel den großen Bruder des Wikireaders vorstellen: den Ben NanoNote. Gebaut wird er von Qi Hardware, einer Firma die von ehemaligen OpenMoko-Mitarbeitern gegründet wurde. Wie auch OpenMoko hat sich Qi Hardware der Entwicklung von Open-Source-lizenzierter Hardware verschrieben, und seit der Firmware-Version vom 17.$\,$11.$\,$2010 enthält der NanoNote nun auch von Hause aus mit gForth ein vollwertiges Forth-System. \begin{figure*}[b] \begin{center} \includegraphics[width=0.7\textwidth]{2010-04/nanonote.eps} \caption{\label{Nanonote:Bild}Der Ben NanoNote im Größenvergleich mit einem handelsüblichen Bleistift} \end{center} \end{figure*} \begin{multicols}{2} \subsection{Eine Kreuzung aus PDA und Netbook} Der NanoNote entspricht in der Bauweise einem stark geschrumpften Netbook. Die Daumen-Tastatur hat ein Qwerty-Layout, bei dem die oberste Tastenreihe mit Ziffern fehlt. Ersetzt wird diese durch Mehrfachbelegungen der anderen Tastenreihen. Es gibt tatsächlich alle Sonderzeichen, die sich ein Programmierer wünscht. Entsprechend geschrumpft ist auch das 3-Zoll-Display. Es bietet 320x240 Pixel mit 24-Bit-Farbwerten. Der 6x10-Font in der aktuellen Firmware stellt 53x24 Zeichen dar, nicht ganz ein Forth-Screen, aber doch völlig ausreichend zum Bearbeiten von Programmen. Ein Mono-Lautsprecher ist eingebaut, ebenfalls ein Mikrofon. Ein 3.5-mm-Klinkenstecker erlaubt auch Tonausgabe in Stereo. Gespart wurde bei den Anschlussmöglichkeiten von Peripheriegeräten. Lediglich eine USB-Mini-Buchse zum Anschluss an einen PC ist vorhanden, die auch auch zum Aufladen des Akkus dient. Eine USB-Schnittstelle im ``Host''-Modus zum Anschluss von USB-Geräten wird erst in einer Folgeversion des NanoNote vorhanden sein. Die 2GB an fest eingebautem Flash-Speicher im NanoNote können mittels preiswerter Micro-SD Karten um bis zu 16GB aufgestockt werden. 126g bringt das Ganze, samt Lithium-Ionen Batterie, auf die Waage. Leichter als so manches Mobiltelefon. Beziehen kann man den NanoNote in Deutschland über \href{http://pulster.de}{\texttt{pulster.de}}, für 119 {\euro} plus Versand. Etwas günstiger erhält man ihn aus dem Ausland über \href{http://hackable-devices.org}{\texttt{hackable-devices.org}} oder über \href{http://tuxbrain.com}{\texttt{tuxbrain.com}}, ab einer gewissen Stückzahl amortisieren sich dann die höheren Versandkosten. \section{Technische Details} Im NanoNote arbeitet ein Ingenic Xburst System-On-Chip, mit einer MIPS32-kompatiblen CPU, getaktet auf 336 MHz, angebunden an 32 MB SD-RAM. Die CPU kommt ohne Fließkomma-Einheit daher, dafür ist aber eine spärlich dokumentierte Vektor-Einheit für Multimedia-Zwecke vorhanden, die man mit moderatem Aufwand im gForth-Assembler unterstützen könnte. \section{Software} Die Firmware, mit der der NanoNote ausgeliefert wird, basiert auf OpenWRT-Linux. Aktuelle Firmware-Versionen präsentieren nach dem Booten einen einfachen grafischen Programmstarter. Aber wie bei Desktop-Linuxen, kann man mittels Strg+Alt+F2 auf eine Text-Konsole umschalten. Stört einen die kleine Schriftgröße der Linux-Konsole, startet man das Programm \verb|fbterm|, ein Terminal im Terminal, das moderne Grafikbibliotheken für die Schrift-Darstellung benutzt. Eine Eigenheit der Linux-Text-Konsole beim NanoNote ist, dass sie Text nicht farbig darstellen kann. Auch dabei schafft aber die Verwendung von \verb|fbterm| Abhilfe. \section{Inbetriebnahme} Zunächst bekommt der Benutzer ``root'' ein Passwort. Um dieses zu setzen, wechselt man per Strg+Alt+F2 auf die Konsole, und gibt ein: \begin{verbatim} $ passwd \end{verbatim} gefolgt von dem zu setzenden Passwort. Verbindet man den NanoNote per mitgeliefertem USB-Kabel mit einem PC, meldet sich dieser als Netzwerkgerät an. Jedenfalls, falls der PC unter Linux läuft, wovon ich im Folgenden ausgehe. Nun gibt man der PC-Seite der USB—Verbindung die IP Adresse 192.168.254.100: \begin{verbatim} $ ifconfig usb0 192.168.254.100 \end{verbatim} Und kann dann den NanoNote unter der Adresse 192.168.254.101 erreichen: \begin{verbatim} $ ping 192.168.254.101 \end{verbatim} Per SSH kann man sich jetzt über Netzwerk anmelden: \begin{verbatim} $ ssh root@192.168.254.101 \end{verbatim} Oder Dateien zum NanoNote kopieren \begin{verbatim} $ scp *.fs root@192.168.254.101: \end{verbatim} Wir loggen uns noch einmal auf dem NanoNote ein und starten \verb|gforth|. Schlägt das Kommando fehl, läuft der NanoNote wohl unter einer zu alten Firmwareversion. Der Kasten ``Aktualisierung der Firmware'' erläutert kurz, wie man das behebt. Wer gForth-Quelltexte direkt auf dem NanoNote editieren möchte, hat eine reichhaltige Auswahl an Editoren zur Verfügung: joe, jstar, jpico, jmacs und vi, um nur einige zu nennen. \newsavebox{\firmwareBox} \begin{lrbox}{\firmwareBox} \begin{minipage}{0.98\textwidth} \begin{multicols}{2} \section{Aktualisierung der Firmware} Zunächst benötigen wir auf dem Host-PC die \verb|xburst-tools| zum Hochladen der Firmware. Fertige Ubuntu/Debian Pakete findet man hier \cite{xburst-tools}, ebenso Tar-Files für andere Linux-Varianten. Danach startet man den Nanonote im USB-Modus durch Drücken der Taste ``u'' beim Startvorgang (am sichersten ist es, Power+``u'' gleichzeitig einige Sekunden gedrückt zu halten). Der Bildschirm sollte daraufhin schwarz bleiben, der normale Boot-Vorgang findet nicht statt. Zum Herunterladen der neusten Firmware aus dem Netz und dem darauf folgenden Hochladen auf den Nanonote verwendet man am besten das Shell-Skript \verb|reflash_ben.sh|: \begin{verbatim} $ wget http://downloads.qi-hardware.com/\ software/images/NanoNote/Ben/reflash_ben.sh $ chmod +x reflash_ben.sh $ ./reflash_ben.sh latest \end{verbatim} Um genau dieselbe Firmware-Version zu verwenden, die diesem Artikel zugrunde liegt, ersetze man \verb|latest| durch \verb|2010-11-17|. Nun benötigt man noch einige Geduld, bis der Schreibvorgang abgeschlossen ist. \paragraph{Warnhinweise:} Der USB—Modus des NanoNote ist nicht sehr fehlertolerant, weswegen man für eine sichere USB-Verbindung sorgen muss. Es sollte kein USB—Hub verwendet werden und man sollte das hochwertige USB-Kabel benutzen, mit dem der NanoNote ausgeliefert wurde. Standardmäßig schreibt das \verb|reflash_ben.sh| Skript auch den Boot-Loader neu. Falls dabei etwas schiefgeht, ist der NanoNote danach zunächst nicht mehr boot-fähig, nichteinmal den USB—Modus kann man mehr aktivieren. Ich empfehle daher, \verb|reflash_ben.sh| so zu modifizieren, dass der Boot-Loader nicht geschrieben wird. Das erreicht man durch folgendes Kommando: \begin{verbatim} $ sed -ie 's/B="TRUE"/B="FALSE"/g' \ reflash_ben.sh \end{verbatim} Zu weiteren Details zur Firmware-Aktualisierung sei auf \cite{software-image} verwiesen. Bei Problemen lohnt es sich auch immer, auf der NanoNote-Mailingliste \cite{mailinglist} nachzufragen. \end{multicols} \end{minipage} \end{lrbox} \begin{figure*}[t] \begin{center} \framebox{\usebox{\firmwareBox}} \end{center} \end{figure*} \section{Programmieren in Forth} Einfache Programme kann man nun nativ auf dem NanoNote verfassen und mittels gForth ausführen. Forth-Skripte erhält man, in dem man die Programme mit \begin{verbatim} #!/usr/bin/gforth \end{verbatim} beginnt, und diese dann mittels \verb|chmod +x| ausführbar macht. Man ist aber zunächst begrenzt auf den Funktionsumfang der in gForth enthaltenen Wörter. Insbesondere hat man keine einfache Möglichkeit, Grafik auszugeben, das macht das ganze etwas langweilig. Für interessantere Funktionalität benötigt man Zugriff auf die installierten Systembibliotheken. gForth enthält zwar eine Schnittstelle zu in C geschriebenen Bibliotheken, jedoch benötigt diese zur Laufzeit einen C-Compiler. Der NanoNote enthält jedoch keinen C-Compiler in der Standard-Firmware. Das Ganze ist nicht so schlimm, wie es scheint. gForth bietet nämlich dennoch die Wörter \verb|OPEN-LIB| und \verb|LIB-SYM|, mittels derer man Bibliotheken laden kann und die Adressen der enthaltenen Funktionen ermittelt. Ein Beispiel: \begin{verbatim} s" libc.so.0" open-lib CONSTANT libc s" sleep" libc lib-sym CONSTANT 'sleep 'sleep HEX . DECIMAL -> 2AB8EA60 ok \end{verbatim} Es fehlt dann lediglich ein Weg, diese Funktionen auch auszuführen. Diesen Mangel beheben wir, indem wir mit dem in gForth enthaltenen MIPS-Assembler ein Wort zum Aufruf von C-Funktionen ergänzen. Zum Verständnis folgt aber zunächst ein Abstecher zum gForth-Assembler für MIPS. \section{CODE für MIPS} Die MIPS-CPU hat einen extrem einfachen Befehlssatz. Die meisten CPU-Befehle haben jeweils 3 Register als Operanden. Der erste Operand ist das Ziel, gefolgt von zwei Quelloperanden. Einige Befehle benutzen statt einem Register eine konstante 16-Bit Zahl als zweiten Quelloperanden. In gForth werden sowohl Register als auch konstante Operanden ohne weiteren syntaktischen Zuckerguss als Zahlen notiert. Ob es sich um eine Konstante oder aber um ein Register handelt, entscheidet sich einzig und allein nach dem Namen des CPU-Befehls. Register 0 ist ein Dummy und liefert immer den Wert 0 bzw. verwirft alle Werte die hineingeschrieben werden. Der Befehl \verb|1 2 3 addu,| addiert Register 2 und 3 und speichert das Resultat in Register 1. Der Befehl \verb|1 2 123 addiu,| addiert die Konstante 123 zum Register 2 und legt das Resultat in Register 1 ab. Laden und Speichern erfolgt über die Befehle \verb|lw,| bzw \verb|sw,|, die nur einen Adressmodus kennen: der letzte Operand ist ein Register, das die Adresse enthält, der vorletzte Operand ist eine 16-Bit-Konstante, die zur Adresse hinzuaddiert wird. Der erste Operand ist für \verb|lw,| das Ziel, für \verb|sw,| die Quelle der Operation. Sprungbefehle wie \verb|jr,| haben die Eigenart, dass der nachfolgende Befehl erst noch ausgeführt wird, bevor tatsächlich gesprungen wird. Grob vereinfacht gesagt, benutzt gForth einen Fadencodeinterpreter für die Ausführung von Forth-Code, und so sehen Assemblerdefinitionen so aus, wie man das auch aus anderen klassischen Forth-Systemen kennt: Argumente vom Stack holen, Rückgabewerte auf den Stack legen, danach der Programmcode für NEXT. Hier z.$\,$B.\ eine \verb|CODE|-Definition von \verb|+| (funktioniert in \verb|gforth-fast|) \begin{verbatim} CODE + ( n1 n2 -- n3 ) 2 4 17 lw, \ lade [SP+4] nach R2 17 17 4 addiu, \ Stackpointer inkrement 21 2 21 addu, \ addiere [SP+4] zum TOS 22 0 16 lw, \ NEXT: Lade IP 22 jr, \ .. springe zu [IP] 16 16 4 addiu, \ .. inkrementiere IP um 4 END-CODE \end{verbatim} Die schlechte Nachricht ist jedoch, dass gForth in C geschrieben ist, damit die Zuordnung der Forth—Register zu Maschinenregistern automatisch vom C-Compiler vorgenommen wurde und je nach Version variiert. Das eben gegebene Beispiel für \verb|+| funktioniert deswegen nur mit \verb|gforth-fast|, und nicht mit \verb|gforth|. Auch wird es eventuell nicht in neueren gForth Versionen funktionieren. Seit Neustem gibt es in gForth deswegen eine alternative Möglichkeit, Maschinencodedefinitionen zu schreiben, die mit einer standardisierten Registerbelegung aufgerufen werden. Benutzt wird dabei die Konvention für Funktionsaufrufe des C-Compilers. Das heißt, der Maschinencode, den man schreibt, entspricht einer C-Funktion mit dem Prototypen \begin{verbatim} void *funktion(void *sp); \end{verbatim} Der Forth-Stackpointer geht als Argument herein; zurückgeliefert wird der neue Wert des Stackpointers\footnote{Das ist nur die halbe Wahrheit. In Wirklichkeit ist der Funktions-Prototyp \texttt{void *funktion(void *sp, double **fp);} und ermöglicht damit auch Zugriff auf den Fließkommazahlenstack. Da uns Fließkomma aber hier nicht interessiert, wollen wir uns von derartigen Details nicht ablenken lassen.}. Definitionen dieser Art werden mit \verb|ABI-CODE| statt \verb|CODE| eingeleitet. Dazu muss man jetzt nur noch wissen, dass bei C-Funktionsaufrufen auf MIPS-CPUs, die ersten 4 Argumente in Registern 4--7 übergeben werden und für Rückgabewerte die Register 2--3 dienen. Als temporäre Register, die nicht gesondert gesichert werden müssen, sind Register 8--15 ausgewiesen. Die Rücksprungadresse nach Funktionsaufrufen liegt in Register 31, Register 29 enthält den C-Stackpointer. Eine portable Definition für \verb|+| sieht somit wie folgt aus: \begin{verbatim} ABI-CODE + ( n1 n2 -- n3 ) 8 4 4 lw, \ lade [SP+4] nach R8 9 0 4 lw, \ lade [SP] nach R9 8 8 9 addu, \ R8 = R8+R9 8 4 4 sw, \ Resultat in [SP+4] speichern 31 jr, \ Funktions-Return 2 4 4 addiu, \ SP+4 als neuer SP zurück END-CODE \end{verbatim} \section{Aufruf von Bibliotheksfunktionen} Nun können wir versuchen, mit einem einfachen Maschinencode-Wort eine Brücke zu Bibliotheksfunktionen zu bauen. Als ersten Versuch rufen wir die Funktion \verb|sleep| auf. Ein Argument wird übergeben: die Zeit, die \verb|sleep| schlafen soll. Auf der Forth-Seite übergeben wir dieses Argument und dazu noch die Adresse der Funktion über den Forth-Stack. Das Argument laden wir in Register 4, die Adresse gehört in Register 25, bevor wir die Funktion anspringen. Register 25 zu verwenden, ist wichtig, da Bibliotheksfunktionen aus positionsunabhängigen Maschinencode bestehen, der unter der Annahme kompiliert wurde, dass die Adresse der aktuellen Funktion immer in Register 25 vorzufinden ist. Unser Brückenwort sieht also so aus: \begin{verbatim} ABI-CODE call1 ( x fn-addr -- ) 29 29 -8 addiu, 31 0 29 sw, \ Rücksprungadresse sichern 4 4 29 sw, \ Forth-SP sichern 25 0 4 lw, \ lade [SP] nach R25 4 4 4 lw, \ lade [SP+4] nach R4 31 25 jalr, \ Funktionsaufruf nop, 31 0 29 lw, \ widerherstellen R31, R4 4 4 29 lw, 29 29 8 addiu, 31 jr, \ Funktions-Return 2 4 8 addiu, \ SP+8 zurück END-CODE \end{verbatim} Wir testen, ob es funktioniert: \begin{verbatim} 10 'sleep call1 \end{verbatim} tatsächlich: die Ausführung benötigt genau 10 Sekunden. Das Ganze lässt sich auf Funktionen mit Rückgabewerten und beliebig vielen Argumenten verallgemeinern. Listing \verb|funcall.fs| enthält den entsprechenden Code für mehrere Brückenwörter, die verschiedene Argumentanzahlen unterstützen. Nun können wir z.B. vereinfacht schreiben: \begin{verbatim} s" printf" libc lib-sym CONSTANT 'printf s\" Hello World %i\0" DROP 123 'printf void(2xint) -> Hello World 123 ok \end{verbatim} Wir benutzen hierbei \verb|S\"..\0" DROP| statt \verb|S""|, da C Null-terminierte Strings erwartet. \section{Ein bisschen Zuckerguss} Um nicht für jede C-Funktion die Adresse erst mit \verb|LIB-SYM| zu ermitteln, dann für jeden Aufruf das richtige Brückenwort \verb|void(int)| etc. benutzen zu müssen, schaffen wir uns eine Reihe von import-Wörtern. Diese ermitteln die Adresse für eine C-Funktion, und definieren ein Forth-Wort gleichen Namens, das den Aufruf per Brückenwort übernimmt. Der entsprechende Code findet sich im Listing \verb|import.fs|. Wir können jetzt ganz kompakt schreiben: \begin{verbatim} s" libc.so.0" open-lib current-lib ! void(int): sleep void(2xint): printf 1 sleep -> ok s\" hello world %i\0" DROP 123 printf -> hello world 123 ok \end{verbatim} \section{Handwerkszeug} Jetzt importieren wir die grundlegenden Linux-Systemfunktionen, die notwendig sind, um auf das Grafik-Gerät zuzugreifen. Wir benötigen \verb|fileno|, das zu einem mit \verb|OPEN-FILE| generierten Dateihandle den zugehörigen Linux-Dateideskriptor ermittelt. Außerdem benutzen wir \verb|mmap| zum Einblenden von Gerätespeicher in den gForth-Prozess, und \verb|ioctl| um mit Linux-Gerätetreibern zu reden. \begin{verbatim} s" libc.so.0" open-lib current-lib ! int(int): fileno ( fid -- fd ) int(3xint): ioctl ( fd n1 x1 -- n2 ) int(6xint): mmap ( n1 fd a1 n2 x1 x2 -- a2 ) \end{verbatim} Dies und ein paar weitere Konstanten für die Nutzung von \verb|mmap| finden sich im Listing von \verb|linux.fs| \section{Es wird grafisch} \begin{figure*}[bt] \begin{center} \includegraphics[width=0.7\textwidth]{2010-04/mandelbr.eps} \caption{\label{Nanonote:Apfelmann}Wir zaubern mit gForth ein Apfelmännchen auf den Nanonote-Bildschirm} \end{center} \end{figure*} Das Fundament ist gelegt. Jetzt können wir auf die Linux-Grafik-Gerätedatei \verb|/dev/fb0| zugreifen. Das ist sogar noch einfacher als es klingt. Blenden wir mit \verb|mmap| den zu \verb|/dev/fb0| gehörenden Speicher in unseren Prozess ein, erhalten wir Zugriff auf den Videospeicher: \begin{verbatim} s" /dev/fb0" R/W OPEN-FILE THROW fileno CONSTANT fb 0 fb 0 320 240 * 4 * PROT_READ PROT_WRITE OR MAP_SHARED mmap CONSTANT video-mem \end{verbatim} \verb|video-mem| zeigt jetzt auf den Anfang des Grafikspeichers. 4 Byte pro Pixel: ein ungenutztes Byte, dann rot, grün, blau. 320x240 Pixel, von links nach rechts und oben nach unten. Um den Bildschirm rot zu färben, geben wir ein: \begin{verbatim} : makered ( -- ) 320 240 * 4 * 0 DO $FF0000 video-mem I + ! 4 +LOOP ; makred \end{verbatim} Es wird jedoch nicht alles Rot. Der Textcursor blinkt weiterhin und hinterlässt ein schwarzes Kästchen. Ein Aufruf von \verb|ioctl| sagt dem Linux-Kernel, dass unsere Konsole im Grafikmodus laufen soll, und deaktiviert den störenden Cursor: \begin{verbatim} s" /dev/tty" R/W OPEN-FILE THROW fileno CONSTANT console console KDSETMODE KD_GRAPHICS ioctl DROP \end{verbatim} Die vollständigen Grafikroutinen finden sich im Listing \verb|grafik.fs|. Falls wir per SSH-Login arbeiten, ersetzen wir \verb|/dev/tty| mit \verb|/dev/tty2| und drücken auf der NanoNote-Tastatur Ctrl+Alt+F2 um die zweite Konsole sichtbar zu machen. \section{Ein Apfelmännchen} Um die Grafik in Aktion zu erleben, wollen wir nun mit gForth ein Apfelmännchen (das Mandelbrot-Fraktal) auf den Bildschirm zaubern. Wie erwähnt, besitzt der NanoNote keine Fließkommaeinheit, und die Verwendung der Softwareemulation würde unser Programm extrem verlangsamen. Stattdessen verwenden wir eine einfache Festkommaarithmetik. Wir benutzen dafür die 32-Bit Ganzzahlen von gForth, und rechnen so, als wäre in der Mitte das Komma gesetzt. Addition und Subtraktion funktionieren dann weiter wie gewohnt. Lediglich nach einer Multiplikation müssen wir das Komma um 16 Binärstellen korrigieren. Die Festkommamultiplikation sieht also so aus: \begin{verbatim} : fix* ( fix1 fix2 -- fix3 ) M* 16 lshift swap 16 rshift or ; \end{verbatim} Das gesamte Apfelmännchen-Programm findet sich im Listing \verb|mandelbr.fs|. Um das Ganze mit maximaler Geschwindigkeit darzustellen, nutzt man folgendes Kommando: \begin{verbatim} gforth-fast --dynamic ./mandelbr.fs \end{verbatim} Das Ganze dauert nur 3 Sekunden, und hinterlässt ein Apfelmännchen samt blau-rot schimmernder Kontur auf dem Bildschirm. \figurename \vref{Nanonote:Apfelmann} lässt erahnen, wie das in Natura aussieht. \section{Der Hardware an den Kragen} Ganz nebenbei haben wir uns mit den grafischen Spielereien auch die Grundlage für ernsthaftere Hardware-Basteleien mit dem NanoNote geschaffen. Unten im Batteriefach liegen ein paar Lötpunkte für I/O Leitungen, die direkt an der CPU hängen. Auch die Leitungen des Micro-SD Ports entspringen direkt der CPU und lassen sich zu generischen I/O Leitungen umfunktionieren. Dazu benötigen wir Zugriff auf die entsprechenden Steuerregister der CPU, die alle auf \textit{physikalischen} Speicheradressen liegen. Unter Linux sehen wir aus gForth heraus zunächst aber nur \textit{logische} Adressen, mit \verb|@| und \verb|!| kommen wir also so einfach nicht weiter. Der Trick ist, dass wir per \verb|mmap| unter Verwendung der speziellen Gerätedatei \verb|/dev/mem| dennoch beliebige physikalische Adressbereiche in den gForth Speicherbereich einblenden können. Ein Blick ins Datenblatt \cite{jzdatasheet} offenbart, dass die für uns interessanten Register zur Steuerung der I/O Leitungen bei Adresse $10010000_h$ beginnen. An die Arbeit: \begin{verbatim} s" /dev/mem" R/W OPEN-FILE THROW fileno CONSTANT mem $10010000 mem 0 4096 PROT_READ PROT_WRITE OR MAP_SHARED mmap CONSTANT gpio-base \end{verbatim} Die Adressen ab \verb|gpio-base| referenzieren jetzt den gefragten physikalischen Speicher. Zum Test lesen wir den Status der I/O Pins, an der die Tastatur hängt. Laut Schaltplänen \cite{nanonotebp,nanonotegpio} liegen diese an Port D, an Adresse $\verb|gpio-base|+300_h$: \begin{verbatim} : test BEGIN gpio-base $300 + @ hex. 10 ms AGAIN ; test \ Abbruch mit Ctrl+C \end{verbatim} Drücken wir ein paar Tasten, können wir beobachten, wie der Pin-Status sich entsprechend ändert. Etwas komplizierter ist es, den Pegel von Pins aktiv zu setzen. Dafür müssen so einige Hardware-Register gesetzt werden. Fertige Routinen finden sich im Listing \verb|gpio.fs|. Testweise erwecken wir damit den eingebauten Buzzer zum Leben, der mit Pin 27 an Port D angesteuert wird (übrigens nicht zu verwechseln mit dem ebenfalls vorhandenen Lautsprecher): \begin{verbatim} io-init 27 #output port-D io-direction : click 27 port-D io-0pin! ; : clack 27 port-D io-1pin! ; : buzz BEGIN click 1 ms clack 1 ms AGAIN ; buzz \ Abbruch mit Ctrl+C \end{verbatim} Das Ganze erinnert an die Verwendung des PC-Parallelports zur Hardwaresteuerung. Allerdings verwenden die I/O-Pins des NanoNote 3-V-Pegel, und sind um mehrere Größenordnungen schneller als ein Parallelport. Auf der Mailingliste \cite{mailinglist} gibt es Berichte, nach denen bitweise mehrere MBit/s zu externer Hardware übertragen wurden. Wer weiß, was man so mit gForth noch alles zusammengebaut bekommt. \end{multicols} \renewcommand*{\refname}{Links} \begin{thebibliography}{5}% \renewcommand{\figurename}{Listing}% \bibitem{xburst-tools}\textsl{Xburst-Tools zum Brennen der Firmware}, \url{http://projects.qi-hardware.com/index.php/p/xburst-tools/downloads/} % \bibitem{software-image}\textsl{Informationen zur Firmware und zum Firmware Upgrade}, \url{http://en.qi-hardware.com/wiki/Official_Software_Image} % \bibitem{mailinglist}\textsl{Mailingliste zur Diskussion über den NanoNote}, \url{http://lists.en.qi-hardware.com/mailman/listinfo/discussion} % \bibitem{jzdatasheet}\textsl{Vollständige Dokumentation des System-On-Chip im Nanonote}, \url{http://www.gmun.unal.edu.co/cicamargoba/embebidos/Jz4725_pm.pdf} % \bibitem{nanonotebp}\textsl{Schaltpläne des NanoNote (korrekterweise: Schaltpläne der noch nicht gebauten nächsten Hardwarerevision)} \url{http://downloads.qi-hardware.com/hardware/qi_avt2/v1.0/orcad_sch/qi_avt2_v1.0.pdf} % \bibitem{nanonotegpio}\textsl{Belegung der I/O Leitungen im NanoNote} \url{http://en.qi-hardware.com/wiki/Hardware/Ben#GPIO_pins} % \end{thebibliography} %\newpage \section{Bibliotheksfunktionen aufrufen --- \texttt{funcall.fs}} \begin{small} \begin{quote} \listinginput[1]{1}{2010-04/funcall.fs} \end{quote} \end{small} \section{Bibliotheksfunktionen nach Forth importieren --- \texttt{import.fs}} \begin{small} \begin{quote} \listinginput[1]{1}{2010-04/import.fs} \end{quote} \end{small} \section{Import von Linux Systemfunktionen --- \texttt{linux.fs}} \begin{small} \begin{quote} \listinginput[1]{1}{2010-04/linux.fs} \end{quote} \end{small} \section{Zugriff auf den Grafikspeicher --- \texttt{grafik.fs}} \begin{small} \begin{quote} \listinginput[1]{1}{2010-04/grafik.fs} \end{quote} \end{small} \section{Zeichnen eines Apfelmännchens --- \texttt{mandelbr.fs}} \begin{small} \begin{quote} \listinginput[1]{1}{2010-04/mandelbr.fs} \end{quote} \end{small} \section{Zugriff auf die I/O Ports --- \texttt{gpio.fs}} \begin{small} \begin{quote} \listinginput[1]{1}{2010-04/gpio.fs} \end{quote} \end{small} \end{document} % Local Variables: % ispell-local-dictionary : "de-neu" % compile-command: "make -C .." % coding : utf-8 % End: