<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">% 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{$&lt;$ret$&gt;$}\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 
 &gt; : hallo ." Hallo " ;
 ok
 &gt; hallo
 Hallo  ok
 &gt; words
 hallo d- d+ dinvert int@ int! is Rdefer 
 Edefer show-wordlist ...
 &gt; unused decimal u.
 57537  ok
 &gt; 
\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}

</pre></body></html>