<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">%\documentclass[ngerman]{article}
%\usepackage[T1]{fontenc}
%\usepackage[latin1]{inputenc}
%\setcounter{secnumdepth}{0}
%\setcounter{tocdepth}{0}
%\usepackage{alltt}


% Forth von der Pike auf
% Teil 6

%\begin{document}
%\title{Forth von der Pike auf --- Teil 6}
%\author{Ron Minke}
%\maketitle

%\newcommand{\inst}[1]{\texttt{#1}}
%\newenvironment{asm}{\begin{center}\begin{tabular}{llp{0.6\columnwidth}}}{\end{tabular}\end{center}}
%\newcommand{\lab}[2]{\multicolumn{2}{l}{\texttt{#1}}&amp;#2}
%\newcommand{\instr}[2]{ &amp;\inst{#1} &amp;  #2}

%Die hier mit freundlicher Genehmigung der HCC--Forth--gebruikersgroep %wiederzugebende achtteilige Artikelserie erschien in den Jahren 2004 und 2005
%in der Zeitschrift \emph{Vijgeblaadje} unserer niederlÃ¤ndischen Forth--%Freunde.\\ Ãœbersetzung: Fred Behringer.

%Dieses ist die Folge sechs der Geschichte Ã¼ber den Versuch, ein Forth--System mit der Voraussetzung \emph{from %scratch}\/, zu erstellen.


%\begin{multicols}{2}




% In dieser Folge sehen wir uns die Hardware--Ausstattung des Systems an. 
Wir sehen uns nun die Hardware--Ausstattung des Systems an. 
Das System hat eine Standard--AusfÃ¼hrung und besteht aus einem AVR--Prozessor, einem Adress--Latch und einem RAM--Speicher. Man beachte, dass das Ã¼bliche EPROM fehlt. Das sitzt als Flash--Speicher im Prozessor selbst. Und in diesem Flash--Speicher sitzt nun wiederum unser Vorhaben, das AVR--Forth. Wir gehen davon aus, dass ein serieller Anschluss in Form eines im Prozessor--Chip vorhandenen UARTs zur VerfÃ¼gung steht. Auch mÃ¼ssen wir natÃ¼rlich einen AVR--Prozessortyp wÃ¤hlen, der externes RAM ansteuern kann (das kÃ¶nnen sie durchaus nicht alle).

\section{Indirekt gefÃ¤delt, direkt gefÃ¤delt, unterprogrammgefÃ¤delt???}

Bevor wir die verschiedenen FÃ¤delungsarten (threads) besprechen, brauchen wir noch eine Methode, \mbox{\inst{:}--Definitionen} in Forth ins RAM zu setzen. Wie wir das tun, ist im Augenblick nicht so wichtig. Wir gehen davon aus, dass es ganz \emph{normal} mÃ¶glich ist. Ausgangspunkt ist die Definition

\begin{verbatim}
		:    QUADRAT   DUP   *   ;
\end{verbatim}

Irgendwo in unserem Forth--System verwenden wir das Wort \inst{QUADRAT}. Um das zu Sagende besser ins Bild zu bringen, nehmen wir ein paar fiktive Speicheradressen an, wo die verwendeten Worte abgelegt sind. Den {\bf Aufruf} von \inst{QUADRAT} finden wir beispielsweise an der Hex--Adresse 9812. Die {\bf Definition} von \inst{QUADRAT} finden wir an Adresse 834F. Das Wort {\tt DUP} ist ein Low--Level--Codewort an Adresse 0426 im Flash--Speicher und \inst{*} ist eine High--Level-- (eine \inst{:}--) Definition an Adresse 1278 im Flash--Speicher. FÃ¼r ein traditionelles indirekt gefÃ¤deltes Forth kÃ¶nnen wir jetzt den folgenden Speicherauszug zeichnen. Abbildung \ref{minke6:indirect} zeigt ein Beispiel, bei dem je zwei Bytes eine Zelle bilden.

%\begin{figure*}
%\includegraphics[width=\textwidth]{2007-Sonderheft-AVR/indirect}
%\caption{Indirekte FÃ¤delung}\label{minke6:indirect}
%\end{figure*}

Wir nehmen an, dass der IP jetzt auf die Stelle 9812 zeigt, so dass also bei Aufruf von \inst{NEXT} die Definition \inst{QUADRAT} ausgefÃ¼hrt wird.

Was geschieht nun genau? Wir verwenden den einfachen Befehlssatz, den wir in ganz zu Anfang eingefÃ¼hrt hatten (man achte auf die Zahlenbeispiele):

\begin{asm}
\lab{NEXT:}{IP zeigt auf das als nÃ¤chstes auszufÃ¼hrende Wort an Adresse 9812}\\
\\
\instr{MOV W,(IP)}{Kopiere den Inhalt von IP (=8359), die CFA des als nÃ¤chstes auszufÃ¼hrenden Wortes, ins Register W.}
\end{asm}
\begin{asm}
\instr{INC IP}{Setze den IP so, dass er auf das Wort NACH dem momentan
bearbeiteten zeigt, um da unmittelbar weiterzuarbeiten (=9814).}\\
\instr{MOV Z,(W)}{FÃ¼hre den Maschinencode aus, dessen Adresse jetzt im
W--Register (=0734) sitzt. Verwende Z als Zwischenregister.}\\
\instr{JMP (Z)}{Gehe Ã¼ber einen indirekten Sprung in den Maschinencode.}
\end{asm}

\begin{figure*}
\rotateright{\includegraphics[width=\textwidth,angle=90]{2007-Sonderheft-AVR/direct}}
\caption{Direkte FÃ¤delung}\label{minke6:direct}
\end{figure*}

WÃ¤re \inst{QUADRAT} eine Maschinencode--Definition gewesen, wÃ¤ren wir nun fertig. Das StÃ¼ckchen Maschinencode wird ausgefÃ¼hrt und wir springen auf das nÃ¤chste \inst{NEXT} zurÃ¼ck, das uns zu Platz 9814 leitet. \inst{QUADRAT} ist jedoch ein High--Level--Wort. Es enthÃ¤lt keinen Maschinencode, sondern einen thread, eine Liste von Adressen. Um diese Definition ausfÃ¼hren zu kÃ¶nnen, muss der Interpreter an Adresse 835B, dem Parameterfeld von \inst{QUADRAT}, aufs Neue gestartet werden. Wir mÃ¼ssen aber auch den alten Wert von IP sichern, um da dann fortfahren zu kÃ¶nnen, wenn das Wort \inst{QUADRAT} abgearbeitet ist. Da wir gerade einen indirekten Sprung ausgefÃ¼hrt haben, mÃ¼ssen wir hierzu auf ein StÃ¼ckchen Maschinencode stoÃŸen. Das ist der Code fÃ¼r \inst{DOCOL} (lesen Sie dort noch einmal kurz nach). Dieses StÃ¼ckchen Maschinencode ist fÃ¼r jede High--Level--Definition dasselbe. Wir wiederholen den Pseudocode:

\begin{asm}
\lab{DOCOL:}{}\\
\\
\instr{PUSH IP}{Sichere den momentanen IP auf dem Returnstack (=9814)}\\
\instr{INC W}{Zeige auf das nÃ¤chste Wort (=835B)}\\
\instr{MOV IP,W}{Kopiere diesen Pointer als neuen IP}\\
\\
\instr{NEXT}{Fahre beim nÃ¤chsten Wort fort}
\end{asm}

Wir sind nun bei der AusfÃ¼hrung der Definition \inst{QUADRAT} eine Ebene tiefer gerutscht. Die Situation, in der wir uns jetzt befinden, ist eigentlich dieselbe wie an unserem Ausgangspunkt, das AusfÃ¼hren einer Reihe von Definitionen (Worten). Wir sind auf indirekte Weise hierher gelangt, Ã¼ber Zeiger (Pointer). Diese Vorgehensweise ist die traditionelle altmodische Art von Forth. Das ist die indirekt gefÃ¤delte Methode.

Es ist klar, dass wir auch noch zurÃ¼ck mÃ¼ssen. Haben wir das Wort \inst{*} auf dieselbe Weise ausgefÃ¼hrt, so stoÃŸen wir auf das Wort \inst{EXIT}. Dieses Wort ist der Returnbefehl, der in den Speicher gesetzt wird, wenn der Forth--Compiler auf das Wort \inst{;} (Ende der Definition) trifft. \inst{EXIT} macht das Umgekehrte von \inst{DOCOL}. In Pseudocode sieht das so aus:

\begin{asm}
\lab{EXIT:}{Die RÃ¼ckkehradresse steht auf dem Returnstack}\\
\\
\instr{POP	IP}{Stell die Adresse des als nÃ¤chstes auszufÃ¼hrenden Wortes wieder her
(=9814)}\\
\instr{NEXT}{Fahre dort fort, wo wir nach dem AusfÃ¼hren des Wortes QUADRAT
verblieben waren}
\end{asm}

Die charakteristischen Merkmale eines indirekt gefÃ¤delten Forths:
Jedes Forth--Wort hat ein Codefeld von genau einer Zelle (hier 2 Bytes). High--Level-- (\inst{:}--) Definitionen compilieren fÃ¼r jedes Wort genau eine Zelle in die Definition. Der Forth--Interpreter muss doppelt indirekt arbeiten, um die Adresse des schlieÃŸlich auszufÃ¼hrenden Maschinencodes zu finden, erst Ã¼ber IP, danach dann Ã¼ber W.

\begin{figure*}
\rotateright{\includegraphics[width=\textwidth,angle=90]{2007-Sonderheft-AVR/subroutine}}
\caption{Unterprogramm--FÃ¤delung}\label{minke6:subroutine}
\end{figure*}


\section{Direkt gefÃ¤delter Code}

Der Unterschied ist klein: Beim direkt gefÃ¤delten Code steht im Codefeld keine Adresse, sondern Maschinencode. Oft hat der Code die Form von \inst{JMP} adresse oder \inst{JSR} adresse, aber es kann natÃ¼rlich auch eine vollstÃ¤ndig ausgeschriebene Routine sein, die auf \inst{NEXT} endet (siehe Abbildung \ref{minke6:direct}).

%\begin{figure*}
%\includegraphics[width=\textwidth]{2007-Sonderheft-AVR/direct}
%\caption{Direkte FÃ¤delung}\label{minke6:direct}
%\end{figure*}

Da \inst{NEXT} nun eine Indirektionsstufe weniger auszufÃ¼hren braucht, wird es ein StÃ¼ckchen einfacher: 
\begin{asm}
\lab{NEXT:}{IP zeigt auf das als nÃ¤chstes auszufÃ¼hrende Wort auf Adresse 9812}\\
\\
\instr{MOV W,(IP)}{Kopiere den Inhalt von IP (=8359), die CFA des als nÃ¤chstes
auszufÃ¼hrenden Wortes, ins W--Reg.}\\
\instr{INC IP}{Setze den IP so, dass er auf das Wort nach dem momentan
bearbeiteten zeigt (=9814), um da unmittelbar weiterarbeiten zu kÃ¶nnen.}\\
\instr{JMP (W)}{Springe direkt zum Maschinencode (=0734)}
\end{asm}

Der letzte Befehl in diesem Beispiel ist ein \inst{JMP}. Und hier liegt zugleich das Problem unseres AVR--Forth--Systems: Der Prozessor wurde so entworfen, dass im RAM--Speicher nichts anderes als Daten liegen kÃ¶nnen. Der auszufÃ¼hrende Maschinencode findet sich einzig und allein im FLASH--Programmspeicherbereich des Prozessors. Und sollten Sie die Maschinencodebefehle ins RAM setzen, dann kÃ¶nnten diese auf keine einzige Art ausgefÃ¼hrt werden. Der Trick des Aufeinanderlegens der beiden Speicherplatzarten (Programmbereich und Datenbereich), so wie er bei der Prozessorserie 8052 Ã¼blich ist, greift hier nicht. Schade, mit dem AVR--Prozessor ist keine direkt gefÃ¤delte Forth--Version mÃ¶glich!


\section{UnterprogrammgefÃ¤delter Code}

Eigentlich kÃ¶nnen wir es nun schon erraten: Ein unterprogrammgefÃ¤deltes Forth besteht aus einer Anzahl von hintereinander platzierten Unterprogrammaufrufen (Calls) der verwendeten Worte. 

Aber wenn wir die Calls im RAM unterbringen, kÃ¶nnen wir auch hier leider keinen Maschinencode ausfÃ¼hren. Abbildung \ref{minke6:subroutine} zeigt der  Deutlichkeit halber einen Speicherauszug.

%\begin{figure*}
%\includegraphics[width=\textwidth]{2007-Sonderheft-AVR/subroutine}
%\caption{Unterprogramm--FÃ¤delung}\label{minke6:subroutine}
%\end{figure*}



Man beachte, dass sich durch die Verwendung von Unterprogrammaufrufen die Adressen, an denen die Calls stehen, verÃ¤ndert haben! Der \inst{CALL}--Befehl selbst nimmt einen gewissen Platz ein.

Unsere Wahl ist einfach:

{\bf Entscheidung 9:}  Wir wÃ¤hlen ein indirekt gefÃ¤deltes AVR--Forth!

%\hfill --- Wird fortgesetzt ---
%\end{multicols}
%\end{document}
</pre></body></html>