% Content-encoding: UTF-8 \documentclass[ngerman]{article} \usepackage[T1]{fontenc} \usepackage[latin1]{inputenc} \setcounter{secnumdepth}{0} \setcounter{tocdepth}{0} \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}{Abbildung} \begin{document} \title{Forth von der Pike auf — Teil 12} \author{Ron Minke} \maketitle %\vspace{-0.5ex} Die mit freundlicher Genehmigung der HCC--Forth--gebruikersgroep in der Vierten Dimension in einer Übersetzung von Fred Behringer wiedergegebene achtteilige Artikelserie erschien ursprünglich in den Jahren 2004 und 2005 in der Zeitschrift \emph{Vijgeblaadje} unserer niederländischen Forth--Freunde. Der Autor arbeitet fleißig an seinem Projekt weiter: Im Vijgeblaadje waren Teil 9 und 10 der Serie (deutsche Übersetzung in den VD-Heften 3--4/2007 und 2/2008) und dann Teil 11 (Übersetzung in VD 1/2009) erschienen. Auch die heutige Übersetzung (Teil 12) aus dem Niederländischen (aus dem Vijgeblaadje 74) stammt von Fred Behringer. Hier kommt nun also Teil 12 der Wiedergabe des Versuchs, ein AVR-Forth--System mit der Voraussetzung \emph{from scratch} zu erstellen. Dieser Teil handelt von den Überlegungen zur Einteilung des RAM--Speichers. \begin{multicols}{2} \section{Testen, Testen} Im letzten Teil meiner Serie \emph{Forth von der Pike auf} habe ich über die Einteilung der Bytes bei der Stack--Reihenfolge gesprochen. Nach einigem Hin-- und Herschieben der Festlegungen hat sich nun eine stabile Situation entwickelt, die auch dem ANSI--Standard genügt (siehe ANSI--Dokument, Punkt 3.1.4). Die Einteilung derselben Bytes im Dictionary im RAM--Speicher (Man erinnere sich: Diese Forth--Version kopiert sich selbst ins RAM) ist aber eine ganz andere Sache. Während des Testens des Forth--Kernels mit einer angepassten Version der Testsuite von John Hayes stellte es sich heraus, dass mit der Ausführung der Worte \texttt{2@} und \texttt{2!} etwas schieflief. \section{Die jetzige Situation} Die Einsichten aus Teil 11 der vorliegenden Serie wurden eingearbeitet. Im Forth--Kernel (im Flash--Speicher) wurde das Wort \texttt{LIT}, das das Einholen einer Zahl aus dem Dictionary besorgt, definiert als: \begin{small} \begin{verbatim} 0630: LIT: 83 Laenge des Textes 'LIT' mit msb=1 4C 'L' 49 'I' D4 'T' mit msb=1 0620 Link zum vorigen Wort 0200 Pointer zu Code_Lit: Maschinencode fuer LIT \end{verbatim} \end{small} Der zugehörige Maschinencode: \begin{small} \begin{verbatim} 0200: Code_Lit: Ld R16,X+ ; get lo value from RAM dictionary Ld R17,X+ ; get hi value, ; auto update IP to next word St -Y,R16 ; store lo value on data stack St -Y,R17 ; store hi value Next \end{verbatim} \end{small} An Platz \texttt{730} im Dictionary (im RAM) steht ein Stückchen Forth, das eine Zahl mit dem Wert \texttt{ABCD} auf den Datenstack legt: \begin{verbatim} 0730: .dw xxxx .dw yyyy .dw LIT .dw 0xABCD .dw zzzz \end{verbatim} Ein Hexdump dieses Stückchen RAMs liefert: \begin{verbatim} 0730: xx xx yy yy 30 06 CD AB zz zz ....... \end{verbatim} Der Maschinencode von \texttt{LIT} holt den Wert \texttt{ABCD} aus dem RAM und verfrachtet ihn auf den Stack. Das ist in Abbildung \vref{pike12:lit} zu sehen. \begin{figure*} \begin{center} \begin{verbatim} Code_Lit ( --- n ) tmp. Daten- AVR- Stack- Input Output Reg. Adresse SP -> 0 0 --- 0x100 1 1 n unter. Byte = CD R16 0x0FF 2 SP -> 2 n oberes Byte = AB R17 0x0FE 3 3 0x0FD \end{verbatim} \caption{\label{pike12:lit}Arbeitsweise von \texttt{LIT}} \end{center} \end{figure*} Bis zu diesem Punkt ist nichts Besonderes zu bemerken. Forth arbeitet so, wie man es von ihm erwartet. \section{Inhalt des RAMs} Wenn wir uns den Inhalt des RAMs näher betrachten, fällt auf, dass der Zahlenwert \texttt{ABCD} \emph{von hinten her} in den Speicher gelegt wurde. Das Gleiche gilt für den Speicherplatz des Wortes LIT (=\texttt{0630}). Für die Arbeit von Forth macht das natürlich nicht das Geringste aus; die zugehörigen Maschinencode--Abschnitte verarbeiten die Information korrekt. Doch hinterlässt das Ganze ein Gefühl der Unzufriedenheit. Ein Test mit einer \emph{Double}--Zahl im Assembler--Quelltext zeigt: \begin{verbatim} .org 0x410 .dd 0x12345678 \end{verbatim} Dies wird vom Atmel--Assembler in den Flash--Speicher übersetzt zu: \begin{verbatim} 0410: 5678 1234 \end{verbatim} Nach dem Kopieren ins RAM liefert ein Hexdump aus diesem Wert: \begin{verbatim} 0640: 78 56 34 12 ....... \end{verbatim} Auch hier steht diese Zahl nach unserem Gefühl \emph{verkehrt herum}. Außerdem fällt auf, dass das \emph{high word} dieser Zahl hintendran steht. Und das entspricht nicht dem, was im ANSI--Standard empfohlen wird. \section{Die Testsuite von John Hayes} Die Vermutung, dass da im Forth--Kernel doch noch etwas nicht in Ordnung ist, wird von einem Abschnitt aus der Testsuite von John Hayes bestätigt. Beim Testen der Worte \texttt{2@} und \texttt{2!} tritt die Fehlermeldung auf, dass da mit den Resultaten auf dem Datenstack etwas nicht stimmt. Der ursprüngliche Code im Forth--Kernel für das Wort \texttt{2@} ist (unter Hinzunahme der Zahlenwerte aus dem RAM): \begin{footnotesize} \begin{verbatim} ; 2@ Replace the 16-bit address on top of ; the data stack with the 32-bit ; nucleus contents d of that memory address. ; ; addr --- d ; ; Input Output ; ; 0 0 ; 1 lo byte addr = 40 1 lo byte lo word d = 78 ; Dsp --> 2 hi byte addr = 06 2 hi byte lo word d = 56 ; 3 3 lo byte hi word d = 34 ; 4 Dsp --> 4 hi byte hi word d = 12 ; 5 5 Code_TwoAt: Ld ZH,Y+ ; get hi address = 06 Ld ZL,Y+ ; get lo address = 40 Ld R18,Z+ ; get lo value lo word = 78 Ld R19,Z+ ; get hi value lo word = 56 Ld R16,Z+ ; get lo value hi word = 34 Ld R17,Z+ ; get hi value hi word = 12 St -Y,R18 ; put on data stack St -Y,R19 St -Y,R16 St -Y,R17 Next \end{verbatim} \end{footnotesize} Wenn wir mit diesem Maschinencode den Zahlenwert von Adresse \texttt{640} holen, wird das in der richtigen Reihenfolge auf den Datenstack gelegt. Jedoch \ldots\ im ANSI--Standard steht bei der Besprechung des Wortes 2@ (Punkt 6.1.0350) das Folgende: \glqq\ldots\ Das Wort 2@ entspricht der Hintereinander--Ausführung der folgenden Worte\grqq : \begin{verbatim} DUP CELL+ @ SWAP @ \end{verbatim} Wenn wir das mit demselben Zahlenwert \texttt{12345678} auf Adresse \texttt{640} im RAM durchführen, kommt etwas ganz anderes dabei heraus. Machen wir das mal schnell: \begin{verbatim} Start Stack --- 0640 DUP 0640 0640 CELL+ 0640 0642 @ 0640 1234 SWAP 1234 0640 @ 1234 5678 \end{verbatim} Wenn wir uns in Erinnerung rufen, dass (nach ANSI) der Wert auf der oberen Stackposition das MSD einer Zahl sein muss, dann sehen wir, dass das hier nicht der Fall ist. Der Test von John Hayes hat mit seinem Ergebnis Recht: Die bisherige Implementation des Wortes \texttt{2@} liefert nicht das richtige Resultat. \section{Und wie nun weiter?} Um das alles dem ANSI--Standard genügen zu lassen, müssen offenbar Worte und müssen Bytes vertauscht werden. Für den Maschinencode von \texttt{LIT} ist das simpel: Wir holen den Wert aus dem RAM \emph{andersherum} herein. Aber damit haben wir das Problem noch nicht bei der Wurzel gepackt. Das wirkliche Problem ist die Reihenfolge der Bytes im Flash--Speicher bei den \texttt{.dw}--Statements. Ein Standard--Aufruf zum Setzen eines Zahlenwertes ins Flash \begin{verbatim} .org 0x540 .dw 0xABCD \end{verbatim} liefert nach dem Assemblieren und dem Kopieren ins RAM \begin{verbatim} 0540: CD AB ....... \end{verbatim} Aber eigentlich wollen wir, dass dieser Wert hier erscheint als \begin{verbatim} 0540: AB CD ....... \end{verbatim} Die Lösung dieses Problems ist Gott sei Dank einfach: Es muss ein Macro--Befehl definiert und dann auf das Ganze angewandt werden, der beim Assemblieren die Reihenfolge der Bytes umdreht. Diesem Macro geben wir den Namen defwrd. \begin{verbatim} .macro defwrd .db high(@0), low(@0) .endmacro \end{verbatim} Der Aufruf der Testzahl \texttt{ABCD} liefert dann \begin{verbatim} .org 0x540 defwrd 0xABCD \end{verbatim} und nach dem Assemblieren und und dem Kopieren ins RAM erhalten wir \begin{verbatim} 0540: AB CD ....... \end{verbatim} Diese Abänderung hat auf den Assembler--Quelltext einen ziemlich großen Einfluss! Zum Glück hat der Editor eine \emph{global replace}--Funktion, die das bewältigt: Alle \texttt{.dw} in \texttt{defwrd} umwandeln. Was uns noch zu tun bleibt, ist das Anpassen des Maschinencodes für das Wort \texttt{2@}. Wie man sieht, werden die Register in einer anderen Reihenfolge angesprochen. \begin{verbatim} Code_TwoAt: Ld ZH,Y+ ; get hi address Ld ZL,Y+ ; get lo address Ld R17,Z+ ; get hi value hi word Ld R16,Z+ ; get lo value hi word Ld R19,Z+ ; get hi value lo word Ld R18,Z+ ; get lo value lo word St -Y,R18 ; put on data stack St -Y,R19 St -Y,R16 St -Y,R17 Next \end{verbatim} Nicht nur der Maschinencode für das Wort \texttt{2@} muss in Angriff genommen werden, alle Worte, die etwas mit dem Zugang zum RAM--Speicher zu tun haben, müssen verändert werden. Es geht um die Worte \texttt{LIT EXECUTE BRANCH ! @ +! 2@ 2! HERE (FIND) RP! SP! DoConstant DoUser ((EMIT)) NEXT} Nach dieser doch recht aufwändigen Aktion habe ich den kompletten Quelltext durch den Assembler gejagt und ins Flash gesetzt, die Speisespannung an die Testplatine gelegt und \ldots\ es funktioniert! Schnell noch den Test von John Hayes durchgeführt und wie zu erwarten: Keine Fehler! Uff \ldots\ eine ganze Menge Arbeit diesmal wieder und das wegen eines so \emph{einfachen Fehlers}. Damit haben wir jedoch nochmal einen weiteren Schritt in Richtung auf ein \emph{Forth--von--der Pike--auf}--System getan! Die Testsuite von John Hayes findet sich unter:\\ \url{ftp://ftp.taygeta.com/pub/Forth/Applications/ANS/core.fr} \end{multicols} % \end{document}