\documentclass[11pt,a4paper]{article} % 2006-07-07 EW Adventures-1.tex % 2006-07-22 EW Adventures-2.tex % 2006-08-14 EW Adventures-2a.tex % 2007-01-10 EW Adventures-3.tex % % Aufgebessert nachdem ich 'ne Reihe Optimierungen gemacht hatte % Und dann nochmal komplett umgerÀumt! % % language support \usepackage[german]{babel} %\usepackage[latin1]{inputenc} % can use Umlauts now "u instead of "u %\usepackage{lmodern} % better fonts %\usepackage{pslatex} % use native PostScript fonts \usepackage{url} % \url{} \path{} with correct "hyphenation" %\usepackage{fancyvrb} % for code examples % \voffset-10mm % \pagestyle{empty} % \pagestyle{plain} % \pagestyle{headings} % \renewcommand{\baselinestretch}{1.08} %\usepackage{xspace} \parindent=0pt %\newcommand{\Forth}{\textsc{forth}\xspace} \begin{document} \title{Adventures in Forth 3} \author{Erich W"alde} \maketitle \begin{multicols}{2} \section{Teil 1: Ausgaben auf \texttt{uart0}} \label{sec:uart0} Der R8C13-Controller hat eine weitere serielle Schnittstelle (\texttt{uart0}), die beim Programmieren nicht ben"otigt wird. "Uber diese sollen Daten verschickt werden. Die Daten sollen als ASCII-Zeichenkette verschickt werden, abgeschlossen mit CR LF. Auf ein Protokoll zum Absichern des Datentransports soll an dieser Stelle verzichtet werden. Es sind drei Aufgaben zu l"osen: \begin{enumerate}\itemsep=0pt\parskip=0pt \item Initialisieren der Schnittstelle \item Formatieren der zu verschickenden Zeichenkette \item Ausgabe der Zeichenkette auf die Schnittstelle \end{enumerate} Um die f"ur \texttt{uart0} wichtigen Register und Einstellungen zu finden, habe ich das Datenblatt konsultiert. Die Schnittstelle liegt auf den Pins 4 und 5 von Port 1. %---------------------------------------------- \begin{verbatim} $E1 Constant port1 \ port 1 $E3 Constant pddr1 \ port direction reg. 1 &4 Constant PinTxD0 \ P1.4 is TxD0 &5 Constant PinRxD0 \ P1.5 is RxD0 \ uart0 $A0 Constant U0MR \ mode register $A4 Constant U0C0 \ control register 0 $A5 Constant U0C1 \ control register 1 &0 Constant TE \ transmit enable bit &1 Constant TI \ transmit buffer empty? $B0 Constant UCON \ control register 2 &2 Constant U0RRM \ receive mode bit $A1 Constant U0BRG \ bit rate $A2 Constant U0TBRL \ transmit buffer, low \end{verbatim} Die Schnittstelle soll mit 38400 baud, 8 Datenbits, kein Parit"atsbit, 1 Stopbit und ohne handshake betrieben werden. Die zugeh"origen Einstellungen finden sich ebenfalls im Datenblatt. Schwierig ist das alles nicht, aber ein wenig Geduld hilft. %---------------------------------------------- \begin{verbatim} : uart0-init ( -- ) PinTxD0 port1 bset \ TxD0 is 1 PinTxD0 pddr1 bset \ TxD0 is output PinRxD0 pddr1 bclr \ RxD0 is input $05 U0MR c! \ 8N1, internal clock $00 U0C0 c! \ clock f1, TxD0 CMOS out, \ . data on falling edge, \ . lsb first U0RRM UCON bclr \ continuous receive OFF &32 U0BRG c! \ 38400 @ 20 MHz ; \end{verbatim} Als N"achstes definieren wir ein Wort, welches ein Zeichen auf \texttt{uart0} ausgibt. Zuerst warten wir, bis das letzte Zeichen "ubertragen ist, d.h.\ bis das Bit \texttt{TI} gel"oscht wurde. Danach schreiben wir das Zeichen in das Senderegister \texttt{U0TBRL}, und sagen dem Controller, dass ein neues Zeichen zu verschicken ist, durch Setzen des Bits \texttt{TE}. %---------------------------------------------- \begin{verbatim} : uart0emit ( n -- ) \ transmit buffer empty? BEGIN TI U0C1 btst UNTIL U0TBRL c! \ n to transmit buffer TE U0C1 bset \ enable transfer ; \end{verbatim} Dieses Wort l"asst sich jetzt schon einsetzen, um die serielle Verbindung zu pr"ufen. \texttt{uart0}, auf der Elektorplatine mit \textit{COM port} bezeichnet, wird mit einem Rechner verbunden (es gibt jetzt 2 Kabel vom Rechner zur Platine). Ein Programm wie \textit{minicom} oder \textit{Hyperterminal} liest dann die Zeichen, die der Kontroller verschickt. Wer die ASCII-Tabelle auswendig kann, ist klar im Vorteil: \begin{verbatim} Gforth terminal Press ENTER to get ok from connected device. Leave with BYE include adv3_uart0.fs ok uart0-init ok $48 uart0emit $61 uart0emit $6c uart0emit ok $6c uart0emit $6f uart0emit $21 uart0emit ok \end{verbatim} Das produziert am \textit{anderen Ende} ein freundliches \begin{verbatim} Hallo!_ \end{verbatim} wobei \texttt{\_} den Cursor bezeichnet. Die gr"o"ste H"urde w"are damit geschafft. Allerdings ist es schon ziemlich unpraktisch, eine Zeichenkette so umst"andlich auszugeben. Das Wort \texttt{type} ist in allen Forths vorhanden und gibt eine Zeichenkette aus. Wenn man ein wenig die Dokumentation studiert, dann findet man, dass \texttt{type} zwei Argumente auf dem Stapel erwartet: \texttt{(addr n -- )}. \texttt{type} erwartet dann eine Zeichenkette der L"ange \texttt{n} an der Adresse \texttt{addr}. Ein Wort von der Art wie \texttt{type} k"onnen wir uns selbst schreiben: %---------------------------------------------- \begin{verbatim} \ send n bytes starting at addr : uart0type ( addr n -- ) 0 DO \ do-loop consumes n dup I + \ { consumes copy of addr c@ uart0emit \ get+send byte LOOP \ } drop \ consumes addr ; \end{verbatim} Mit Hilfe des Wortes \texttt{s"} wird die Welt sch"on. \texttt{s"} produziert aus dem nachfolgenden Text (abgeschlossen mit \texttt{"}) eine Zeichenkette, und legt die Adresse und die L"ange auf den Stapel. \texttt{uart0type} benutzt diese Information und \begin{verbatim} s" Hallo!" uart0type \end{verbatim} produziert das gleiche freundliche \texttt{Hallo!} wie die "Ubung vorher, nur viel bequemer. Ein zus"atzliches Wort \texttt{uart0cr} vereinfacht die Sache weiter: \begin{verbatim} : uart0cr ( -- ) $0d uart0emit $0a uart0emit ; \end{verbatim} % ==================================================================== \section{Teil 2: Ausgabeumleitung} \label{sec:redir} Wenn man auf das Wort \texttt{type} gesto"sen ist und ein wenig in der Dokumentation von gforth (auch das Wort \texttt{see} wurde mein Freund) und/oder im Buch gelesen hat, dann ist es nicht sehr weit zu sagen: W"are doch sch"on, wenn man die gleiche Ausgabe am gforth-terminal, auf \texttt{uart0} und auf das LCDisplay benutzen k"onnte. Etwa so: \begin{verbatim} : msg s" blabla" ; : run to-lcd msg to-uart0 msg to-stdout msg ; \end{verbatim} Die kurze Antwort ist: \textit{Man kann}. Um dem gleichen Wort verschiedene Aufgaben unterzuschieben benutzt man so etwas wie \textit{Zeiger auf Funktionen}. Das haben wir bei \texttt{timeup} in der zweiten Folge schon einmal gesehen: Man kann die \textit{Ein\-sprung\-a\-dres\-se} eines Wortes in einer Variablen speichern und dann mit \texttt{execute} die Ausf"uhrung erreichen. Zur Erinnerung: \begin{verbatim} create Jobs ' job.tick , job.sec , ... ... ... DO ... I cells Jobs + @ execute ... LOOP \end{verbatim} Die Frage hei"st also: kann man mit den Worten \texttt{type} (gib eine Zeichenkette aus) und \texttt{emit} (gib ein Zeichen aus) so eine Akrobatik veranstalten? Also eigentlich m"usste man ja die Adresse von \texttt{type} in einer Variablen speichern und dann alle Worte, die eine Ausgabe machen, so umdefinieren, dass sie "uber die Variable auf die Worte \texttt{type} und \texttt{emit} zugreifen --- nee, das ist nicht sch"on, denn es gibt einige solcher Worte (\texttt{.} \texttt{u.} \texttt{d.} \texttt{d.r} \texttt{."} usw.). Da spart man nichts, wenn man die alle umschreiben muss. Jetzt stellt sich aber g"unstigerweise heraus, dass \texttt{type} selbst nur auf ein Wort namens \texttt{(type)} verweist. Das l"asst hoffen. Wir basteln uns also drei Variablen, die Zeiger auf die gerade ben"otigten Versionen von \texttt{type}, \texttt{emit} und der Vollst"andigkeit halber \texttt{cr} beinhalten. \begin{verbatim} Variable 'type \ pointer to correct "type" Variable 'emit \ pointer to correct "emit" Variable 'cr \ pointer to correct "cr" \end{verbatim} Dann brauchen wir drei Worte, die diesen Variablen die korrekten Werte verpassen, falls wir die Ausgaben auf \texttt{lcd}, \texttt{uart0} oder das gforth terminal (\texttt{stdout}) umbiegen wollen. Dabei gibt es noch eine kleine Schwierigkeit. Normalerweise liefert uns das Wort \texttt{'} (\textit{tick}) die Ein\-sprung\-a\-dres\-se des nachfolgenden Wortes --- au"ser in einer \texttt{:}-Definition. Dort muss man stattdessen \texttt{[']} benutzen. Das liegt daran, dass innerhalb einer \texttt{:}-Definition Forth im compile-Modus l"auft. Wir wollen aber nicht \texttt{'} einkompiliert haben, sondern das Ergebnis von \texttt{' wort}. Das Wort \texttt{[']} schaltet daher den compile-Modus vor"ubergehend aus. \begin{verbatim} : to-stdout ( -- ) ['] (type) 'type ! ['] (emit) 'emit ! ['] cr 'cr ! ; : to-lcd ( -- ) ['] lcdtype 'type ! ['] lcdemit 'emit ! ['] lcdcr 'cr ! ; : to-uart0 ( -- ) ['] uart0type 'type ! ['] uart0emit 'emit ! ['] uart0cr 'cr ! ; \end{verbatim} Jetzt fehlt noch die Verbindung zwischen den alten Worten und der Variablen, die auf die umgeleiteten Worte zeigt. \begin{verbatim} : >type ( -- ) 'type @ execute ; : >emit ( -- ) 'emit @ execute ; : >cr ( -- ) 'cr @ execute ; \end{verbatim} Die Umleitung l"asst sich jetzt aktivieren, indem man \texttt{type} auf \texttt{>type} zeigen l"asst. Das Wort \texttt{is} schiebt dem nachfolgenden \texttt{type} das Ergebnis von \texttt{['] >type} als Adresse der neuen Anweisungen unter. \begin{verbatim} : +redir ( -- ) ['] >type is type \ "type" output redirection ['] >emit is emit \ "emit" output redirection ; : -redir ( -- ) ['] (type) is type ['] (emit) is emit ; to-stdout \ default \end{verbatim} Und wie funktioniert das jetzt? Wir schreiben einen kleinen Test. In \texttt{init} wird die serielle Schnittstelle \texttt{uart0} initialisiert, einmal CR LF verschickt und die Anzeige auf dem LCDisplay gel"oscht. Dann wird die Umleitung eingeschaltet. \texttt{msg} produziert zwei Zeilen Ausgabe. Man beachte, dass hier nicht \texttt{cr}, sondern \texttt{>cr} verwendet wird. Das ist der Preis daf"ur, dass \texttt{cr} eben kein Zeiger auf ein anderes Wort ist. Wenn man jetzt dem Wort \texttt{cr} mit \texttt{' >cr is cr} etwas anderes zu tun unterschiebt, dann verliert man den Zugriff auf die Originalanweisungen. Das kann man dann auch nicht mehr zur"ucksetzen. Es sieht allerdings so aus, als w"urde \texttt{cr} nur vom Programmierer benutzt --- damit bleibt alles unter unserer Kontrolle. Wenn alles klappt, dann sieht die Ausgabe so aus: \begin{verbatim} cr run-test String 1 32 String 2 x \end{verbatim} \texttt{run-test} schickt diese Zeichenketten an alle drei Ausgabeger"ate: auf das LCDisplay, auf die serielle Schnittstelle und auf die Ausgabe im gforth terminal. \begin{verbatim} include adv3_uart0.fs include adv3_redir.fs : init-test uart0-init uart0cr lcdpage +redir ; : msg ." String 1" $20 s>d4 d.r >cr ." String" space ." 2" 3 spaces $78 emit ; : run-test init-test to-lcd msg to-uart0 msg to-stdout msg ; \end{verbatim} Wirklich sch"on. Man hat Zeiger-auf-Funktionen in der Gegend herumgebogen. Aber das geht doch mit \textsc{\$meine\_lieblings\_sprache} auch, oddrrr? Vielleicht. Aber in diesem Fall haben wir immerhin zwei Funktionen aus der Sprache (\texttt{emit}, \texttt{type}) verbogen --- auch wenn das netterweise schon vorbereitet war. Das f"uhrt dazu, dass wir die Worte \texttt{.}, \texttt{."}, \texttt{d.r} etc.\ f"ur jede Ausgabe einfach weiterverwenden k"onnen, wie wenn das immer so gegangen w"are. Zur"uckbiegen geht "ubrigens auch ohne Verluste. Ob das alles in \textsc{\$meine\_lieblings\_sprache} immer noch so einfach ist? Wenn man vor dem n"achsten \texttt{empty} noch \texttt{-redir} eingibt, dann kann man sich auch den Reset sparen. Erg"anzungen, Kommentare, Korrekturen sind ausdr"ucklich erw"unscht. Sie erreichen mich unter \url{ew.forth@nassur.net} \section{Referenzen} \begin{enumerate} \item \label{Adv1} E. W"alde, Adventures in Forth, Die 4. Dimension 3/2006, Jahrgang 22 \item \label{Adv2} E. W"alde, Adventures in Forth 2, Die 4. Dimension 4/2006, Jahrgang 22 \item \label{r8c-ds} Renesas R8C/13 Datenblatt, siehe \url{www.renesas.com} \end{enumerate} \end{multicols} \section{Listings} \begin{quote} \begin{small} \begin{multicols}{2} \listinginput[1]{1}{2007-01/adv3_uart0.fs} % uart0 module \listinginput[1]{1}{2007-01/adv3_redir.fs} % uart0 module \listinginput[1]{1}{2007-01/adv3_redir_test.fs} % uart0 module \end{multicols} \end{small} \end{quote} \end{document}