% Content-encoding: UTF-8
\documentclass[ngerman]{article}
\usepackage[utf8]{inputenc}
\usepackage{multicol,babel}
\usepackage{xspace}
\setcounter{secnumdepth}{0}
\setcounter{tocdepth}{0}

%\newcommand{\code}[1]{\texttt{#1}}
%\newcommand{\ret}{\textsf{$<$ret$>$}\xspace}
%\newcommand{\ret}{$\hookleftarrow$\xspace}

\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{amforth XXL} 
\author{Matthias Trute}

\begin{document}
\maketitle
Amforth ist ein 16--Bit--Forth für die 8--Bit--Mikrocontrollerserie
Atmega der Firma Atmel. Mit einer Cellsize von 16 Bit scheinen die 
Grenzen deutlich zu sein: 64 KB Adressraum. Doch da diese Controller
einen getrennten Daten-- und Programmadressraum haben (\emph{Harvard Architektur}\/)
steht der 64--KB--Adressraum zweimal zur Verfügung.

\begin{figure*}[b]
\vspace*{0.2ex}
\begin{center}
\includegraphics[width=0.45\textwidth]{2010-0203/img_4472}
\end{center}
\caption{\label{amforth-xxl:Bild1}AVR--Entwicklungsmodul mit 128 KB ext.\ SRAM und ATMEGA2561 [3]}
\end{figure*}

\begin{multicols}{2}

Tatsächlich läuft amforth jedoch auch auf Systemen, die deutlich
mehr als dies haben. Und dieses Mehr steht den Programmen
auch zur Verfügung, ohne dass man die Programme umschreiben müsste.
Bei alledem belegt das Kernsystem nicht mehr Platz als auf den 
kleinen Systemen.

\begin{verbatim}
amforth 3.9 ATmega2561 14745 kHz 
 > : hallo ." Hallo " ;
 ok
 > hallo
 Hallo  ok
 > words
 hallo d- d+ dinvert int@ int! is Rdefer 
 Edefer show-wordlist ...
 > unused decimal u.
 57537  ok
 > 
\end{verbatim}

Um das zu erreichen, hat schon der Hersteller einige Entscheidungen 
beim Design der Controller getroffen, die amforth ausnutzt. Sie
betreffen den Programmspeicher, der als selbst--reprogrammierbarer
Flash ausgeführt ist und bei amforth das gesamte Dictionary enthält.



\section{Die Speicheraufteilung}

Amforth als 16--Bit--System ist natürlich begrenzt auf die Möglichkeiten, 
die 16 Bit bieten: 65536 Adressen. Beim Flash heisst das ungewohnterweise 
128 KB. Der Grund ist folgender: Der Flash beinhaltet normalerweise den 
ausführbaren Code. Die Maschineninstruktionen der Atmegas sind nun immer 16 Bit 
oder Vielfache davon groß (RISC lässt grüßen). Atmel hat das so implementiert, 
dass hinter jeder Adresse 2 Bytes liegen.  Dass Programme zwei Instruktionen 
benötigen \texttt{(lpm Z+)} und solcherart doch eine Art byte--basierte Adressierung 
zum Einsatz kommt, zählt wohl zu den Seltsamkeiten der Plattform\ldots

Damit kann das Dictionary 128 KB groß werden. Bei Systemen, die noch mehr Flash 
haben, ergibt sich ein Dilemma: Der nutzbare Speicher ist kleiner als der 
vorhandene. Soll heißen: Es liegt Flashspeicher brach. Zum anderen ist der
Sonderbereich, der für das Selbstprogrammieren des Flashes zu nutzen ist,
jenseits der Adressgrenze für die zahlreich genutzten 
\texttt{JMP/CALL}--Befehle.

Letzteres ist einfach zu lösen: Es gibt einen neuen Befehl: \texttt{RAMPZ}. Er ist zwar deutlich umständlicher zu benutzen und damit langsamer, da aber der Flash--Programmierbefehl  ohnehin 2--3 Millisekunden benötigt, spielt das keine Rolle.

Um ersteres Dilemma zu lösen, schließlich bezahlt niemand für etwas, was 
er nicht nutzen kann, gibt es mehrere Ansätze, die derzeit
noch nicht umgesetzt sind, aber sicher über kurz oder lang
nutzbar sein dürften: Zum einen kann man Worte definieren, die zur
Adressierung nicht eine, sondern zwei Zellen einsetzen. Dass
das bislang nicht umgesetzt ist, ist auch eine Frage der Wortwahl:
Wie sollte so ein Wort heißen? \texttt{id@ ( d -{}- n )} bzw. \texttt{id! ( n d -{}- )}?%
\footnote{\texttt{i!} ist das amforth--Wort, um in den Instruktionsspeicher
zu schreiben. Hierbei ist die Adresse eine Zelle groß, also 16 Bit. \texttt{id@}
liefert also keine doppelt--genaue Zahl, sondern nimmt eine solche als
Adresse.} 
\footnote{Interessanterweise gibt es ein analoges Dilemma auch beim Zugriff auf
SD--Karten: Das \texttt{BLOCKS} Wordset definiert Zugriffsworte, die genau eine
Zelle als Blocknummer beinhalten. Dummerweise gibt es so kleine SD Cards
aber gar nicht mehr\ldots\ wenn man ein 16--Bit--Forth betrachtet.}

Der zweite Ansatz geht auf eine Idee von Michael Kalus zurück:
Flash als Blockdevice ansprechen. Und wieder gibt es zwei Varianten:
Standard--Forth Blöcke von 1 KB oder die device--spezifische Pagesize nutzen. 
Relativer Nachteil der Standard--Blöcke ist, dass sie recht viel vom RAM 
für Buffer belegen, der immer knapp ist. Dies ist bei der zweiten Variante
deutlich entspannter, dafür aber auch anspruchsvoller bei der Nutzung. 
Andererseits stehen beim Atmega2561 8 KB interner RAM zur Verfügung.



\section{Technisches}

Wer den Quellcode analysiert, wird feststellen, dass die Unterstützung
für große (Flash--) Speichermengen in mehreren Stufen erfolgt. Die erste
Stufe sind die 128--KB--Systeme. Hier kommt ein zusätzliches Adressregister
RAMPZ zum Einsatz. Es erweitert das normalerweise genutzte Z--Registerpaar
um ein weiteres Byte und stellt so die komplette Adresse bereit. Dieses
Registertriplett wird von den Befehlen \texttt{elpm} und \texttt{spm} genutzt, um
den Flashspeicher zu adressieren. Im Quelltext wird das alles in den 
Assemblermakros \texttt{readflashcell} und \texttt{writeflashcell} gekapselt. 
In diesen Macros ist auch die eigentümliche interne Zugriffsmethode 
auf Byteadressen versteckt.

Aus Performancesicht sind große Atmegas bei gleicher Taktfrequenz
langsamer als kleinere. Kleine Systeme benötigen 4 Instruktionen, um 
eine Flashzelle zu lesen. Große Systeme müssen 7 Befehle ausführen,
um das Gleiche zu leisten. Da jedoch zusätzlich immer die Stackoperationen 
und der innerere Interpreter involviert sind, ist die prozentuale 
Einbuße, bezogen auf das Gesamtsystem, deutlich geringer. In der Praxis
wird man wohl einen etwas schnelleren Quarz verbauen\dots

\begin{small}
\hfil
\begin{minipage}[t]{0.4\columnwidth}
\begin{verbatim}
.macro readflashcell
	lsl zl
	rol zh
	lpm @0, Z+
	lpm @1, Z+
.endmacro
.macro writeflashcell
	lsl zl
	rol zh
.endmacro
\end{verbatim}
\end{minipage}
\hfil
\begin{minipage}[t]{0.4\columnwidth}
\begin{verbatim}
.macro readflashcell
	clr temp7
	lsl zl
	rol zh
	rol temp7
	out RAMPZ, temp7
	elpm @0, Z+
	elpm @1, Z+
.endmacro
.macro writeflashcell
	clr temp7
	lsl zl
	rol zh
	rol temp7
	out RAMPZ, temp7
.endmacro
\end{verbatim}
\end{minipage}
\hfil
\end{small}\medskip

Der scheinbar fehlende \texttt{spm}--Befehl im writeflashmacro ist an anderer 
Stelle enthalten.

Der zweite Schritt sind Systeme, die mehr als 128 KB haben. Hierzu zählt
interessanterweise auch der ATXmega128. Diese Systeme sind erkennbar
am 24 Bit (3 Byte) großen Program--Counter--Register. Damit legt z.~B.\ ein
CALL 3 Bytes auf den Returnstack, anstelle 2 bei den kleineren Controllern.
Bei diesen Controllern liegt die Hürde darin, dass der Bereich, von dem aus 
das Flash--Selbstprogrammieren erfolgen muss, außerhalb der zulässigen 
Sprungdistanz der normalerweise genutzten Befehle liegt.

\begin{small}
\begin{quote}
\begin{verbatim}
; ( n addr -- ) Memory
; R( -- )
; writes a cell in the flash
VE_DO_ISTORE:
    .dw $ff04
    .db "(i!)"
    .dw VE_HEAD
    .set VE_HEAD = VE_DO_ISTORE
XT_DO_ISTORE:
    .dw PFA_DO_ISTORE
PFA_DO_ISTORE:
  ....
  ldi zl, byte3(DO_ISTORE_atmega)
  out_ rampz, zl
  ldi zh, byte2(DO_ISTORE_atmega)
  ldi zl, byte1(DO_ISTORE_atmega)
  eicall ; reaches any address
  ....
  ; finally clear the stack
  loadtos
  rjmp DO_NEXT

.org NRWW_START_ADDR 
  ; way outside of an call/jmp
DO_ISTORE_atmega:
  rcall pageload
  ; erase page if needed
  ; it is needed if a bit goes from 0 to 1
  com temp4
.....
  ret ; return to caller, all done
\end{verbatim} % $
\end{quote}
\end{small}

Damit amforth hier die nötige Flexibilität erhält, wurde das alles
entscheidende Wort i! umgebaut, indem es in Assembler komplett neu 
geschrieben wurde. Das brachte neben einigen Bytes Platzersparnis 
auch die Möglichkeit, den Programmcode unabhängig vom Rest des 
Systems zu platzieren. Eine Alternative wäre, ein weiteres Forthsystem
zu haben, das nur für die Ausführung von \texttt{i!} zuständig ist.

Damit rückt auch ein weiteres Ziel in Reichweite: Da es nur wenige Bytes umfasst,
kann man eine Einbeziehung in Standard--Bootloader angehen, die dann nicht
nur ein neues System einspielen können, sondern darüberhinaus noch eine
API für Programme wie amforth anbieten können, um den Flash gezielt ändern
zu können.

Der Inhalt des Bootloaderbereichs ist für das amforth--System immer read--only.
Daraus ergibt sich die Konsequenz, dass amforth diesen Bereich maximal nutzen
sollte. Bei den Systemen mit bis zu 128 KB Flash heisst dies: Alles dort ablegen,
was irgendwie geht. Die Systeme mit mehr Flash\-speicher sind da exakt entgegengesetzt:

Da amforth mit den Standardworten den Bootloaderbereich nicht addressieren kann,
darf \em{nichts} dort liegen. Allerdings \em{muss} das Wort \texttt{i!} dort platziert werden, da für die Dauer des Flashprogrammierens unter keinen Umständen auf den RWW--Flash, der das Dictionary enthält, zugegriffen werden darf. Die CPU wird in diesem Fall einfach gestoppt. Um das zu lösen, liegt der Dictionary--Eintrag von \texttt{i!} zwar im normalen Flash, ruft aber Code im Bootloaderbereich auf. Dieser Code kehrt erst dann zurück, wenn die Arbeit getan ist. Wie man an dem obigen Codeschnipsel sehen kann, ist die Implementierung nicht für jedes Wort sinnvoll einzusetzen.

\section{Zukünftiges}
Prognosen sind schwierig, vor allem, wenn sie die Zukunft betreffen. 
Die Eckdaten für amforth werden wohl zukünftig so aussehen: Das Dictionary
umfasst maximal 128 KB.  

Jeglicher Flash\-speicher jenseits der 128 KB wird z.B. als Block
über eine 16 Bit große Blocknummer angesprochen. Alternativ oder
zusätzlich kann ein Wortpaar analog zu \texttt{i@} und \texttt{/i!} existieren, das als Adresse  eine doppelt--genaue Zahl hat und so den Zugriff auf den gesamten
Flash\-speicher gewährt. 
\end{multicols}

\section{Links}
{}[1] \url{http://www.atmel.com/products/AVR/}\\
{}[2] \url{http://amforth.sourceforge.net/}\\
{}[3] Anbieter des Entwicklungsboard: \url{www.alvidi.de}

%\end{document}