swiftx
swiftx
Cross-Development Software
Reference Manual
SwiftForth, SwiftX, SwiftOS, pF/x, polyFORTH, and chipFORTH are trademarks of FORTH, Inc. All
other brand and product names are trademarks or registered trademarks of their respective
companies.
This document contains information proprietary to FORTH, Inc. Any reproduction, disclosure, or
unauthorized use of this document, either in whole or in part, is expressly forbidden without
prior permission in writing from:
FORTH, Inc.
5959 W. Century Blvd. Suite 700
Los Angeles, California USA 90045
Phone: +1 310.999.6784 Fax: +1 310.943.3806
www.forth.com
SwiftX Reference Manual
CONTENTS
Welcome!
What is SwiftX? . . . . . . . . . . . .... ... .... . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Scope of This manual . . . . . . .... ... .... . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Audience . . . . . . . . . . . . . . . .... ... .... . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
How to Proceed . . . . . . . . . . .... ... .... . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Typographic Conventions. . . .... ... .... . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Support . . . . . . . . . . . . . . . . .... ... .... . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Contents 3
SwiftX Reference Manual
4 Contents
SwiftX Reference Manual
Appendix D: Bibliography
Recommended Books . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Other Publications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Contents 5
SwiftX Reference Manual
LIST OF FIGURES
SwiftX directory structure 12
Code layers in a SwiftX system 21
The SwiftX command window 22
Toolbar items 22
SwiftX command window status line 22
Right mouse button actions on a selected word 23
Select Editor dialog box 27
Preferences dialog box 28
System warning configuration dialog box 29
Right-click to revisit or apply other options to LOCATEd words 32
New Project dialog box 38
Open project dialog box 39
Configuring INCLUDE debugging aids 43
The Forth virtual machine in a SwiftX target 49
A defining word and an instance, in host and target 63
XTL communication 70
SwiftOS round-robin multitasking loop 75
User variables offset into tasks’ user areas 79
Background task memory 85
Two tasks are involved in a word containing ACTIVATE 88
Terminal task use of memory 110
Angles of repose 119
Conical pile calculator 120
LIST OF TABLES
Command window keyboard controls 24
File menu options 25
Edit menu options 26
View menu options 26
Options menu options 27
Examples of editor parameter sequences 27
Tools menu options 29
Project menu options 30
Help menu options 30
Number-conversion prefixes 48
Memory section types 50
Scope selectors 58
Search-order commands for extending the cross-compiler 59
Scopes in which colon definitions are accessible 60
Object-file format selection 65
Memory access words affected by target connection 66
Host-to-target commands 69
Target-to-host responses 70
Vectored terminal-specific words 90
Functions applied to background and terminal tasks 93
Parameters governing the space allocation for a terminal task 109
Comparison of results using 16-bit and 32-bit arithmetic 123
Stack argument notation 127
6 Contents
SwiftX Reference Manual
Contents 7
SwiftX Reference Manual
8 Contents
SwiftX Reference Manual
WELCOME!
What is SwiftX?
SwiftX is FORTH, Inc.’s interactive cross compiler, a fast and powerful tool for the
development of software for embedded microprocessors and microcontrollers.
SwiftX is based on the Forth programming language, which for over 30 years has
been the language of choice for engineers developing software for challenging
embedded and real-time control systems. SwiftX provides you with the most inti-
mate, interactive relationship possible with your target system, speeding the soft-
ware development process and helping to ensure thoroughly tested, bug-free code.
It also provides a fast, multitasking kernel and libraries to give you a big head start
in developing your target application.
This manual describes the basic principles and features of the SwiftX cross-com-
piler product line. It is accompanied by additional material documenting the spe-
cific CPU and platform you have purchased.
The purpose of this manual is to help you learn SwiftX and use it effectively. It
includes the basic principles of the cross compiler, SwiftOS multitasking operating
system, libraries, development tools, and recommended programming strategies.
This manual does not attempt to teach Forth. If you are learning Forth for the first
time, install this system and then turn to the Forth Programmer’s Handbook, which
accompanies this system.
Audience
This manual is intended for engineers developing code for processors in embedded
systems. It assumes general knowledge of embedded system programming, and
some familiarity with the Forth programming language (which you can get by fol-
lowing the suggestion above).
How to Proceed
If you are not familiar with Forth, start by reading the first two sections of the Forth
Programmer’s Handbook. Then experiment with this system by downloading sim-
ple definitions to your target and testing them before proceeding.
After you have installed and tested SwiftX on the PC and on the target board sup-
plied with this system, all SwiftX functions will be available to you.
Welcome! 9
SwiftX Reference Manual
Typographic Conventions
Support
The support period included with the original purchase of a SwiftX system is one
year. The support period may be renewed in one-year increments. During the sup-
port period, you are entitled to unlimited downloads of new releases as well as engi-
neer-level technical support via email.
Please send support requests to [email protected] use the support request form
on our website; http://www.forth.com/support.
FORTH, Inc. maintains an email list server that enables SwiftX users to share experi-
ences and code and discuss their application-related problems. To subscribe, please
send a blank email to [email protected] with the word subscribe as the sub-
ject. You may cancel your subscription at any time by sending email to the same
address with the subject unsubscribe. A searchable message archive is located at
http://www.forth.com/archive/swiftx.
10 Welcome!
SwiftX Reference Manual
Both SwiftX Pro and SwiftX Lite versions include the following components:
• Project management features (Section 3.1.1), which facilitate setting up and manag-
ing the source files for multiple applications.
• An optimizing compiler that produces faster and/or smaller code.
• A code stripper (Sections 2.3.7 and 3.2.2), which removes all unused words from a
completed program, for greater compactness.
Getting Started 11
SwiftX Reference Manual
• A target-resident interpreter (see Section 7) supports full user interaction and lim-
ited compiler capabilities via a serial terminal task in a standalone target. This fea-
ture is useful for field diagnostics, configuration, and other user interactions. (Not
available in all targets.)
• Complete source code for the cross compiler, host side of Cross-Target Link (XTL),
assembler, and decompiler/disassembler.
The directory structure for the files provided with SwiftX is shown in Figure 1. This
example shows a SwiftX installation with multiple target CPU types to show the
hierarchical arrangement.
The default installation directory, ForthInc, may contain multiple FORTH, Inc. prod-
uct directories (e.g, SwiftX, SwiftForth, pfWin32).
• bin contains the Windows executable program and associated libraries and other
12 Getting Started
SwiftX Reference Manual
This section describes how to install your SwiftX cross compiler and connect it to
the target board supplied with this system. It also describes basic procedures for
downloading and testing a kernel and your programs.
If you have previously installed SwiftX, you may wish to back up any files you have
modified before installing a new version on top of the old one.
The installation procedure creates a SwiftX program group on the Windows Start >
Getting Started 13
SwiftX Reference Manual
Programs menu, from which you may launch an instance of Windows Explorer to
navigate the SwiftX directory tree, view SwiftX documentation, or uninstall SwiftX.
Launch SwiftX from the project.swx icon in the target-level project folder that cor-
responds to your board. See Section 1.2 for a discussion of the SwiftX source direc-
tory organization.
You may configure SwiftX to use an editor of your choice by specifying certain com-
mand parameters as described in Section 2.3.5.
Here we provide a brief overview of some development paths you might pursue.
You may wish to:
Simple guidelines for doing these things are given in the following sections, and will
prepare you to interact with your target hardware by using the software as deliv-
ered. Further details about the SwiftX compiler and interactive development aids
are given in Sections 2.4 and 4.
Launch SwiftX as described in Section 1.4.2. When SwiftX is running and your target
board is connected, you may change any options you wish. When you are ready, you
may compile a target image of a SwiftX kernel plus libraries and other routines,
depending upon how you have configured your system. There are two options for
doing this, both available from SwiftX’s project menu (the usual development
approach is to use Debug during development, and Build only when you are ready
for PROM burning):
14 Getting Started
SwiftX Reference Manual
• Project > Build compiles the target image in a file on the PC suitable for burning into
a PROM.
• Project > Debug compiles the target image, and establishes communication with the
Cross-Target Link (XTL, see Section 4.9) on the target board. If no target is con-
nected, or is not connected properly, this command will fail and will generate an
error message or redisplay the XTL port selection dialog box.
This means the kernel was fully compiled, but the XTL connection was not estab-
lished; check your connections and select Project > Debug again. If the target sys-
tem runs from PROM, it will compare the newly compiled image to the image in the
target; they must be identical for the XTL to work properly. With some targets, a
new image can simply be downloaded via the XTL.
If these steps are completed, additional debugging facilities are then downloaded to
support interactive testing and debugging. When communication has been estab-
lished successfully, the target will greet you by displaying the system and target
IDs. At this point, you may directly execute words on the target, examine its mem-
ory or I/O ports, and define additional words which will be downloaded automati-
cally for testing. To try it, type:
2 6 + .
The numbers you typed will be transmitted to the target, followed by the com-
mands + and . (the command “dot,” which types a number). These commands will
be executed on the target board, which will add the numbers and display the sum.
The sum will be displayed on your screen, because your PC is providing the target’s
keyboard and display functions.
Whether or not you are connected to a target, you may use LOCATE, DUMP, and many
other debugging commands, described in Section 2.4.
If you are using a target system other than the test board supplied with this SwiftX
product for your final application, you may need to make some changes to the
parameters of your kernel. The configuration procedure described in Section 4.2
will help you to do this.
If your target will execute out of PROM, you will need to burn a PROM. The menu
selection Project > Build compiles a target image and writes it in a file suitable for
burning to a PROM. See Section 4.8 for the available object file formats.
As shipped, the Debug option is configured to run a demo application based on the
Conical Pile Calculator described in Appendix A.2. The source for this program is in
the file SwiftX\Src\Conical.f; we recommend that you review it, because it exhibits
many features found in SwiftX programming.
Getting Started 15
SwiftX Reference Manual
The demo program requires that the target be connected and communicating with
the host. It may use either the host keyboard and screen via the XTL (the default
configuration), or you may connect the target board’s serial port to a COM port on
your host and set up a separate task in the target to talk to a standard terminal
emulator utility in the target, as described in Section 5.5.
To run this program, launch SwiftX as described in Section 1.5.1 and select Project >
Debug to bring up the target program. Type CALCULATE to start the application; it
will issue the prompt:
Select a material by typing, for example, 1M. The target will echo, in that example,
Loose gravel. Similarly, enter a number of feet and inches. Finally, type = and the
target will display the answer.
This demo program is configured to run indefinitely; to exit, press the Esc key.
To explore further, try typing LOCATE DENSITY. This will display the source where
this word is defined. If you have linked an editor (as described in Section 1.4.3 and
Section 2.3.5) you may press your right mouse button and select Edit This to launch
your editor, opening the Conical.f file.
You may examine the contents of any of the variables in this program by typing, for
example:
DENSITY ?
You may also exercise the individual words in the demo by providing suitable stack
arguments (look at the comment following the name of each definition); for exam-
ple:
1 SELECT
This displays Loose gravel and stores the parameters for that material in DENSITY,
THETA, and MATTER.
When you have successfully compiled the kernel and exercised the Cross-Target
Link, you can begin trying changes to the kernel.
The simplest (and safest) changes involve adding new words. You can simply type
new definitions at the keyboard, and they will be compiled and downloaded auto-
matically, available for immediate testing. For example, you could type:
This defines a word which, when executed, displays the message between quotation
marks, followed by a new-line function (CR). Try it by typing Hi.
16 Getting Started
SwiftX Reference Manual
Certain target microncontrollers, such as the AVR and some variants of the 8051
family, do not support entering new Forth words “on the fly”from the command
line as they requre additional steps to program code space, typically in flash mem-
ory. Entering new definitions in a source file and downloading or programming the
device is support for all processor types.
You can create a new file—e.g., via the File > Edit menu item or toolbar button or by
typing EDIT filename—for your source code, for example, extras.f. With the board in
interactive mode (after doing a Project > Debug), you may compile the words in your
new file for interactive testing by using the menu item File > Include or by typing:
INCLUDE EXTRAS
You may do this repeatedly, until the board runs out of code space. If necessary,
you may start over with a new download by repeating Project > Debug, which re-ini-
tializes the target.
When the new functions are tested to your satisfaction, you may add them to the
kernel by inserting INCLUDE EXTRAS in the space provided in source file app.f.
The startup code for a SwiftX system is usually factored into two files, both called
start.f, but at different directory levels: one is in the directory Swiftx\src\<CPU>,
and one is in the target-specific subdirectory. These are usually the last files to be
loaded, with the target-specific one (containing the actual power-up code) last.
Then rebuild and reinstall the kernel as described above (using Project > Build), and
test. Instructions for installing a new kernel are provided in your platform-specific
documentation.
Changes to the Forth primitives (such as those in the file core.f) should only be
made with the greatest of care. The SwiftX kernel and the Cross-Target Link rely on
those primitives for their operation. Changes to the model of the underlying Forth
system (such as cell size or stack allocation) should only be attempted by an experi-
enced Forth programmer.
Getting Started 17
SwiftX Reference Manual
18 Getting Started
SwiftX Reference Manual
SwiftX supports interactive development and testing of software, on even the small-
est microcontrollers, without expensive additional hardware and software tools.
This is achieved by using a Windows-based host computer to handle a continuous
communications link between the PC and an actual target.
This introductory section gives a general view of the design of the SwiftX develop-
ment environment. We recommend that you read this, even if you are already famil-
iar with the Forth language.
The SwiftX cross compiler is based on the Forth language, and its target source code
is written in Forth. Therefore, gaining familiarity with the essentials of Forth is
strongly recommended before tackling SwiftX programming.
If you are a Forth beginner, read any of the introductory books in “Bibliography” on
page 137. Review the demo application (“Conical Pile Calculator”) supplied with
your system. Find out what software is available by looking through the source
code supplied with SwiftX. Finally, don’t hesitate to contact the FORTH, Inc. Hotline
Support Service with any questions or problems (see page 10). Forth programming
courses are available at FORTH, Inc. and can help shorten the learning process. We
also offer a full range of consulting and custom programming services to help kick-
start your project.
SwiftX is a very powerful and flexible system, supporting software development for
virtually any embedded system configuration. Although the internal principles of
SwiftX are simple, a necessary side-effect of its power is that it has a large number
of commands and capabilities. To get the most benefit, allocate some time to
become familiar with this system before you begin your project. This will pay off in
your ability to get results quickly.
The SwiftX system has two basic components: a host system (the PC side of the
development system) which supports the SwiftX cross-compiler and interactive pro-
gramming tools, and a target system which executes on the target board and sup-
ports interactive debugging with the host.
Introduction to SwiftX 19
SwiftX Reference Manual
The host software is based on a 32-bit Forth system running under Windows. This
host is designed to support a special cross-compiler for the target processor, along
with a cross-assembler and the source code for the target system’s kernel and appli-
cation.
• Memory and address space There are a number of different address spaces: the
host’s local memory, which is not directly accessible in the cross-compiler; the vari-
ous regions of target memory (code space plus initialized and uninitialized data
space); and a private region where the host maintains pointers into the target’s
memory image. When you are programming in SwiftX, you usually are working with
target memory space.
• Command set SwiftX compilers are written in Forth. The host provides locally exe-
cutable versions of many Forth words that are also present in the target. In order to
distinguish between the host and target versions of these words, they are main-
tained in separate, searchable word lists. Commands are provided to select among
these word lists. The context in which a word may be accessed (either for execution
or for compiling a reference to it) is called its scope. The default arrangement is that
one accesses the target versions of these words. Scopes are discussed further in
Section 4.6.
• Compiler words and directives There actually are two compilers in SwiftX. The
most visible compiler is the one used to construct the target program; it contains
defining words (such as :, CONSTANT, VARIABLE, etc.), flow-of-control words (such as
IF, THEN, BEGIN, DO, LOOP, etc.), words for managing data space (such as , and ALLOT,
etc.), and other compiler words. However, an underlying compiler on the host was
used to build the cross-compiler. This compiler may be extended in order to pro-
vide special compiling or defining capabilities. For this reason, it is accessible via
special scope selectors (described in Section 4.6.2), as are the host versions of com-
mon Forth commands.
SwiftX contains an assembler which provides direct access to the native instruction
set of the CPU. The assembler for your target processor is described in the Target
Reference Manual specific to your SwiftX system.
SwiftX also supports a third state, called interacting. This means that words typed
on the command line will be executed on the target. The Cross-Target Link (XTL,
described in Section 4.9) connects the host and target systems in this interactive
mode. Two programs communicate via this link. The host XTL issues commands to
the target and responds to output from the target. The target XTL receives and exe-
cutes commands from the host, and sends display commands to the host. The XTL
allows communication at moderate speed over a serial or parallel line.
The target software may be thought of as having several layers, illustrated in Figure
2. Included with your SwiftX system are the core, drivers (including the XTL proto-
col on systems using a serial host-target link), SwiftOS multitasking executive (see
20 Introduction to SwiftX
SwiftX Reference Manual
Section Section 5:), and libraries (supplied in source form). You may select which
libraries to add to the system (see Section Section 6:). You may also add custom
drivers, other libraries, and application code easily. This makes your SwiftX system
very adaptable, in both content and size, to your special requirements.
Application
Custom application
Libraries
Drivers Math or other libaries
SwiftOS
Device drivers
Multitasking
Core executive
Code primitives &
common functions
Your main interface with SwiftX is through the command window, which is dis-
played when the system boots. In this window, you may type commands, which will
be executed by SwiftX or routed to the target for execution, as described in Section
Introduction to SwiftX 21
SwiftX Reference Manual
2.5.
All information displayed in the command window (including commands you type,
and system responses or displays) is kept in a large circular buffer while the IDE is
running; to see previous parts of the session, you may scroll through this buffer by
using the scroll bar or the PageUp and PageDown keys. You may also print or save
the entire buffer, or any portion of it you select using the mouse.
The toolbar at the top of the command window provides one-click access to several
menu options described in the following sections (see Figure 4).
The status line at the bottom of the command window shows the current number
base (the default is decimal), the stack depth with the actual values of the top sev-
eral items, the current scope (see Section 4.6.2), and other useful information (see
Figure 5).
In addition to the buffer containing the general history of the command window’s
contents, SwiftX remembers the last several commands you type, storing them in a
circular queue. The up-arrow and down-arrow keys allow you to retrieve these com-
22 Introduction to SwiftX
SwiftX Reference Manual
mand lines from the buffer. You may edit them by using the left-arrow and right-
arrow keys and typing; the Insert key toggles between “insert” and “overwrite”
mode (indicated at the right end of the status bar). You can execute the entire line
(regardless of where on the line your cursor is) by pressing Enter; or leave the line,
without executing it, by pressing Esc.
Lines shorter than three characters are not saved in the recall buffer, as they take
more time to get to via the control keys than to retype!
Double-clicking any word in the command window will select it. The right mouse
button presents a menu of operations you can apply to a selected word, shown in
Figure 6.
Introduction to SwiftX 23
SwiftX Reference Manual
Copy and Paste (below the horizontal line in the menu) differ a bit from the other
options. The functions above the line require that you have selected a Forth word
that is recognizable in your current scope (or, in the case of Execute, an executable
word or number). Copy does not depend on the selected text being a defined Forth
word, and Paste will ignore any selected text.
After you have displayed source for a word in the command window, pressing Alt-
PageUp and Alt-PageDown will display adjacent portions of that source file.
Key Action
PageUp Scroll through the history of the current session.
PageDown
UpArrow Retrieve commands you have typed.
DownArrow
LeftArrow Move cursor on the command line.
RightArrow
Insert Toggle the insert/overwrite mode of typing.
Enter Execute the command line the cursor is on.
Ctrl-C Copy from, or paste text into, the window.
Ctrl-V (See Section 2.3.3.)
Double-click Selects it, making it available for pop-up menu
on a word actions LOCATE, EDIT, SEE, WH (cross-reference), or
EXECUTE.
Right-click Display pop-up menu options: PageUp, PageDown,
Edit This (which launches your editor with the cursor
positioned at the source line targeted by your previ-
ous LOCATE action; see Sections 2.3.5 and 2.4.1); and
with shortcuts to previously LOCATEd words. (See
Figure 10 on page 32.)
The following sections describe the menu options available from the command win-
dow. Where a letter in a menu item is underlined, the Alt key plus that letter is a
keyboard equivalent. In each case, we list the menu item, equivalent command (if
any), and a description of the item.
24 Introduction to SwiftX
SwiftX Reference Manual
The “New project” and “Open project” items are described in more detail in Section
3.1.1.
The Edit menu option opens a file for editing, using your linked editor (see Sections
2.3.5 and 2.4.1).
Edit
Both the File > Open Project and File > Edit menu items and their corresponding
toolbar buttons bring up a “Browse” dialog box through which you can find your
file. Both will reset SwiftX’s path to the one for the file you select. However, the
command INCLUDE invoked from the keyboard will not change SwiftX’s current-path
Open information.
Save Command Window, Save Keyboard History, and Session Log are discussed fur-
ther in Section 2.4.6.
Introduction to SwiftX 25
SwiftX Reference Manual
Most editing in SwiftX is done with your associated editor (see Section 1.4.3 and Sec-
tion 2.4). However, you can copy text—from a file in another window or from else-
where in the command window—and paste it into the command window, which will
have the same effect as typing it. You may also select text for typing, saving, or
copying into another window. Edit menu options are summarized in Table 3. (Cut
and Delete are not available in the command window, since the purpose of the com-
mand window is to maintain a record of your actions during this programming ses-
sion.)
Paste
2.3.4 View Menu
The View menu provides alternate views of the command window. Each feature will
toggle when you select it. The choices are described in Table 4.
Item Action
Status line If checked, displays the status line at the bottom of the screen.
See Figure 5 for details.
Toolbar If checked, displays the toolbar at the top of the screen. Toolbar
button options (flat, large, small) may be set using Options >
Preferences, described in Section 2.3.5.
The Options menu provides ways to customize SwiftX. Its selections are summa-
rized in Table 5.
To use an editor other than Notepad, which is the default when SwiftX is first
installed, use Options > Editor and type your editor’s path and name into the box or
click the browse button to search for it. After providing the pathname, the User
Options menu
26 Introduction to SwiftX
SwiftX Reference Manual
Item Action
Font Select a font for the command window. Only fixed-width
(i.e., non-proportional) fonts are listed.
Editor Select and set parameters for your editor.
Preferences Set text and background colors for normal and highlighted
displays, select case sensitivity, and other options
Warnings Enable/disable various system warnings, and establish how
they and error messages will be displayed.
Include Sets options for diagnostic features to be performed during
Monitoring file INCLUDE operations. (See Section 3.1.5 for details.)
Save Options Save all current settings.
Next you must specify, on the Editor Options line, how SwiftX is to pass line-number
and filename parameters to your editor. The specification format is:
When SwiftX calls the editor, it provides the line number at the place in this string
that has a %l (lower-case L), and provides the filename at the place that has a %f.
Example parameter strings for some editors are shown in Table 6.
When your editor’s pathname and parameter string are correct, click Done. This
Introduction to SwiftX 27
SwiftX Reference Manual
The Options > Preferences dialog (or its equivalent Toolbar button) lets you specify
a number of configuration items, shown in Figure 8. The Colors section controls
Prefs the color scheme of the command window.
“Use coloring for WORDS” vectors the command WORDS (described in Section 2.3.6).
If this box is checked, typing WORDS in the command window produces a color-coded
display in that window. The Words browser window launched from the toolbar or
Tools menu is not affected by this.
“Save options on exit” records your selections so they will be in effect when you
next launch SwiftForth. (Note: the Reset button will restore all options to the sys-
tem defaults.)
“Flat” and “Large” toolbar buttons affect the appearance of the toolbar, if it is dis-
played.
The Options > Warnings dialog provides configuration settings that determine
whether, and where, error messages and system warnings will appear.
28 Introduction to SwiftX
SwiftX Reference Manual
Options > Include monitoring configures diagnostics that can be used when you’re
INCLUDEing a source file. These are discussed in detail in Section 3.1.5.
This menu provides tools that may be helpful in the development process.
Introduction to SwiftX 29
SwiftX Reference Manual
A project is a link between the SwiftX cross-compiler for the kernel’s CPU and a
source file set up to build your system. It also incorporates configuration informa-
tion, such as the port and baud rate used for the XTL. The Project Menu provides
features for compiling your project.
SwiftX Pro offers additional project management facilities; these are discussed in
Section 3.1.1.
The Help menus provide on-line documentation for your SwiftX system.
Item Content
Handbook Forth Programmer’s Handbook (PDF format).
Reference Manual This manual (PDF format).
Target Manual Documentation for target MCU and boards (PDF format).
Go Online Connect to the FORTH, Inc. web site.
About Product release date and related information.
This section describes the specific features of SwiftX that aid development. These
tools typically will be used from the keyboard in the command window.
30 Introduction to SwiftX
SwiftX Reference Manual
The command:
LOCATE <name>
LOCATE may also fail if the source file has been altered after the last time it was com-
piled, because the host version of each compiled definition contains a pointer to the
position in the file that produced it.
LOCATE /STRING
(or double-clicking on /STRING ) opens the correct source file, and displays the
source for this word, plus several lines before and after it (the number of lines dis-
played depends upon the size of your command window).
If you right-click the mouse, you will see a pop-up menu, shown in Figure 10. You
can apply any of these menu selections to the most recently LOCATEd word, or to a
currently selected word.
Introduction to SwiftX 31
SwiftX Reference Manual
Near the top of this menu, you will see the option Edit. Selecting that command, or
typing EDIT, will launch your linked editor (or switch to it, if it is already open) with
the cursor positioned on the source line containing the word you last located. This
feature lets you immediately edit the source, if you wish, and examine the rest of the
file. (To link to an editor other than the default Notepad, see Section 2.3.5.)
You may also use the EDIT command to open an arbitrary file for editing, by typing
EDIT wordname or EDIT filename. (Also see the File > Edit menu option, discussed
in Section 2.3.2.) If EDIT sees a string, it will attempt to look it up in the dictionary,
in the current scope. If it finds it, it will use the editor to open the source file in
which wordname is defined, positioned at the definition. If the text cannot be
found in the dictionary, EDIT will attempt to treat it as a filename and open that file
in the editor. To avoid confusion, we recommend that you always append the .f
extension when you use EDIT with a filename.
If the compiler encounters an error and aborts, you may directly view the file and
line at which the error occurred by typing G (for Go to the error). This is particularly
convenient if you have a linked editor (see Section 2.3.5), because you can immedi-
ately repair the error and recompile. If you don’t have a suitable editor, SwiftX will
display the source path and line number in the command window, and you will have
to manually switch to your editor to fix the problem.
Glossary
32 Introduction to SwiftX
SwiftX Reference Manual
N (—)
Display the Next range of lines following a LOCATE display.
B (—)
Display the previous (Back) range of lines following a LOCATE display.
L (—)
Following a compiler error, display the line of source at which the error occurred,
along with the source path and line number, in the SwiftForth command window.
G (—)
Following a compiler error, opens the linked editor with the cursor positioned on
the line where the error occurred.
2.4.2 Cross-references
This tool finds all the places a word is referenced. The syntax is:
WHERE <name>
It displays the first line of the definition of name, followed by each line of source
code in the currently compiled program that contains name.
If the same name has been redefined, WHERE gives the references for each definition
separately. The shortcut:
WH <name>
does the same thing. It is also the word that responds to the “Cross ref” option on
the right-mouse menu.
This command is not the same as a source search—it is based on the code you have
compiled and are debugging. This means you will be spared any instances of name
that are in files you aren’t using.
Glossary
WH <name> (—)
Introduction to SwiftX 33
SwiftX Reference Manual
2.4.3 Disassembler
The disassembler is used to reconstruct readable source code from compiled CODE
and : (colon) definitions. This is useful as a cross-check whenever a new definition
fails to work as expected.
The single command SEE name disassembles CODE commands and colon definitions
defined for the target scope. The results depend somewhat upon the implementa-
tion; see your target-specific documentation. Subroutine-threaded systems and sys-
tems that compile actual machine code may be unable to reconstruct a high-level
definition, and may instead show the assembler code that was generated. In such a
case, use LOCATE to display the source. SEE is one of the options on the right-mouse
menu.
<addr> DASM
Glossary
DASM ( addr — )
Disassemble code beginning at addr. The display format is platform dependent.
.’ ( addr — )
Displays the name of the definition closest to and preceding addr. Useful for
decoding memory dumps.
Sequences from the host image or target may be dumped via these commands. If
you are connected with an active XTL, all sections of actual target memory will be
displayed; if not, you will see the host image, and uData may not be dumped.
Glossary
DUMP ( addr u — )
Display u bytes of hex characters, starting at addr, in the current section, which
may be either code or data. If you are not connected to your target, you can only
display code space or initialized data space.
34 Introduction to SwiftX
SwiftX Reference Manual
DUMPC ( addr u — )
Display u bytes of hex characters, starting at addr, in the current code-space sec-
tion.
SwiftX’s single-step debugger allows you to step through source compiled from a
file. A simple example is the sample program Sstest.f, shown below:
TARGET
[DEBUG
: 2X ( n -- n*2) DUP + ;
: 3X ( n -- n*3) DUP 2X + ;
: 4X ( n -- n*4) DUP 2X SWAP 2X + ;
: 5X ( n -- n*5) DUP 3X SWAP 2X + ;
DEBUG]
When the source has been compiled from the file Sstest.f, type the following to
invoke the single-step interface:
4 DEBUG 5X
At each breakpoint between Forth words, the current data stack is displayed along
with a prompt to select the next action:
• Save Command Window records a snapshot of the present contents of the com-
mand window in a text file. This is useful if, for example, you have just encoun-
tered a strange behavior you would like to record for later analysis.
• Save Keyboard History records into a text file only the commands you’ve typed.
Such a file may be edited, if you like, using your text editor. You can replay these
Introduction to SwiftX 35
SwiftX Reference Manual
commands by including the file. This is useful for developing scripts or for repro-
ducing a bug.
• Session Log opens a file and starts recording everything that happens thereafter in
the session, until you turn it off by re-selecting this menu item. While it is active, its
menu item displays a check mark.
You may display a window containing the keyboard history by selecting Options >
History or the Toolbar button. You can edit the contents of this window, using it as
Histor a scratch area, and you may copy and paste selections from this window into the
command window.
SwiftX supports interactive development via a debug interface known as the XTL
(Cross-Target Link). This provides access to the target through a debug interface
such as a serial port, BDM, or JTAG cable. XTL functions include reading and writing
memory and registers, as well as controlling execution.
36 Introduction to SwiftX
SwiftX Reference Manual
The primary vehicle for SwiftX program source is text files, which may be edited
using a linked editor of your choice as described in Section 2.3.5. This section
describes tools for managing text files.
3.1.1 Projects
• A project file (typically project.swx), used to launch SwiftX and establish the work-
ing directory and cross-compiler environment.
• A load file, normally called kernel.f that loads the files constituting your project,
organized as described in Section 3.1.4.
• A configuration file, normally named config.f, that specifies memory organization
and other global configuration parameters for your program, described in Section
4.2.
• The source files for your project, perhaps in a hierarchy if it is a complex project.
You can find examples of kernel.f and config.f in the directory for your target
board.
SwiftX Pro contains features that help you manage projects; with SwiftX, the same
principles apply, but the procedures are more manual.
We recommend that you build your project directory by copying into it the files
supplied in the directory for your target board. You don’t need to copy the entire
SwiftX directory. Keep the original target board directory and its files intact, so if
you have problems you can use them for comparison!
These files include a shortcut to the SwiftX executable. Do not reset the “Start in”
directory in the shortcut’s properties! If it stays blank, your project directory will
be the default path for finding your application.
You can then customize the files (kernel.f, config.f, start.f, etc.) as needed for
your project. If you need to customize any other SwiftX system features, we recom-
mend that you copy those files to your project directory and customize them there.
SwiftX Pro contains added features to help with setting up and managing projects.
These include:
• Maintenance of project information in a special project file that has the extension
.swx. This includes various settings for each of your projects.
• A dialog box to automate creation of a new project (copying files and settings from
an existing project).
• A dialog box to open a previously defined project.
To create a new project, launch SwiftX from the target board directory that is most
similar to your project’s target. Then select File > New Project or the corresponding
New toolbar button. This will display a dialog box in which you can enter basic informa-
tion about your project, as shown in Figure 11.
The Description field will appear in the title bar when you launch SwiftX from the
project icon.
When you click the Create button, the new project will be constructed, necessary
files will be copied into the designated directory, the current project will close, and
the new one will open.
To open an existing project, select File > Open Project or its corresponding toolbar
Open button. This will open a dialog box showing your present directory and its neigh-
borhood, as shown in Figure 12. Navigate to the project directory of your choice,
and click OK. If you select a directory that does not contain a project file, the OK
button will be disabled. When you select a directory with a valid project file, your
present project will close, and the new one will open.
The project file itself is a simple text file. You may edit it using any text editor (the
default is Notepad).
You may load source files using the File > Include menu option or by typing:
INCLUDE <filename>
…in the command window. The functional difference between these is that the but-
ton and menu options display a browse window in which you can select the file, and
they change SwiftX’s current path to that of the selected file, whereas the typed com-
mand handles a specified file (including relative path information) and doesn’t
affect the current path.
INCLUDE HEXCALC
1. Absolute path The name starts with a \ or <drive>:\ or \\<name>\. Any of these
indicates an absolute path to the file.
2. Relative path to subdirectories The name does not begin with a \ or ..\ and the
file is located in the current directory or in a subdirectory below it.
3. Relative path to parent directories The name begins with a series of ..\ (two peri-
ods and a backslash). Each series raises the location one directory level from the
current subdirectory. After you have raised the level sufficiently, you can use the
technique in #2 to go down subdirectory levels.
In addition, SwiftX can manage paths relative to the location of the actual execut-
able (normally in the SwiftX\Bin directory). Such paths are indicated by the starting
symbol %, and the actual root is two levels above wherever the executable is. For
example, the shared (platform-independent) core definitions are loaded by the
phrase:
INCLUDE %SWIFTX\SRC\CORE
If you have launched SwiftX from a project file or shortcut in your project directory
(described in Section 3.1.1), your default path is that directory, so you don’t need to
preface local files with any path information. So, your local configuration file could
be loaded like this:
INCLUDE CONFIG
For examples of this, see the Kernel.f file in your target board directory.
Files can load other files that load still others. It is the programmer’s responsibility
to develop load sequences that can be maintained well. We recommend that you
cluster the INCLUDE commands for a logical section of a program into a single file,
rather than scattering INCLUDEs throughout the source: your program will be more
manageable if you can look in a small number of files to find the INCLUDE
sequences. A good example is the main load file for the SwiftX kernel, Kernel.f
(found in your project directory or the directory for your target board).
To see a log of the names and target addresses of all definitions, you may set:
LOGGING ON
This causes any INCLUDE operation to display in the command window a log show-
ing the locations of definitions compiled, which may be printed or saved using the
File menu items described in Section 2.3.2.
Glossary
fers from the File > Include menu option and Toolbar button in that it does not
offer a browse dialog box and does not change the current path. Preceding the path
and filename by % causes the path to be relative to the system root directory (up two
levels from the directory from which your .exe file was launched).
LOGGING ( — addr )
Returns the address of a switch controlling display of names and target addresses
of cross-compiled definitions. To enable the display, use the phrase LOGGING ON. To
disable it, use LOGGING OFF.
For extra visual highlighting of extended comments, SwiftX uses a full line of
dashes at the beginning and end of an extended comment:
{ -----------------------------------------------------
Numeric conversion bases
Forth allows the user to deal with arbitrary numeric conversion
bases for input and output. These are the most common.
----------------------------------------------------- }
Glossary
{ (—)
Begin a comment, which may extend over multiple lines, until a terminating right
brace } is encountered.
\\ (—)
During an INCLUDE operation, treat anything following this word as a comment; i.e.,
anything that follows \\ in a source file will not be compiled.
The main load file for your system is Kernel.f. Its contents are organized into
groups identified by a comment at the beginning of each:
• Nucleus contains functions that, collectively, represent most of the run-time words
in the ANS Forth Core wordset (the compiler and interpreter words are available on
the host). Most are required, but the two files called Double.f (at different directory
levels) may be omitted if you do not need 64-bit and mixed 32-bit/64-bit arithmetic.
The last file in this group, Methods.f, is also optional; it supports the ANS Forth
word VALUE, which you may or may not use.
• Extensions contains the multitasker and also Tools.f (containing ?, .S, and DUMP,
which are extremely useful in debugging but are rarely used in applications). The
multitasker is quite small, and we recommend keeping it even if you have only one
task, because the interaction it provides between interrupts and task-level process-
ing is very convenient.
• Drivers supports hardware specific to your SwiftX system. These files are required
for the system as shipped, but you may need to modify or replace them if your ulti-
mate target hardware is different from the demo target board.
• Initialization contains the startup functions, and must be last.
Near the end of Kernel.f, a file App.f is loaded. This is intended to serve as the
main load file for your application. If your program is very small, you may put its
code directly in App.f. More commonly, however, you will organize your applica-
tion in multiple files and use App.f to INCLUDE them.
Files containing new code that is being tested can be loaded interactively using File
> Include (described in Section 1.5.4) and the procedures described in Section 3.2.1.
When you are confident that it works, you may add it to App.f.
You can monitor the progress of an INCLUDE operation by using a flexible utility
enabled by the command VERBOSE and disabled by SILENT. The level of monitoring
is controlled by the dialog box, shown in Figure 13, which can be invoked by using
the Options > Include monitoring menu item. The default behavior is “Display the
text of each line.”
For example, you might place these commands in a file where there is a problem:
VERBOSE
< troublesome code >
SILENT
VERBOSE turns on the monitor; SILENT turns off the monitor. While monitoring is
active, any INCLUDE also displays the name of the file being processed.
These words are not “immediate,” which means they should be used outside defini-
tions unless you specifically intend to define a word that incorporates this behavior.
Glossary
VERBOSE ( —)
Enables the INCLUDE monitor, with a default behavior of “display the text of each
line.”
SILENT ( —)
Disables the INCLUDE monitor.
The interactive development phase should occupy most of your time. It depends on
using a modified version of the file Debug.f supplied with your system, and requires
writable code space (preferably RAM, but flash or EEPROM can be used with some
inconvenience) for the code under test.
The basic procedure is to replace the demo files (which are loaded in Debug.f
between the commands SET-DOWNLOAD and DOWNLOAD-ALL) with the files being tested,
as described in Section 4.9.1. You may list the files individually or, especially as
your application grows more complex, use an INCLUDE file such as the file App.f, as
described in Section 3.1.4. Since SwiftX is temporarily disconnected from the target
between SET-DOWNLOAD and DOWNLOAD-ALL, however, you cannot do such things as
initializing uData or interrupt vectors at this time.
In general, we strongly recommend that you centralize all target initialization func-
tions, because it will be easier to manage them during development and when bring-
ing up your standalone system when you’re finished. Depending on the extent of
required initialization, you can group such activities in a definition, or as a few def-
initions in a file. During interactive development, you can do these things when the
target is reconnected following the DOWNLOAD-ALL.
If your application is large or your RAM code space is limited, you may wish to
incrementally test related groups of functions and, after they are tested, add them
to the kernel by moving their INCLUDEs to App.f.
When all your application has been tested interactively, it is time to configure your
final application. This generally is done by moving the loading of your application
files to the file App.f (which is loaded by the main file Kernel.f). If your application
is very complex, you may wish to group major components into their own load files,
which are each loaded by App.f.
The first may be done in stages. If memory is in short supply even during develop-
ment, study the list of functions loaded in Kernel.f and discard those you know
you won’t need (e.g., fraction arithmetic). As your familiarity with SwiftX and your
application grows, you may be able to discard more.
When your application is complete and installed in the App.f file loaded by Ker-
nel.f, SwiftX Pro users can apply the ultimate weapon: the stripper. This feature
Strip (Project > Strip) repeatedly does a Build, noting each time which (if any) words were
never called. On the next pass, the compiler will skip those words. When words
have been omitted, any additional words they called may be freed on the next pass.
When two successive compiles give the same target size, the process has com-
pleted—your application has everything it needs and nothing more. The source
files are not affected. If you wish, you can display the list of stripped words at the
end of code stripping operation. To use this feature, type .STRIP BUILD on the com-
mand line instead of using the Strip button.
We don’t recommend using Strip until your application is essentially complete and
tested, as you may strip from your kernel functions you will need later.
If you are a SwiftX (non-Pro) user, you can manually omit from Kernel.f any files
containing features not needed by your application.
Basic hardware initialization is performed by the SwiftX kernel in the POWER-UP rou-
tine in the board-level Start.f, and handles these general requirements:
Most initialization is performed by the high-level startup routine named START, usu-
ally found at the end of the board-level Start.f file. Here’s a representative exam-
ple:
| : START ( -- )
OPERATOR CELL+ STATUS DUP |U| ERASE \ Set up OPERATOR task
|OPERATOR| CMOVE /IDATA\ Initialize iData
/CLOCK /SERIAL GO ;\ I/O, launch application
The default contents of the file App.f (which is intended to be used to load your
application) is a single definition for GO, as follows:
: GO ( -- ) DEBUG-LOOP ;
This simply starts the XTL running. In order to launch your application from
power-up (rather than from Debug) you need to replace this with a definition that
performs any additional initialization required by the application and that finally
calls the highest-level word in the application that makes it all run.
This section covers the requirements of the cross-compiler used to develop the tar-
get program, including methods you may use in source files that will generate tar-
get code—such as techniques for mapping memory, controlling the compiler in
various ways, and accessing the code and initialized data space images in the host
and target.
The cross-compiler uses the same words as a resident Forth system to construct
definitions, and to define and manage data objects. The discussion of these words
in this section focuses on special issues related to cross-compilation; please refer to
the Forth Programmer’s Handbook for basic descriptions and examples of usage.
This section describes how you can control the SwiftX cross-compiler using typed
commands and (more commonly) program source. In most respects, words typed
at the command-line in the SwiftX command window are treated identically to pro-
gram source—anything you do in source may be done interactively.
When the SwiftX text interpreter encounters numbers in the input stream, it con-
verts them to binary. If the system is in compile mode (i.e., between a : and ;), it
compiles a reference to the number as a literal and, when the word being compiled
is executed later, that number will be pushed onto the stack. If the system is inter-
preting, the number will be pushed onto the host’s stack directly.
All number conversions in Forth are controlled by the user variable BASE. The host
system’s BASE controls all input number conversions on the host; there is also a
BASE in the target that controls number conversions performed by the target sys-
tem. The words described in this section are used to control both the host and tar-
get versions of BASE. In each case, the requested base will remain in effect until
explicitly changed. Punctuation in a number (decimal point, comma, colon, slash, or
dash anywhere other than before the leftmost digit) will cause the number to be con-
verted as a double number; see Section 6.1.
Cross-compiler Principles 47
SwiftX Reference Manual
tive, the minus sign must follow the prefix and precede the most-significant digit.
[IF], [ELSE], and [THEN] support conditional compilation by allowing the compiler
to skip any text found in the unselected branch. These commands can be nested,
although you should avoid very complex structures, as they impair the maintain-
ability of the code.
Say, for example, you have defined a flag this way (see Config.f):
[UNDEFINED] <word> will return a true flag if word has not been defined. Thus, if a
code or optimized version of -ZEROS was included in an earlier CPU-specific file
(e.g., Core.f), it will not be replaced when this file is compiled later. Note that load
order is extremely important!
In contrast, [DEFINED] <word> will return a true flag if word has been defined previ-
ously.
48 Cross-compiler Principles
SwiftX Reference Manual
Swiftx\Src\<CPU>\<Target>\Config.f
…which specifies the memory organization of the target system and other options.
Platform-specific configuration issues are discussed in your target-specific docu-
mentation.
SwiftX divides target memory into two logical regions, as shown in Figure 14: code
space (which may or may not be in ROM) and data space (directly accessible RAM).
Data space is further divided into initialized and uninitialized regions. Initialized
data space may be pre-set to specific values at compile time; these values will be
automatically copied into initialized RAM at power-up in the target. You may fur-
ther define multiple sub-regions of each type, as discussed in Section 4.3.
Return Exception
Data Stack
Stack Stack
IDATA
Initialized Data
ALU CDATA
Internal RAM
• Baud rate used for a serial XTL, if the target communicates that way. This is dis-
cussed further in Section 4.9.1.
• Flags controlling whether a target-resident interpreter is being used (for SwiftX Pro
customers only) and, if so, whether the default is to keep heads on target defini-
tions. The target-resident interpreter option is discussed further in Section Section
7:.
SwiftX provides a very flexible scheme for declaring and managing multiple, possi-
bly discontiguous, memory spaces of different types. Each section of memory must
first be declared as described below. Memory can then be allocated using the defin-
Cross-compiler Principles 49
SwiftX Reference Manual
Target memory space can be divided into multiple sections of three types, shown in
Table 11. Managing these spaces separately provides an extra measure of flexibility
and control, even when the target processor does not distinguish code space from
data space.
The words in Table 11 select a current section type. The current section type con-
trols data defining words, memory allocation, and memory accesses of various
types, both during compilation and during interactive testing
.
Table 11: Memory section types
Type Description
CDATA Code space; includes all code plus initialization tables. May
be in PROM.
IDATA Initialized data space; contains preset values specified at
compile time and instantiated in the target as part of power-
up initialization.
UDATA Uninitialized data space, allocated at compile time.
Its contents are unspecified.
At least one instance of each section must be defined, with upper and lower address
boundaries, before it is used. Address ranges for instances of the same section type
may not overlap. The syntax for defining a memory section is:
There is one exception to this rule: If no iData section is defined, the vectored oper-
ators that would normally act on iData will use the current cData section instead,
This scheme should only be used when the following conditions are met:
1. The CPU does not have separate code and data spaces (i.e. this is not a Harvard
Architecture machine).
2. No matter what the boot medium (PROM, flash, disk, etc.), the target loads the cData
image into RAM for execution.
An instance becomes the current section of its type when its name is invoked. The
compiler will work with that section as long as it is the current one, maintaining a
set of allocation pointers for each section of each type. Only one section of each
type is current at any time.
The words used to allocate and access memory (the vectored words in the glossaries
below) operate on the current section of the current type. Some words control only
cData, and are available any time; their use does not affect the selection of the cur-
rent section or type. Use of one of the section type selectors CDATA, IDATA, or UDATA
sets the section type for the vectored words. If you only have one section of each
type, the section names are rarely used.
Here is an example from a typical Config.f file with one section of each type:
INTERPRETER HEX
50 Cross-compiler Principles
SwiftX Reference Manual
The current state of all section definitions, including the current section type and
the current section of each section type—but not the contents of the sections—is
called the section context. It may be saved and restored by SAVE-SECTIONS and
RESTORE-SECTIONS.
CDATA (—)
Select cData as the current section type.
IDATA (—)
Select iData as the current section type.
UDATA (—)
Select uData as the current section type.
SAVE-SECTIONS ( — n*x n )
Save the entire current section context, consisting of n cells.
RESTORE-SECTIONS ( n*x n — )
Restore the entire section context previously saved by SAVE-SECTIONS.
Vectored Words
ORG ( addr — )
Set the address of the next available location in the current section of the current
section type.
HERE ( — addr )
Return the address of the next available location in the current section of the cur-
rent section type.
ALLOT (n—)
Allocate n bytes at the next available location in the current section of the current
section type.
ALIGN ( —)
Force the space allocation pointer for the current section of the current section type
to be cell-aligned.
C, (b—)
Compile b at next available location (cData and iData only).
Cross-compiler Principles 51
SwiftX Reference Manual
W, (x—)
Compile a word (the low-order 16-bits of x) at the next available location (cData and
iData only). Available on 32-bit targets only.
, (x—)
Compile a cell at the next available location (cData and iData only).
cData-specific Words
THERE ( — addr )
Return the address of the next available location in the current cData section.
GAP (n—)
Allocate n bytes at the next available location in the current cData section.
C,C (b—)
Compile b at the next available location in the current cData section.
W,C (x—)
Compile a word (low-order 16-bits of x) at the next available location in the current
cData section. Available on 32-bit targets only.
,C (x—)
Compile a cell at the next available location in the current cData section.
References Compiling words and literals, Forth Programmer’s Handbook, Section 2.9
Most defining words in SwiftX are used to create executable target definitions.
Some—such as those created by : (colon) and CODE—are executable functions; oth-
ers are data objects of various kinds. However, data objects may be thought of as
having an executable component (or characteristic behavior), as well as a data com-
ponent (or value). For example, the behavior of a word defined by CONSTANT is to
return its value, whereas a word defined by VARIABLE returns the address of its data.
One defining word, EQU, does not exist in the target. An EQU is a constant for use by
the cross-compiler, and has neither an executable component nor data space in the
target. EQU is typically used to name an address, flag, size, etc., that the cross-com-
piler will use in preparing the target system. When used insdie a target colon defini-
tion, an EQU will be compiled as a literal. This feature is used to great advantage by
the Optimizer in many SwiftX Pro implementations.
Target defining words place their executable components in code space. Data-
defining words such as CREATE—and custom defining words based on CREATE—make
definitions that reference the section type and instance that are current when CRE-
ATE is executed.
Because uData is only allocated at compile time, there is no compiler access to it.
uData is allocated by the defining words themselves; a summary of defining words
52 Cross-compiler Principles
SwiftX Reference Manual
More details on the use of defining words, and how to make custom defining words,
may be found in the Forth Programmer’s Handbook.
Glossary
2CONSTANT <name> ( x1 x2 — )
Define a two-cell constant whose values are x1 x2. Execution of name returns x1 x2.
You cannot change the value of a 2CONSTANT.
TO <name> (x—)
Store x in name’s data space. name must have been defined by VALUE.
Cross-compiler Principles 53
SwiftX Reference Manual
RESERVE ( n — addr )
Allocate n bytes of uData, starting at addr.
Words that access code and data space are described in this section. The behavior
of these words depends critically on the context in which they are used. When they
are used inside target definitions, they behave in a straightforward manner, refer-
encing target data at given addresses as described in the Forth Programmer’s Hand-
book.
However, if you use these words interpretively (e.g., typing them during debugging,
outside of definitions in a source file, or in the compile-time part of a defining or
compiling word), they have a special cross-compiler behavior that depends on
whether you are connected to a running target system using the XTL (see Section
4.9.1).
Unless you are connected to a running target, access using the words described in
this section is restricted to cData and iData.
The following words are used to access individual bytes, cells, and words. As with
the allocation and initialization words in Section 4.3, the primary words are vec-
tored according to the current section type; but some convenient cData-specific
equivalents do not affect the selection of the current section type.
C@ ( addr — b )
Fetch a byte from addr in the current section of the current section type.
W@ ( addr — x )
Fetch a word (16-bits) from addr in the current section of the current section type.
Available on 32-bit targets only.
54 Cross-compiler Principles
SwiftX Reference Manual
@ ( addr — x )
Fetch a cell from addr in the current section of the current section type.
C! ( b addr — )
Store a byte at addr in the current section of the current section type.
W! ( x addr — )
Store a word (the low-order 16-bits of x) at addr in the current section of the current
section type. Available on 32-bit targets only.
! ( x addr — )
Store a cell at addr in the current section of the current section type.
cData-specific Words
C@C ( addr — b )
Fetch a byte from addr in the current cData section.
W@C ( addr — x )
Fetch a word (16-bits) from addr in the current cData section. Available on 32-bit
targets only.
@C ( addr — x )
Fetch a cell from addr in the current cData section.
C!C ( b addr — )
Store a byte at addr in the current cData section.
W!C ( x addr — )
Store a word (low-order 16-bits of x) at addr in the current cData section. Available
on 32-bit targets only.
!C ( x addr — )
Store a cell at addr in the current cData section.
The following words are used to initialize and manage strings. All are vectored
according to the current section and section type. See Section 4.5 for the restric-
tions that apply to these words.
Glossary
Cross-compiler Principles 55
SwiftX Reference Manual
This section describes SwiftX tools used to create and test target commands.
Forth’s compiler and interpreter work together to process source text for this pur-
pose. Strictly speaking, a Forth compiler is only operating between the colon that
begins a definition and the semi-colon that ends it. The interpreter is processing
the text, finding words and either executing them or delivering them to the com-
piler for processing. However, the consequence of executing most of the words
encountered in source text causes definitions and data objects to be constructed
and manipulated in the target image, both inside and outside of colon definitions,
an activity that falls within the broad, commonly understood meaning of compila-
tion. It is this broader definition that we will discuss in this section.
The glossary below lists examples of defining words used to begin compilation or
when creating defining words. Data-space defining words are described in Section
4.4; commands that allocate or fill memory are listed in Section 4.3.
Glossary
56 Cross-compiler Principles
SwiftX Reference Manual
END-CODE (—)
End a code word that was started with CODE or LABEL.
: <name> (—)
Begin compiling a Forth definition. Target definitions may not be referenced out-
side a colon definition unless the host is connected to the target with an active XTL.
DOES> (—)
Begin the run-time action of a new defining word written in high-level Forth. Used
with CREATE (see the Forth Programmer’s Handbook and Section 4.7).
;CODE (—)
Similar to DOES>, but the run-time action is written in assembler code.
; (—)
End a Forth definition that was started with : (colon).
Many details of this advanced subject are outside the domain of this document;
they are covered more thoroughly in the Forth Programmer’s Handbook. However,
when developing a target application, sometimes it can be helpful to extend the
supplied cross-compiler. To do so, it is necessary to understand that a Forth sys-
tem implements multiple (e.g., host and target) versions of some words and selects
among them by managing the way in which its dictionary is searched.
For example, a Forth cross-compiler includes an integral Forth compiler and assem-
bler; they are used to build the target compiler and assembler which, in turn, are
used to construct target code. But some words—from simple primitives to higher-
level compiler words like : (colon) and IF—are defined in more than one of these
places, and are implemented differently in each to provide specific functionality in
each context.
The scopes defined in SwiftX are listed in Table 12. These words specify the scope
to which new words will be added, as well as the words that are available to the
compiler. Each of these remains in effect until explicitly changed.
By default, new commands belong to the TARGET scope; i.e., they are compiled onto
the target. But after the ASSEMBLER command, new words will be added to the
assembler and will be found while assembling machine instructions into the target.
Likewise, after the INTERPRETER command, new words are added to the host that will
be found when the host is interpreting on behalf of the target; and so on.
Cross-compiler Principles 57
SwiftX Reference Manual
If you use any of these scope selectors (or compiler directives) to change the default
scope, you must later use TARGET before commands can again be compiled to the
target. SwiftX’s status line (at the bottom of the command window) indicates the
current scope, so you can easily verify, for example, that the current scope is TARGET
when you attempt to interactively test a target word.
The compiler directive in force at the time you create a new colon definition is the
scope in which the new word will be found. As a trivial example:
TARGET ok
: Test1 1 . ; ok
Test1 1 ok
INTERPRETER ok
Test1
Error 0 TEST1 is undefined
On rare occasions, while defining a new word, you might need to specify words
from scopes other than the one currently in effect. Therefore, the specifiers in
Table 13 are provided for use inside colon definitions being built in the host. They
add the search orders COMPILER, ASSEMBLER, etc., to the beginning of the current
search order, without otherwise changing the search order. These additions nor-
mally are for some limited, specific purpose, so the command [PREVIOUS] may be
used to remove the most recent addition.
58 Cross-compiler Principles
SwiftX Reference Manual
Glossary
ASSEMBLER (—)
Select ASSEMBLER scope. This provides access to the native instruction set of the tar-
get CPU. Selecting this scope lets you customize your assembler, for example, by
adding macros.
COMPILER (—)
Select COMPILER scope. Words defined in this scope will be available for execution
only while compiling target colon definitions; selecting this scope lets you custom-
ize your compiler. Examples of COMPILER words include IF, ELSE, THEN, BEGIN, UNTIL,
DO, LOOP, and similar words.
HOST (—)
Select HOST scope. HOST words are used on rare occasions to extend the host system
to provide specialized compiler capabilities that will be used in scopes other than
TARGET, or to execute the host versions of words that have been redefined in other
scopes.
INTERPRETER (—)
Select INTERPRETER scope. Add the following definitions to the host environment’s
interpreter. INTERPRETER words are used to create target data objects. Examples
include CREATE, VARIABLE, etc.
TARGET (—)
Select TARGET scope. This is the default compiler state. If you select another scope,
you must re-assert TARGET before producing any more target definitions.
Target colon definitions are available for interactive execution and testing only
when you are connected to a target via an interactive XTL. Target data objects are
executable when interpreting, according to the guidelines in Section 4.6.4.
[+ASSEMBLER] (—)
Add ASSEMBLER scope to the current scope inside a colon definition. This gives
access to mnemonics, addressing modes, etc., to define assembler macros.
Cross-compiler Principles 59
SwiftX Reference Manual
[+INTERPRETER] (—)
Add INTERPRETER scope to the current scope inside a colon definition. This lets you
access the compile-time behavior of a defining word.
[+HOST] (—)
Add HOST scope to the current scope inside a colon definition. This lets you access
the underlying Forth system’s behavior of a word that is defined in both HOST and
TARGET (e.g., @).
[+TARGET] (—)
Add TARGET scope to the current scope inside a colon definition. This lets you
access target words from within an INTERPRETER or HOST definition.
[PREVIOUS] (—)
Remove the most recently added scope from the search order. This is normally
used following the actions enabled by words such as [+ASSEMBLER] above, to return
to the previous scope.
References Word lists and search order, Forth Programmer’s Handbook, Section 3.6
The behavior of words defined in each of these scopes is different for colon defini-
tions than for data objects, and also depends upon the state (compiling or interpret-
ing) in which they are invoked.
The default behavior of colon definitions when they are invoked in interpreting
state is to be executed. However, COMPILER words may not be invoked in interpret-
ing state, and TARGET words may only be invoked when you are connected to a target
via an active XTL.
Table 14 shows the accessibility of colon definitions defined in various scopes when
they are invoked in interpreting and compiling states.
60 Cross-compiler Principles
SwiftX Reference Manual
Defining words other than : (colon) are used to build data structures with charac-
teristic behaviors. Many such words are included in SwiftX, and it is possible to
construct new ones, if you wish.
• iData objects in initialized data memory—e.g., words defined by CREATE, VALUE, etc.,
including most user-defined words made with CREATE … DOES>.
• uData objects in uninitialized data memory—e.g., words defined by the use of VARI-
ABLE, BUFFER:, etc.
• Constants—words defined by CONSTANT, 2CONSTANT, and USER.
Unlike target colon definitions, target data objects may be invoked in interpreting
state. However, they may not exhibit their defined target behavior, because that is
available only in the target (or in interacting state). Constants will always return
their value; other words will return the address of their target data space address.
iData objects may be given compiled, initial values with , (comma) and C, (c-
comma), and you may also use @ and ! with them regardless of whether you’re con-
nected to a target with an active XTL. However, there is no way to initialize uData
objects at compile time, and you may only access their data space when the XTL is
connected and active.
One of the most powerful features of Forth is the ability to construct custom data-
object defining words. The basic principles of custom defining words in Forth are
discussed in the Forth Programmer’s Handbook.
However, some special issues arise when creating custom data objects in a cross-
compiled environment: defining words are executed on the host, to create new defi-
Cross-compiler Principles 61
SwiftX Reference Manual
nitions that can be executed on the target. Therefore, you must be in the INTER-
PRETER scope (see Section 4.6.2) when you create a custom defining word, and you
must be aware of what data space you are accessing (see Section 4.3) in the new
data object.
INTERPRETER
TARGET
1 PRINTS ONE
2 PRINTS TWO
ONE and TWO are target definitions, instances constructed by the defining word
PRINTS. Each instance has its own value, but all objects defined by PRINTS share the
run-time behavior (@ and .) associated with PRINTS.
You must specify INTERPRETER before you make the new defining word, and then
return to TARGET to use this word to add definitions to the target. The INTERPRETER
version of DOES> allows you to reference TARGET words in the execution behavior of
the word, since that will be executed only on the target.
When CREATE (as well as other memory allocation words listed in Section 4.3) is exe-
cuted to create the new data object, it uses the current section type. The default in
SwiftX is iData. Defining words that explicitly use uData (VARIABLE, BUFFER:, etc.) do
not affect the current section type. If you wish to force a different section type, you
may do so by invoking one of the selector words (CDATA, IDATA, or UDATA) inside the
defining portion or before the defining word is used. If you do this, however, you
must assume responsibility for re-asserting the default section. You may choose to
use SAVE-SECTIONS and RESTORE-SECTIONS (described in Section 4.3).
You can control where individual instances of PRINTS definitions go, like this:
CDATA
1 PRINTS ONE
IDATA
2 PRINTS TWO
In this case, the data space for ONE is in code space, but the data space for TWO is in
initialized data space. (Not all processors support data objects in code spaces, so
TWO is portable and ONE is not.)
Alternatively, assuming your processor permits it, you could define PRINTS to
explicitly assert cData:
: PRINTS ( n -- )
CDATA \ Select code section.
62 Cross-compiler Principles
SwiftX Reference Manual
In this case, both the CREATE and the , (comma) will use cData.
Host PC Target
Figure 15 shows the action of a defining word. The run-time behavior of all its
instances exists at one place in the target cData. The host part of the defining word
can compile instances of its class, each of which has a definition in the host, a run-
time behavior in the target, and a data space in the target. The host portion of an
instance contains two pointers: the host pointer is to the data area in target address
space, while the target pointer is to the instance’s run-time code in the target. The
instance’s run-time code will call the general run-time code for the class, providing
the address of the instance’s data area. The data area may be in cData, iData, or
uData, but is usually in iData.
The demo program SwiftX\Src\Conical.f (see Section 1.5.3) contains a good exam-
ple of a custom defining word, MATERIAL, used to define materials. When executed,
a word that has been defined by using MATERIAL (an instance of MATERIAL) stores its
parameters in the variables used in the demo program.
If you invoke an instance’s name interpretively on the host, its behavior depends on
whether you’re connected to the target with an active XTL. If you’re connected, the
target pointer will be used to execute the target’s run-time behavior. If not, the host
pointer will be used to return the address of its data area; if that is in cData or
iData, you may read or write that location in the host’s target image.
It is possible to define custom host behaviors that emulate target behaviors (assum-
ing, of course, that it’s possible and doesn’t require access to target-only devices or
other features). The technology used to do this is called twins, because it involves
making twin dictionary entries in the Interpreter and Target scopes. The two key
words are TWIN (which makes a duplicate dictionary entry with one data cell, like a
VARIABLE ) and 2TWIN (which makes a duplicate entry with two data cells, like a
2VARIABLE). These words are already built into pre-existing defining words that
return values (e.g., CREATE, VARIABLE, CONSTANT), but are also available for defining
custom host behaviors.
Cross-compiler Principles 63
SwiftX Reference Manual
HOST
VARIABLE >FCB \ Current field, host copy
TARGET
VARIABLE >FCB \ Current field, target copy
INTERPRETER
: FCB: ( n1 -- n2 ) \ Defining word definition
DUP (FCB:) \ Make host twin
CREATE DUP , CELL+ \ Make target twin
DOES> @ >FCB @ + ; \ Target behavior
TARGET
0 FCB: ORG FCB: LIM FCB: R# DROP
In this example, FCB: defines fields within a file control block in data space. The
host twin word returns the field in the structure whose address is contained in the
host variable >FCB. The target word returns the field pointed to by the target vari-
able >FCB. The host twins are useful for defining precompiled structures in iData.
TWIN and 2TWIN should always be used in conjunction with a defining word (CREATE
in the above example) that creates target definitions. The built-in TWIN in words like
CREATE and CONSTANT is automatically bypassed if you use an explicit TWIN, as in the
example.
Glossary
2TWIN <name> ( x1 x2 — )
Make a duplicate dictionary entry for name in the current scope, leaving the input
stream unchanged (i.e., name still visible), and give it the initial values x1 and x2.
SwiftX can generate the object file formats shown in Table 15. Two commands,
shown in the glossary below, are available to create object files suitable for PROM
programmers and for downloading. In each case, the first letter of the filename
extension determines the format that will be used.
64 Cross-compiler Principles
SwiftX Reference Manual
First letter
of extension Format Example
H Intel Hex format Target.hex
S S-record format Target.s19
T TI txt record format Target.txt
any other Binary data Target.bin
If you have multiple cData or iData sections, each must be saved separately. For
example, to save two cData sections named ProgA and ProgB, you might use:
You may, if you wish, concatenate several cData or iData sections into a single
multi-record image using APPEND-CODE or APPEND-DATA, respectively. For example, to
write both sections in the previous example to the same file you could use:
Finally, if you are writing cData sections to records which require an absolute
address that is different from the logical address for which it is compiled (e.g., code
residing in PROM which will execute from a different address), you may specify the
absolute address by using ABSOLUTE preceding SAVE-CODE or APPEND-CODE. Note that
ABSOLUTE applies only to the next instance of SAVE-CODE or APPEND-CODE.
Glossary
ABSOLUTE ( addr — )
Used before SAVE-CODE or APPEND-CODE, specifies the absolute address where the
record is to begin.
APPEND-CODE (—)
Appends the current cData section to the file initiated by a previous use of SAVE-
CODE.
Cross-compiler Principles 65
SwiftX Reference Manual
APPEND-DATA (—)
Appends the current iData section to the file initiated by a previous use of SAVE-
DATA.
The cross-compiler can operate while connected (i.e., interacting with a terminal
using the XTL) or disconnected (not connected, or not using the XTL). Building a
program image for later downloading (the Project > Build menu option) may be
done in either mode, because the cross-compiler keeps an image in host memory of
each iData and cData section that has been defined (described in Section 4.3).
For targets using a serial line for the XTL, the command XTL-BAUD sets the baud rate.
This is normally found in the project’s Config.f file. You can get a copy of the
specified baud rate using the command @XTL-BAUD. This is commonly done in con-
junction with the target’s driver for the port being used for the XTL.
When you are compiling a program image for later downloading, the words in Table
16 access a host image of the current section being constructed or maintained. In
such circumstances, you may only access cData and iData.
When interacting with actual target memory via the XTL, you may access any type of
space, including uData. New definitions (including colon definitions and new data
structures) will modify the host image. On systems that support interactive compi-
lation, such changes will also be downloaded to the target, immediately available for
interactive testing. See your platform-specific documentation.
Words Descriptions
C@ C! Byte (character) fetch and store in the current section
W@ W! Word (16-bit) fetch and store in the current section
(available only on 32-bit targets)
@ ! Cell fetch and store in the current section
66 Cross-compiler Principles
SwiftX Reference Manual
Words Descriptions
C@C C!C Byte (character) fetch and store to code space
W@C W!C Word (16-bit) fetch and store to code space (available
only on 32-bit targets)
@C !C Cell fetch and store to code space
• Fully interactive, in which you can examine target memory and execute target defi-
nitions and, also, if you type a colon or code definition it will be immediately down-
loaded to the target, ready for testing.
• Batch, in which the target is temporarily disconnected and an image of your code is
compiled in the host memory for later downloading. This mode is much faster if
you’re compiling one or more files of source, as opposed to typing single defini-
tions.
These modes are controlled by SET-DOWNLOAD and DOWNLOAD-ALL. You can see how
these are used in the file Debug.f, where you’ll find a sequence like:
SET-DOWNLOAD
INCLUDE ..\..\CONICAL \ Conical piles demo
INCLUDE ..\..\DUMB \ Dumb terminal
256 TERMINAL CONSOLE
: DEMO CONSOLE ACTIVATE DUMB SCI-TERMINAL
BEGIN CALCULATE AGAIN ;
DOWNLOAD-ALL
SET-DOWNLOAD is called before the files are INCLUDE d, the task defined, and the
startup word DEMO defined. These actions occur in batch mode. When they are com-
plete, DOWNLOAD-ALL downloads the compiled code and reconnects the XTL in full
interactive mode. To test your application interactively, all you have to do is
replace the demo files and definitions with your application.
To support interactive debugging, the image of the target dictionary and data space
in the host must be an exact match for the one in the target. To ensure this, SwiftX
places a checksum of a compiled kernel in the kernel image. This will be checked
near the beginning of Debug.f, as follows:
• If SwiftX can install a new kernel without a manual procedure (e.g. it resides in flash
or RAM), a check is performed in the word RELOAD, which will automatically down-
load a new kernel if there is no match. You can force a new download by executing
the command RELOAD!. An active XTL is required.
• If a special procedure is required to install a new kernel, the check is performed by
the word SYNC-CORE, and you will get an error message if the checksum doesn’t
match. You must then install a new kernel by the procedure appropriate for your
target.
Cross-compiler Principles 67
SwiftX Reference Manual
Glossary
XTL-BAUD (n—)
Sets the baud rate for serial XTL communication, on targets using it, to rate n.
@XTL-BAUD (—n)
Returns the baud rate for serial XTL communication, on targets using it.
CONNECT (—)
Starts the XTL communicating with the target. CONNECT will abort if target commu-
nication cannot be established (e.g., it is not connected or not responding). When
communication is established, the host can execute words on the target, examine its
memory, etc.
DISCONNECT (—)
Shuts down the XTL link. When this is done, you may no longer execute target
words. You may, however, examine the host image of cData and iData, and perform
host functions such as LOCATE, WH, etc.
SET-DOWNLOAD (—)
Disconnects the XTL, saves target code and data space pointers, and enters batch
mode. Subsequent compilation affects the host’s image of target cData and iData
only.
DOWNLOAD-ALL (—)
Re-connects to the target. Compares the saved code and data space pointers with
the current ones, and downloads all new cData and iData. Leaves the target in inter-
active mode, ready to test the new code.
RELOAD (—)
Compares the checksum of the most recently compiled kernel with the one in the
target, and automatically downloads a new kernel if necessary.
RELOAD! (—)
Downloads a new kernel unconditionally.
SYNC-CORE (—)
Ensures that the host and target images of code space are synchronized by compar-
ing their checksums. If the comparison fails, interactive testing will not be possible
until a matching kernel is installed in the target.
Figure 16 is an overview of the logical relationship between the host and target
using a standard serial XTL. Implementations using a BDM or JTAG may differ; see
your platform-specific documentation.
Table 17 lists each command from the host to the target, parameters sent to the tar-
get, and parameters received from the target in response to the command.
68 Cross-compiler Principles
SwiftX Reference Manual
Parameters Parameters
Fn Description to target from target
0 Execute target word n(1), data(n*4) {cmd(1)}n(1),
data(n*4),
ack(1)
1 Send back register contents CPU dependent
2 Fetch byte from data space addr(4) data(1), ack(1)
3 Store byte to data space addr(4), data(1) ack(1)
4 Fetch half-cell (16-bits) addr(4) data(2), ack(1)
from data space
5 Store half-cell to data space addr(4), data(2) ack(1)
6 Fetch cell from data space addr(4) data(4), ack(1)
7 Store cell to data space addr(4), data(4) ack(1)
8 Download to data space length(1)[a], ack(1)
addr(4), data(n)
9 Fetch byte from code space addr(4) data(1), ack(1)
10 Store byte to code space addr(4), data(1) ack(1)
11 Fetch half-cell from code addr(4) data(2), ack(1)
space
12 Store half-cell to code space addr(4), data(2) ack(1)
13 Fetch cell from code space addr(4) data(4), ack(1)
14 Store cell to code space addr(4), data(4) ack(1)
15 Download to code space [a]
length(1) , ack(1)
addr(4), data(n)
a. Buffer length 1..255 or 0 for 256.
Commands from host to target consist of a single byte, followed by optional param-
eters; the size of each parameter, in bytes, is noted in parentheses. The target exe-
cutes the command, returns its optional parameters, and ends with a positive
acknowledge (ack) code (see Table 18). Multi-byte parameters are sent most-signifi-
cant byte first. The half-cell operations (Fn 4, 5, 11, and 12) are available on 32-bit
targets only.
All data transmitted, in both directions, are binary 8-bit characters. One exception
is the Esc character (ASCII 27), which has special meaning when transmitted to the
target. Esc followed by any other character tells the target to abort the current com-
mand in progress and to return an “Announce reset” (255) response. Two Esc char-
acters in a row indicate a single data byte whose value is 27. The Esc character has
no special meaning when transmitted from the target to the host.
Cross-compiler Principles 69
SwiftX Reference Manual
Target processes
command
Host service No
needed?
Yes
Host processes
Target sends request
request (usually
to host
character I/O)
The data indicated in Table 17 for function 0 (execute target word)—for both host
and target—is the parameter stack. The stack is passed bottom item first. When
sent from the host to the target, the top two stack items are the execution address
for the word and the host’s BASE. (If the target implements CATCH and THROW excep-
tion handling, it executes the word using CATCH.) When returned by the target to the
host, the top two stack items are the host’s BASE and the function’s THROW code (0
indicates successful completion or that CATCH/THROW isn’t implemented on the tar-
get). Thus, the value n (number of stack items) is always at least two, in both direc-
tions. The cmd parameter in the “from target” field can be any of the responses
listed in Table 18. The host will not begin receiving the target stack until it receives
the Ack response, indicating that the target has finished executing its word.
Parameters Parameters
Fn Description from target to target
255 Announce reset
70 Cross-compiler Principles
SwiftX Reference Manual
Parameters Parameters
Fn Description from target to target
254 Ack; command completed suc-
cessfully
253 Nak; command aborted[a]
252 KEY (input key and send it back) char(1)
251 KEY? flag(1)
(test for keypress, send status
back)
250 Display address addr(4)
249 ACCEPT addr(4), length length(1)
(input string, return actual (1)
length)
248 AT-XY (cursor position) row(1), col(1)
247 Write data to log file 247, length (1),
data (length)
13 CR (new-line function)
12 PAGE (clear-screen function)
a.Target issues function 253 on start-up and on restart.
Table 18 lists the possible cmd responses from the target; they are only valid while
the host awaits the initial response to function 0 (execute target word). These
response codes enable the host to provide virtual terminal services to the target.
The host will acknowledge any of the terminal output functions by sending an
unspecified character to the target, to pace output.
If the program under test never returns control to the host, pressing the “Stop Sign”
button on the SwiftX debug window toolbar abort out of the wait loop. This is use-
ful when testing a routine whose behavior is an infinite loop, or when a program
behaves unexpectedly. Note that aborting out of the wait loop leaves the target in an
indeterminate state. It will be necessary to restart the target and the XTL to regain
control from the debug window.
Except for the codes listed in Table 18 and the data logged, all characters sent from
the target to the host will be displayed by the host in the command window.
The code 247 (supported only on devices with serial XTLs) facilitates writing test
data from a target to a file on the host. The applicable commands are X-LOG and X-
CLOSE use XTL function 247 to send binary log data to the host to be written to a
file named Target.log. Blocks of data are written in records of up to 255 bytes
each. The message format is:
Cross-compiler Principles 71
SwiftX Reference Manual
A special form is used by X-CLOSE which sends a length byte of 0 and no data. This
tells the host to close the file. Subsequent calls to X-LOG will over-write the existing
Target.log file.
Glossary
X-LOG ( addr n — )
Sends the data at addr of length n bytes to the host. The data will be logged in the
next record of the file Target.log (which will be created and/or opened if neces-
sary).
X-CLOSE (—)
Closes the Target.log file. Subsequent calls to X-LOG will over-write data in this file.
72 Cross-compiler Principles
SwiftX Reference Manual
SwiftOS supports two types of tasks: background tasks and terminal tasks. These
are fundamentally identical, but a terminal task can be thought of as a more elabo-
rate background task tailored to service a serial-type device. You can easily prune
unnecessary resources from a terminal task, or add more to either kind of task.
Each task has a private area of uData space containing its data and return stacks
and a user area for task-specific variables.
1. Task definition takes place at compile time. Tasks are given fixed allocations of
memory in which to operate, including stack space and user area.
2. Task initialization takes place after power-up in the target system. At this time, the
task’s RAM areas are initialized and it is linked into the running multitasker loop.
3. Task activation may take place at one or more points in the running application.
This involves giving the task words to execute. It may be a temporary assignment
(execute this, then stop) or a permanent one (start running an infinite loop).
Although the definition and physical structure of a task is static, its job assign-
ments may change according to the needs of the application.
When more than one task can share a piece of code, that code can be called re-
entrant. Re-entrancy is valuable, because memory is conserved when tasks share
code.
Routines that are not re-entrant are those containing elements that are subject to
change while the program runs. Thus, self-modifying code is not re-entrant. Rou-
tines with private variables are not re-entrant, but re-entrant routines can have pri-
vate constants (because a constant’s value does not change). Re-entrant routines
can always be programmed into ROM.
Forth routines can be made completely re-entrant with very little effort. Most keep
their intermediate results on the data stack or the return stack. Programs to handle
strings or arrays can be designed to keep their data in the section of RAM allotted to
each task. It is possible to define public routines to access variables, and still retain
re-entrancy, by providing private versions of these variables to each task; such vari-
ables are called user variables.
Since re-entrancy is easily achieved, tasks may share routines in a single program
space. This conserves large amounts of memory. In most applications, all system
and application routines can be shared (with the minor exception of the I/O instruc-
tions on certain processors). Terminal tasks (such as printer spooling) can operate
with only a few hundred bytes. The minimum size of a useful task is about 512
bytes, devoted to the task’s stacks and user variables. Some applications (PBXs,
process control, and some communications systems) naturally use large arrays of
small tasks, with each task running a simple shared program.
Simplicity and good performance are ensured because task-switching only happens
at known, programmer-controllable points, and between Forth words. This greatly
simplifies the context-switching operation (thus reducing overhead) and the job of
writing routines for a multi-user environment.
This section provides a detailed discussion of the scheduling algorithm, its associ-
ated words, and some useful techniques. Processor-specific details of the SwiftOS
implementation are described in a separate document accompanying your SwiftX
product.
The SwiftOS multitasker may be said to be I/O driven. A round-robin algorithm (see
Figure 17) schedules processor time. Each task has control until it executes the
high-level PAUSE or STOP, or the assembler code ending WAIT. Most words perform-
ing asynchronous hardware operations (e.g., TYPE, ACCEPT) contain a WAIT or a jump
to PAUSE so, while a task is waiting for an I/O operation to be completed, other tasks
can use the CPU. Since Forth is naturally very fast, tasks tend to spend much of
their time awaiting I/O. Tasks that perform extensive computations may be pre-
vented from impacting overall system performance by incorporating PAUSE into a
few regularly executed or CPU-intensive words.
The round robin is sometimes called the PAUSE loop, the idle loop, or the multitask-
ing loop. Where possible, it is implemented as an endless loop of jump instructions
(see Figure 17). Each task has its own jump instruction, which transfers control to
the jump instruction of the next task.
When a task is being scheduled to awaken, the task’s jump instruction is replaced
by an instruction to transfer control to the machine code that awakens the task.
This special instruction is usually called WAKE, and is usually a trap or subroutine
call. The address of the first byte of a task’s jump instruction is pushed on the
stack by the high-level Forth word STATUS, a user variable (see Section 5.2.3) for the
current task. In assembly code, the address of the current task’s STATUS is available
in register U. The address used by the jump in STATUS immediately follows it.
TaskA
TaskB
TaskE
(active)
TaskD TaskC
The most general case of changing tasks in the round robin occurs when CPU con-
trol is relinquished from high-level Forth, with arrangements for the task to awaken
and resume execution on its next turn. PAUSE performs this most general case.
PAUSE can be embedded in complex calculations which perform no I/O and which
might otherwise cause a particular task to control the CPU for undesirably long
periods. Consider the following collision-orbit calculation:
In this example, the word STEP is assumed to have been defined to perform the cal-
culations for integrating the next step in the target X or Y coordinate. HIT expects
the coordinate of the target (computed by POSITION) on the stack and performs
appropriate course corrections. Because these computations are time consuming,
and because other functions must be running concurrently, it is desirable to give up
the CPU for one turn around the round robin for each step in the integration.
Inserting the PAUSE in the loop accomplishes this.
The related words STOP and WAIT (see the glossary below) share much of the code
for PAUSE. These are the steps PAUSE performs:
1. The WAKE instruction is stored into STATUS, replacing the round-robin jump, so that
the task executing PAUSE will awaken on its next turn. On many machines, WAKE is
equivalent to a subroutine call to the code for step 5, below.
2. The system pointers I and R are saved by being pushed onto the current task’s data
stack. This portion of the code is the entry point for STOP and WAIT, which by skip-
ping step 1 do not automatically resume execution of the current task on the next
turn. (On some implementations, the address interpreter pointer I is not needed;
see your platform-specific SwiftX documentation for details.)
3. The data stack pointer (S, in assembler) is saved in a reserved location in the user
area. At the completion of this step, all non-recoverable unshared task data for the
address interpreter has been saved. Tasks only relinquish the CPU between Forth
words, so other registers do not have to be saved.
4. The CPU jumps to the location whose address follows STATUS (i.e., the next task’s
STATUS), and proceeds to jump through the circular round-robin loop until a WAKE
instruction is encountered. The WAKE transfers control to step 5.
5. The address of the new task’s STATUS is stored in U. The address of STATUS can be
obtained from the address left by WAKE.
6. Using U to find the task, the data-stack pointer is restored, then I and R are restored
from the new task’s data stack.
7. The SLEEP instruction (a jump to the next task) is stored into the current task’s STA-
TUS to make the current task’s state “don’t awaken.”
8. Finally, PAUSE is exited and the task will execute its next word, based on the con-
tents of I and R.
The words in the glossary below control task use of the CPU.
Glossary
PAUSE (—)
Suspend the task that calls PAUSE to allow all other tasks one turn in control of the
CPU.
STOP (—)
Put the task that calls STOP to sleep until that task is awakened by an interrupt rou-
tine or by some other task.
WAIT (—)
An assembler code ending on some systems that is equivalent to STOP.
WAKE (—x)
Return x, the machine instruction (usually a trap instruction or subroutine call) that
may be stored in a task’s STATUS to cause the task to be awakened at its next turn in
the multitasker round robin. See your platform-specific documentation for imple-
mentation details.
SLEEP (—x)
Return x, the machine instruction (a jump to the task whose address follows the
current task’s STATUS) that may be stored in a task’s STATUS to cause the task to
remain inactive (skip its turn in the round robin). See your platform-specific docu-
mentation for implementation details.
Interrupt routines are often used to awaken tasks. A common way to perform com-
plex, non-critical interrupt servicing is to have the interrupt routine perform all
time-critical operations, and then store WAKE into a task’s STATUS. For example, if a
hypothetical data acquisition word ACQUIRE solicits data from a serial device, it
could send a request to the device and then STOP. Input from the device could be
buffered by interrupt code; when the interrupt code sees a carriage return, it would
awaken the terminal task associated with the interrupting device. When the round
robin gets around to the task, the task resumes execution at the word immediately
following STOP, and runs until it executes another STOP or PAUSE, or WAITs for an I/O
operation.
Tasks typically perform asynchronous operations such as data reduction and log-
ging. An example of a data reduction loop being run by a dedicated task might be:
The interrupt routine that services the data source for this example will awaken the
task by storing WAKE in the task’s STATUS when data is ready to be accepted.
In SwiftOS, tasks can share code for the text interpreter, I/O drivers, etc., but each
task will have different data for these facilities. The fact that all users have private
copies of variable data for such shared functions enables them to run concurrently
without conflicts. For example, number conversion in one task needs to control its
BASE value without affecting that of other tasks.
Such private variables are referred to as user variables. User variables are not
shared by tasks; each task has its own set, kept in the task’s user area.
• Executing the name of a user variable returns the address of that particular variable
within the task that executes it.
• Invoking <task-name> @ returns the address of the first user variable in task-
Some user variables are defined by the system for its use. You may add more in
your application, if you need to in order to preserve re-entrancy, to provide private
copies of the application-specific data a task might need.
User variables are defined by the defining word +USER, which expects on the stack
an offset into the user area, plus a size (in bytes) of the new user variable being
defined. A copy of the offset will be compiled into the definition of the new word,
and the size will be added to it and left on the stack for the next use of +USER. Thus,
when specifying a series of user variables, all you have to do is start with an initial
offset and then specify the sizes. When you are finished defining +USER variables,
you may save the current offset to facilitate adding more later. The conventional
way to do this is by using EQU (which makes a host-only constant and, conveniently,
removes the last offset from the stack).
The minimum SwiftOS user area begins something like this (details vary, depending
upon your target CPU):
0 2 +USER STATUS
CELL +USER FOLLOWER
CELL +USER SSAVE
CELL +USER S0
CELL +USER CATCHER
EQU #USER
Here, the task’s status area starts at offset 0 relative to the beginning of the user
area, and provides two bytes for a jump to the next task. Next, one cell is provided
for the address of the next task in the loop, followed by a cell for the “stack-pointer
save” location, and then S0, etc.
It is good practice to group user variables as much as possible, because they are dif-
ficult to keep track of if they are scattered all over your source.
A user variable is defined as an offset into the user area, where a zero offset usually
corresponds to STATUS. The offset is the number passed on the stack during a
sequence of +USER definitions; the current value of the offset is compiled into each
user variable definition, and the offset left on the stack is incremented by the num-
ber of bytes to be reserved (one cell, in most of the examples above). Eventually,
when a task executes a user variable, its offset is added to the register containing
the address of the currently executing task’s user area. Therefore, all defined user
variables are available to all tasks that have a user area large enough to contain
them (see Figure 18; also task definition, Section 5.3.1 and Section 5.4.1).
Background task
0 WATCHER 8 10
Outside WATCHER's
user area
Terminal task
0 TYPIST 8 18 32
The system does not test an address returned by invoking a user variable to see if it
is within the space allotted to the current task’s user variables. It is your responsi-
bility not to let a task reference a user variable outside its own user area!
The minimum size for a background task’s user area would be about five cells for
the example on the previous page, for STATUS through CATCHER. Terminal tasks gen-
erally have a larger user area to accommodate I/O, task management, dictionary
management (in programmable systems—see Section 7.1.3), text interpretation, and
other functions.
A task may need to initialize another task’s user variables, or to read or modify
them. The word HIS allows a task to access another task’s user variables. HIS takes
two arguments: the address of the task of interest, and the address of the user vari-
able of interest. For example:
will set the user variable BASE of the terminal task named CHUCK to 2 (binary). In this
example, HIS takes the address of the executing task’s BASE and subtracts the STA-
TUS address of the executing task from it to get the offset, then adds the offset to
the STATUS address of the desired task, supplied by CHUCK.
The user variable definitions provided for COLLECT in the sample data logger devel-
oped below are examples of application-specific user variables. Note how HIS is
used to transfer a value from the stack of the task that starts the definition RECORD
to the user variable #SAMPLES belonging to the task SCRIBE, which will execute the
words COLLECT and STOP following ACTIVATE.
This example assumes that A/D will request a sample from an analog-to-digital con-
verter, PAUSE while the conversion takes place, and signal via an interrupt when a
1.Example is for a 16-bit target
sample is ready. The interrupt should read the sample, put it in a temporary place,
then set the task to awaken. The rest of A/D will get the value and put it on the
stack. This scenario is typical of the relationship between interrupt code and task-
level code.
This version of RECORD would be used with the number of samples as its argument;
the task address is built in SCRIBE. The following phrase would record 500 samples:
500 RECORD
The glossary at the end of this section shows the user variables required by a fully
interactive SwiftOS terminal task. Your CPU’s implementation may require variables
not listed—see your SwiftX implementation’s system and user variables defined in
Swiftx\Src\<CPU>\data.f.
Although the order in which they are defined varies, all systems possess these user
variables. You can obtain the absolute address of location 0 in a task’s user area by
typing:
<task-name> @
All user variables return the address of the value for the task that is executing when
they are invoked.
See Data.f for the exact organization of user variables in your system. Generally,
the most-used user variables are defined first, so tasks needing only some of the
user variables can have a minimal-sized user variable area.
The first glossary below lists words used to manage the user variables. It is fol-
lowed by the user variables in two groups: those required for all tasks, and those
used only by terminal tasks.
+USER ( n1 n2 — n3 )
Define a user variable at offset n1 in the user area, and increment the offset by the
size n2 to give a new offset n3.
#USER (—n)
Return the number of bytes currently allocated in a user area. This is an appropri-
ate offset for the next user variable when this word is used to start a sequence of
+USER definitions intended to add to previously defined user variables.
STATUS ( — addr )
Indicates whether the task is ready to become active, by containing a jump to the
wake up code or to FOLLOWER.
FOLLOWER ( — addr )
Address of the next task in the multitasking chain.
SSAVE ( — addr )
Stack pointer, saved when the task was last active.
S0 ( — addr )
Pointer to the bottom of the data stack and the start of the message buffer (for ter-
minals). The data stack grows toward low memory from addr, and the message buf-
fer, if any, extends toward high memory from this same addr.
CATCHER ( — addr )
Pointer to the latest exception frame (0 if none), set by CATCH.
DEVICE ( — addr )
Terminal device address or other device information.
BASE ( — addr )
Address of the variable containing the number conversion base (eight for octal, ten
for decimal, sixteen for hex).
'EMIT ( — addr )
Address of the task’s EMIT routine.
'TYPE ( — addr )
Address of the task’s TYPE routine.
'CR ( — addr )
Address of the terminal new-line routine.
'PAGE ( — addr )
Address of the terminal screen clear or form-feed routine.
'ATXY ( — addr )
Address of a routine to position the terminal’s cursor.
'CLEAN ( — addr )
Address of the task’s “clear to end of line” routine.
C# ( — addr )
Task’s current cursor position (column), set to 0 by CR and PAGE, and maintained as
appropriate by EMIT, TYPE, and AT-XY.
L# ( — addr )
Task’s current cursor position (line), set to 0 by PAGE, and maintained as appropriate
by CR and AT-XY.
TOP ( — addr )
Top of task’s screen-scrolling area, expressed as a line number, with 0 signifying the
top of the screen.
'KEY ( — addr )
Contains the most recent character received since the last ACCEPT or KEY; or 0, if
none.
'KEY? ( — addr )
Returns true if a key is ready to be read by KEY.
'ACCEPT ( — addr )
Address of the task’s ACCEPT routine.
SPAN ( — addr )
Contains the number of characters read by the most recent ACCEPT.
#TIB ( — addr )
Contains the actual number of characters available to interpret in the input stream.
Some system resources must be shared by tasks without giving any single task per-
manent control of them. Disk units, tape units, printers, non-reentrant routines,
and shared data areas are all examples of resources available to any task but limited
to use by only one task at a time.
SwiftOS controls access to these resources with two words that resemble Dijkstra’s
semaphore operations. (Dijkstra, E.W., Comm. ACM, 18, 9, 569.) These words are
GET and RELEASE.
As an example of their use, consider an A/D multiplexor. Various tasks in the sys-
tem are monitoring certain channels. But it is important that while a conversion is
in process, no other task issue a conflicting request. So you might define:
VARIABLE MUX
: A/D ( ch# -- n ) \ Read a value from channel ch#
MUX GET (A/D) MUX RELEASE ;
In the example above, the word A/D requires private use of the multiplexor while it
obtains a value using the lower-level word (A/D). The phrase MUX GET waits in the
PAUSE loop (see definition of GET, below) to obtain private access to this resource.
The phrase MUX RELEASE releases it, without awakening another task.
GET checks a facility repeatedly until it is available. GET is written in code, and the
overhead rarely exceeds two or three machine instructions. Maintaining a queue is
almost always slower.
RELEASE checks to see whether a facility is free or is already owned by the task that
is executing RELEASE. If it is owned by the current task, RELEASE stores a zero into
the facility variable. If the facility is owned by another task, RELEASE does nothing.
Using the definition of FREE above, a high-level definition of RELEASE would be:
Note that GET and RELEASE can be used safely by any task at any time, as they don’t
let any task take a facility from another.
SwiftOS does not have any safeguards against deadlocks, in which two (or more)
tasks conflict because each wants a resource the other has. For example:
If 1HANG and 2HANG are run by different tasks, the tasks could eventually deadlock.
The best way to avoid deadlocks is to get them one at a time, if possible! If you
have to get two resources at the same time, it is safest to always request them in the
same order. In the multiplexor/tape case, the programmer could use A/D to obtain
one or more values stored in a buffer, then move them to tape. In almost all cases,
there is a simple way to avoid concurrent GETs. However, a poorly written applica-
tion might have the conflicting requests occur on different nesting levels, hiding the
problems until a conflict occurs.
Glossary
GET ( addr — )
Obtain control of the facility variable at addr, having first made one circuit of the
SwiftOS round robin. If the facility is owned by another task, the task executing GET
will wait until the facility is available.
GRAB ( addr — )
Obtain control of the facility variable at addr. If the facility is owned by another
task, the task executing GRAB will wait until the facility is available. GRAB does not
PAUSE before attempting to obtain control, so, in order to prevent deadlocks and
avoid “resource hogging,” it should be used only in circumstances in which it is
known that no other task could have the facility.
RELEASE ( addr — )
Relinquish the facility variable at addr. If the task executing RELEASE did not previ-
ously own the facility, this operation is a no-op.
Background tasks exhibit the general properties of all tasks in SwiftOS. In fact, ter-
minal tasks are supersets of background tasks, possessing extended user areas to
support the requirements for serial I/O.
Background tasks are suitable for virtually all chores that do not require serial I/O.
Examples include many kinds of equipment control and data acquisition.
This section describes procedures for defining and managing background tasks.
Background tasks have a data stack, a return stack, and a user area for variables
whose values are not shared (the user variables, discussed in Section 5.2.3). Back-
ground tasks do not service a terminal or support a compiler.
BACKGROUND creates a task definition table in initialized data space that is used, after
target power-up, to build a background task’s user area and stacks in RAM (see Fig-
ure 19). BACKGROUND is a defining word that expects the sizes (in bytes) of the user
area, data stack, and return stack. BACKGROUND does not link the task into the round
robin or make the task run a program; that will be described in the next section.
Host PC Target
User area
Return stack
Data stack
This defines a task whose name is SCRIBE, which has 32 bytes of user area, 128
bytes of data stack, and 64 bytes of return stack. The total target size of SCRIBE in
this example would be three cells (12 bytes on a 32-bit target, 6 bytes in a 16-bit tar-
get) in code space and 224 bytes of RAM. On a target with four bytes per cell, the 64-
byte return stack allows the program to nest Forth words, loop parameters, etc., to a
depth of 16 cells.
The smallest possible user area is the size of the region needed to keep the user
variables STATUS through CATCHER, about five cells (see Section 5.2.3). The extra cells
in SCRIBE’s user area could be used by its program to keep a sample count, a virtual
array address, and a device I/O address for a data-logging application.
There must be sufficient space to store the registers I (or the program counter, in
subroutine-threaded implementations) and R on the data stack, in addition to the
maximum number of stack items that may be present when the task enters the mul-
titasking loop (e.g., by executing PAUSE).
The run-time behavior of words created by BACKGROUND is to return on the stack the
address of the task’s definition table, the first cell of which contains a pointer to the
first byte of the task’s STATUS. Thus, the location of SCRIBE’s STATUS is found by the
phrase:
SCRIBE @
Glossary
BACKGROUND <task-name> ( nu ns nr — )
Define the background task task-name—with nu bytes of user area, ns bytes of data
stack and nr bytes of return stack—and set up its task definition table based on
these parameters. Subsequent use of task-name returns the address of the table
containing the parameters for building the task. The phrase <task-name> @ will
return the address of the task’s STATUS (the start of its user area).
<task-name> BUILD
is used to initialize task-name’s user area and to link it into the round robin. This
usually is done as part of the power-up sequence.
To initialize the task and link it into the round robin, one would use:
SCRIBE BUILD
SCRIBE leaves the address of its task definition table on the stack. Then BUILD
begins its work:
1. BUILD uses the address that is on the stack to set up the new task’s stack space and
user area in RAM.
2. BUILD copies the complete jump instruction, including the address of the next task,
from the STATUS of OPERATOR into the STATUS of the new task.
3. BUILD stores the address of the new task’s STATUS into OPERATOR’s jump address.
(Steps 2 and 3 enable the CPU to jump from OPERATOR to the new task, then to the
task which formerly followed OPERATOR in the round robin.)
4. BUILD gets a copy of the value for the new task’s S0—the bottom of its data stack,
calculated by BACKGROUND and compiled just after the STATUS address—and stores it
into the user variable S0.
At this point, although the task exists and is part of the round robin, it is not yet
running a program. The words the task executes may be defined later.
Glossary
BUILD ( addr — )
Initialize a task, given the address of the task’s definition table which was con-
structed by BACKGROUND. The task will be linked in the round-robin after OPERATOR,
and before the task previously linked to OPERATOR. This must be done at run time in
the target before any attempt to ACTIVATE the task. Usage:
<task-name> BUILD
OPERATOR ( — addr )
Return the address of the task definition table of the first task defined in any Swif-
tOS kernel. OPERATOR is a TERMINAL task. If no task has been defined, addr is OPERA-
TOR’s own STATUS.
After a task has been defined by BACKGROUND and linked into the round robin by
BUILD, the new task is “asleep.” This is necessary because the task still has not been
given the parameters that will determine what word(s) the task will execute.
The word that makes a task run a program is ACTIVATE, which must be used in a :
definition. It expects on the stack the address of a task definition table, placed
there by executing a task’s name. ACTIVATE clears the task’s data and return stacks,
then awakens the task such that it will begin executing the word immediately fol-
lowing ACTIVATE. The words following ACTIVATE must end in STOP or in an endless
loop.
SCRIBE RECORD
ACTIVATE uses the address returned by executing a task’s name ( SCRIBE, in this
example) to cause that task to execute the words following ACTIVATE. In the defini-
tion of RECORD,
Note that, in the above example, BUILD is kept separate from RECORD because a task
can only be built once, but can be activated many times.
For convenience in the discussion below, a slave task is ACTIVATEd by another task.
A master task uses ACTIVATE to activate the slave task. When the phrase SCRIBE
RECORD executes, ACTIVATE (in the definition of RECORD) will do the following:
1. Reset the slave task’s (SCRIBE, in the example) stacks to an empty state. If the slave
was previously active, it will forget what it was doing and its data and return stacks
will be cleared.
2. Store the address of the next word to be executed as the only item on the slave’s
return stack. In this case, that is the address of COLLECT, since BEGIN only acts at
compile time to set up the loop.
3. Push the slave’s return stack pointer (with one item on it) onto the slave’s data
stack, and save the data stack pointer in the slave’s user area until it begins execut-
ing.
4. Store a WAKE instruction into the slave’s STATUS cell.
Because the master task’s return stack was popped (in step 2, above), when it leaves
ACTIVATE it will return not to the next word in RECORD, but to whatever called RECORD.
In other words, the master task starts executing the word containing ACTIVATE, but
goes no further than that; the slave task is the only one that executes the balance of
the definition. This relationship is shown in Figure 20.
“Master” task executes this part “Slave” task executes this part
Code following an ACTIVATE must never reach the ; because the EXIT or RTS that is
compiled by a semicolon would attempt to pop an empty return stack. Therefore,
the code following an ACTIVATE must end either in an endless loop (as in the exam-
ple) or in the word STOP.
Here is another example of a control word, this time using the word STOP:
Note that ACTIVATE does not distinguish whether a task was previously assigned a
function that it is performing. In fact, after a task is ACTIVATEd the first time, it will
never be without a function to perform, even if that function is NOD. Nor is the con-
cept of “busy” relevant; the master task is running, or it couldn’t be executing ACTI-
VATE! So, if you want to avoid interrupting a task until it has finished performing an
assigned function, let the task set and clear a flag or variable to indicate when it is
busy or free for re-assignment. Facility variables (described in Section 5.2.4) are con-
venient for this purpose.
Glossary
ACTIVATE ( addr — )
Start the task at addr executing part of the definition in which ACTIVATE appears,
starting with the word following ACTIVATE. ACTIVATE may only be used inside a
colon definition. The task executing the balance of the definition must be pre-
vented from ever reaching the end of the definition (e.g., by STOP, NOD, or by being in
an infinite loop that describes its desired behavior).
NOD (—)
Infinite loop designed to ensure that a task remains inactive until ACTIVATEd to do
something else.
HALT ( addr — )
Cause the task at addr to perform NOD. Usage:
<task-name> HALT
A terminal task is a background task with additional user variables that enable it to
do serial I/O. Optionally, terminal tasks also may be given user variables to support
an interpreter.
The word TERMINAL allots memory to a terminal task and creates the task definition
table for a task that may control a serial port. The return stacks of all terminal
tasks in a single system have the same size, and space is allowed for input message
buffers and private dictionaries. Because terminal tasks can have a private diction-
ary, if the target system has an interpreter, they may have user variable space for
dictionary management, disk access, editing, and interpretation of text input (from
disk or keyboard); see Table 21 on page 109 for related details.
where n is size in bytes to be allotted to the task’s private dictionary (Section 7.1.2
discusses terminal tasks as they relate to the optional target-resident interpreter).
The sizes of individual stacks, user area, and buffers belonging to a terminal task
are configuration parameters, specified in Swiftx\Src\<CPU>\Config.f.
Besides allotting space, TERMINAL may also establish driver routines for the terminal
task. The exact method depends on the serial interface hardware; see your hard-
ware-specific SwiftX documentation for details.
A terminal task also has provision for device-specific words for various common
functions performed by serial devices. These correspond to certain of the terminal
Application Programming Interface (API) functions described in the Forth Program-
mer’s Handbook, Section 3.8, which often require device-specific definition. For
example, the control character sequence required for cursor positioning (AT-XY) var-
ies from one terminal to another, and cursor positioning may or may not be sup-
ported on a particular printer. SwiftOS provides for these by including execution
vectors for these functions in a terminal task’s user area. Each function supported
in this way has a vector and a standard name for a low-level, device- or task-specific
version of its behavior. These are summarized in Table 19.
Device-
API word Vector specific word Description
EMIT 'EMIT (EMIT) Display a character.
TYPE 'TYPE (TYPE) Display a string.
CR 'CR (CR) Go to next line (carriage-
return).
PAGE 'PAGE (PAGE) Go to next page (form-feed).
AT-XY 'AT-XY (AT-XY) Go to specified column/row.
KEY 'KEY (KEY) Await one key-press.
KEY? 'KEY? (KEY?) Check whether keypress
occurred.
ACCEPT 'ACCEPT (ACCEPT) Accept a string.
S0 will be copied to the task’s user variable area by CONSTRUCT. Consult your plat-
form documentation for the procedure for initializing the other vectors for your
target system.
builds the ROM table used to construct the task in RAM after power-up in the target
system.
Glossary
After a terminal task has been defined by the word TERMINAL, the terminal task must
be initialized by the use of the word CONSTRUCT, and then be made to run a program
by the use of ACTIVATE. CONSTRUCT is used for terminal tasks similarly to how BUILD
is used for background tasks.
Terminal task initialization consists of linking the task into the round robin and set-
ting the task’s user variables. The only remaining initialization required before a
task is running is to set up the task’s stacks, which will be performed by ACTIVATE
(described in Section 5.3.3).
The word CONSTRUCT must be executed after power-up in the target system. It per-
forms four separate functions:
1. It links the new terminal task into the round robin (using BUILD).
2. It copies non-device-dependent initialization from OPERATOR’s user variables to the
new task’s user variables.
3. It copies device-dependent data from the task definition table compiled by TERMINAL
into the user variable area of the new task. Typical device-dependent data includes
DEVICE and vectored routines for the terminal-specific functions described in Table
19.
4. If the target has an interpreter, it sets the task’s interpreter pointers.
After CONSTRUCT has been used, the task may be given a function to perform, as
described in Section 5.4.3.
Glossary
CONSTRUCT ( addr — )
Initialize a task, given the addr of its task definition table that was constructed by
TERMINAL. The task will be linked in the round-robin after OPERATOR and before the
task previously linked to OPERATOR. This must be done at run time in the target sys-
tem, before any attempt to ACTIVATE the task. Usage:
<task-name> CONSTRUCT
After a terminal task has been CONSTRUCTed, it may be made to run a program. This
is done by ACTIVATE, which controls TERMINAL tasks in the same way it controls
BACKGROUND tasks.
To demonstrate the SwiftOS multitasker at work, you may run the Conical Pile Cal-
culator demo (described in Section A.2) with a separate terminal task. To do this,
you will need to:
1. Follow directions accompanying your SwiftX product to connect the serial output
port on the demo board to a COM port on your computer that is not being used for
your XTL link.
2. Launch a terminal emulator (such as Terminal or HyperTerminal) on your PC, and
configure it for the COM port connected to your board.
3. Check that the following lines are included near the end of Debug.f:
INCLUDE ...\CONICAL
INCLUDE ...\DUMB
4. Launch SwiftX (if it is not already running) and initialize your target by using Project
> Debug.
5. Run the demo by typing DEMO in the SwiftX command window. If you have posi-
tioned your terminal emulator window so both it and the SwiftX window are visible,
you should see the application’s prompt in the terminal emulator window.
6. In the terminal emulator window, type any parameters you wish for the demo, as
described in Section 1.5.3.
Observe that your target system is responsive to demo program commands in the
terminal emulator window, and to normal XTL commands in the SwiftX command
window. In fact, you may run the demo from the command window, as well; but
you may find that the application is not re-entrant (see the discussions in Section
5.1 and Section 5.2.3), due to its use of variables. If you are feeling ambitious, you
might try defining those as user variables, and see if that helps!
Terminal tasks and background tasks are architecturally similar. In fact, a terminal
task is technically a superset of a background task. Terminal tasks differ in that
they have larger user areas to accommodate user variables related to servicing ter-
minals and other serial devices.
A SwiftX system includes libraries for the target system, all supplied in source form.
Depending upon the extent of a library, it may be found as an individual file or as a
directory. This differs from the method of providing libraries as linkable objects,
but it is generally more flexible, and is more consistent with Forth’s normal practice
of compiling directly from source to executable form without a link phase.
To add a library to your target, just include the relevant files in the main load file,
Kernel.f, prior to the line that includes the startup file Start.f.
Such a word could be put inside a loop, starting with a 0 “accumulator” on the stack
and, for each digit, multiplying the accumulator by 10 (assuming decimal) before
adding the next digit.
For more complex situations, SwiftX provides a more powerful set of number-con-
version words. For example, you may need to accept numbers with:
The word NUMBER? takes the address and length of a string, and attempts to convert
it until the length expires (in which case it is finished) or it encounters a character
that is neither a digit (0 to BASE-1) nor valid punctuation.
NUMBER? interprets any number containing one or more valid embedded punctuation
characters as a double-precision integer. Single-precision numbers are recognized
by their lack of punctuation. Conversions operate on character strings of the fol-
lowing format:
where dddd is one or more valid digits in the task’s current base (or radix). All
numeric strings must end with a blank or expiration of the length. If another char-
acter is encountered (i.e., a character which is neither a digit in that base nor punc-
tuation), conversion will end. There must be no spaces within the number, since a
Target Libraries 95
SwiftX Reference Manual
, . + - / :
All punctuation characters are functionally equivalent, causing the digits that follow
to be counted. This count may be used later by certain conversion words. The
punctuation character itself performs no function other than to set a flag indicating
its presence, and does not affect the resulting converted number.
1234.56
1,23.456
• If number conversion failed (i.e., a character was encountered that was neither a
digit nor a punctuation character), it returns the single value zero.
• If the number is single-precision (i.e., not punctuated), it returns a 1 on top of the
stack, with the converted value beneath.
• If the number is double-precision (i.e., contained at least one valid punctuation
character), it returns a 2 on top of the stack, with the converted value beneath.
The variable DPL is used to track punctuation during the conversion process. DPL is
initialized to a large negative value, and is incremented every time a digit is pro-
cessed. Whenever a punctuation character is detected, it is set to zero. Thus, the
value of DPL immediately following a number conversion indicates potentially use-
ful information:
This information may be used to scale a number with a variable number of decimal
places. Since DPL doesn’t care (or know) what punctuation character was used, it
works equally well with American decimal points and European commas to start the
fractional part of a number.
The word NUMBER is the high-level, input number-conversion routine used by SwiftX,
both in the host’s interpreter that processes source text and in the target kernels. It
performs number conversions explicitly from ASCII to binary, using the value in
BASE to determine which radix should be used. This word is a superset of NUMBER?.
NUMBER will attempt to convert the string to binary and, if successful, will leave the
result on the stack. Its rules for behavior in the conversion are similar to the rules
for NUMBER? except it always returns just the value (single or double). It is most use-
ful in situations in which you know (because of information relating to the applica-
tion) whether you will be expecting punctuated numbers. If the conversion fails due
96 Target Libraries
SwiftX Reference Manual
Glossary
NUMBER? ( c-addr u — 0 | n 1 | d 2 )
Attempt to convert the characters in the string at c-addr, whose length is u, into dig-
its, using the radix in BASE, until the length expires. If valid punctuation is encoun-
tered ( , . + - / : ), returns d and 2; if there is no punctuation, returns n and 1; if
conversion fails due to a character that is neither a digit nor punctuation, returns 0
(false).
NUMBER ( c-addr u — n | d )
Attempt to convert the characters in the string at c-addr, whose length is u, into dig-
its, using the radix in BASE, until the length expires. If valid punctuation is encoun-
tered ( , . + - / : ), returns d; if there is no punctuation, returns n; if conversion
fails due to a character that is neither a digit nor punctuation, a THROW will occur.
DPL ( — addr )
Return the address of a variable containing the punctuation state of the number
most recently converted by NUMBER? or NUMBER. If the value is negative, the number
was not punctuated. If it is non-negative, it represents the number of digits to the
right of the rightmost punctuation character.
NH ( — addr )
Return the address of a variable containing the high-order part of the number most
recently converted by NUMBER? or NUMBER.
The words in this section support a hardware time-of-day clock and calendar. On
targets without a built-in clock, you may enter a date and time, and SwiftX will
maintain it using an internal clock or programmable timer, if one is available. See
Target Libraries 97
SwiftX Reference Manual
your hardware-specific documentation for details. The accuracy with which this
can be done depends, of course, upon the resolution of the available clock hard-
ware.
SwiftX supports a calendar using the mm/dd/yyyy format. Some of the words
described below are intended primarily for internal use, whereas others provide
convenient ways to enter and display date and time-of-day information.
Dates are represented internally as the number of days since January 1, 1900, also
known as the modified Julian date (MJD). This is a simple, compact representation
that avoids the “Year 2000 problem,” because you can easily do arithmetic on the
integer value, while using the words described in this section for input and output
in various formats.
The range of dates that can be converted accurately by this algorithm is from March
1 1900 through February 28, 2100. Both of these are not leap years and are not
handled by this algorithm, which is good only for leap years that are divisible by
four with no remainder.
8/03/1940 M/D/Y
will present the double-precision integer 80340 to M/D/Y, which will convert it to the
MJD for August 3, 1940. This takes advantage of the enhanced SwiftX number-con-
version facility that automatically processes punctuated numbers as double-preci-
sion (see Section 6.1).
Normally, M/D/Y is included in the application user interface command that accepts
the date. For example:
98 Target Libraries
SwiftX Reference Manual
On most target platforms, you can set the system date by typing:
<mm/dd/yyyy> NOW
To obtain the day of the week from an MJD, simply take the number modulo 7; a
value of zero is Sunday. For example:
gives 6 (Saturday).
The alternative input form D/M/Y is also available (see “Date functions” on
page 100).
@NOW ( — ud n )
Return the system time as an unsigned, double number ud representing seconds
since midnight, and the system date as n days since 01/01/1900. Used (for exam-
ple) by TIME&DATE (see the Forth Programmer’s Handbook).
!NOW ( ud u — )
Take the same parameters as those returned by @NOW and set the system time and
date.
!TIME&DATE ( u1 u2 u3 u4 u5 u6 — )
Convert stack arguments u1 seconds (0–59), u2 minutes (0-59), u3 hours (0–23), u4
day (1–31), u5 month (1–12), u6 year (1900–2079) to internal form and store them as
the system date and time.
Time functions
@TIME ( — ud )
Return the system time as an unsigned, double number representing seconds since
midnight.
(TIME) ( ud — c-addr u )
Format the time ud as a string with the format hh:mm:ss, returning the address and
length of the string.
.TIME ( ud — )
Display the time ud in the format applied by (TIME) above.
TIME (—)
Display the current system time.
HOURS ( ud — )
Set the current system time to the value represented by ud, which was entered as
hh:mm:ss.
Target Libraries 99
SwiftX Reference Manual
Date functions
D/M/Y ( u1 u2 u3 — u4 )
Convert day u1, month u2, and year u3 into MJD u4.
M/D/Y ( ud — u )
Accept an unsigned, double-number date which was entered as mm/dd/yyyy, and
convert it to MJD.
@DATE (—u)
Return the current system date as an MJD.
(DATE) ( u1 — c-addr u2 )
Format the MJD u1 as a string with the format mm/dd/yyyy, returning the address
and length of the string.
.DATE (u—)
Display the MJD u in the format applied by (DATE) above.
DATE (—)
Display the current system date.
NOW ( ud — )
Set the current system date to the value represented by the unsigned, double num-
ber which was entered as mm/dd/yyyy.
SwiftX includes facilities to time events, for specifying when something will be
done, and for measuring how long something takes. These words are described in
the glossary below.
The word MS causes a task to suspend its operations for a specified number of milli-
seconds, during which time other tasks can run. For example, if an application
word SAMPLE records a sample, and you want it to record a specified number of sam-
ples, one every 100 ms., you could write a loop like this:
: SAMPLES ( n -- )
( n ) 0 DO \ Record n samples
SAMPLE 100 MS \ Take one sample, wait 100 ms
LOOP ;
Because MS is dependent upon the target system’s clock, the accuracy of the mea-
sured interval depends upon the resolution of that clock. As a general statement,
the error on an interval will be approximately the number of milliseconds in one
clock tick. If you need to respond more promptly to an external event, the best way
is to associate an interrupt directly with the event.
The words COUNTER and TIMER can be used together to measure the elapsed time
between two events. For example, if you wanted to measure the overhead caused by
Following a run of MEASURE, you can divide the time by 100,000 to get the time for
an average PAUSE. For maximum accuracy, you can run an empty loop (without
PAUSE) and measure the measurement overhead itself.
A formula you can use in Forth for computing the time of a single execution is:
where t is the time given by a word such as MEASURE, above, and n is the number of
iterations. This yields the number of 1/100ths of a millisecond per iteration (the
extra 100 is used to obtain greater precision).
The maximum clock error per iteration (in 1/100ths of a millisecond) may be calcu-
lated by:
where T/SEC is the number of clock interrupts per second (usually defined as an EQU
in the INTERPRETER scope on the host, and used to compile the timing definitions
discussed here), and n is the number of iterations, as above.
Glossary
MS (n—)
PAUSE the current task for n milliseconds. The accuracy of this interval is always
about one clock tick.
COUNTER (—u)
Return the low-order cell of the millisecond timer.
TIMER (u—)
Repeat COUNTER, then subtract the two values and display the interval between the
two in milliseconds.
EXPIRED ( u — flag )
Return true if the current millisecond timer reading has passed u. For example, the
following word will execute the hypothetical word TEST for u milliseconds:
References Time and timing functions, Forth Programmer’s Handbook, Section 3.7
6.2.3 Benchmarks
The file \Swiftx\Src\Bench.f contains a small suite of benchmarks, useful for com-
paring various targets. It is also a good example of how to time functions using the
tools described in Section 6.2.2. You may wish to apply similar techniques for mea-
suring time-critical application functions.
INCLUDE %SWIFTX\SRC\BENCH
You may then run the benchmarks by typing BENCH. The output displayed is a list of
words and the time each takes to execute on the target.
The first of these benchmarks measures the DO ... LOOP overhead associated with the
measurement process. The last, PAUSE, measures the time it takes for the multitask-
ing loop. The other tests in BENCH measure arithmetic function timings.
SwiftX provides a variety of arithmetic operators for use in applications. They are
designed to work efficiently on small microcomputer systems, trading extreme pre-
cision for size and speed. We recommend that you study the requirements of an
application carefully; the provided routines have nearly always been found ade-
quate when the limited precision of the associated I/O is properly taken into
account. Most analog I/O has a precision of 12 bits or less; rarely does it exceed 16
bits. Numeric I/O, in real-time applications typical of SwiftX projects, rarely needs
to be entered or displayed with any more precision than this.
The standard double-precision operations (64 bit, in this case) defined in the Forth
Programmer’s Handbook have all been included in SwiftX as separate files, so they
can be included or excluded, depending on the application. High-level words may
be found in SwiftX\Src\Double.f, while code primitives may be found in SwiftX\
Src\<cpu>\Double.f.
Fixed-point fractions are very simple and are widely applicable. In most cases, math
using them executes much faster than math using floating-point numbers—hence
their inherent desirability. As a basic starting point, this SwiftX includes 14-bit frac-
tions. These are convenient, because they have sufficient headroom in 16 bits to
exactly describe unity and, in fact, can almost reach two (handy for vector magni-
tudes, etc.); and they have sufficient precision for most applications.
For those who are unfamiliar with fractional arithmetic, a brief overview follows.
Fractional arithmetic involves scaling and an implied decimal point. Instead of scal-
ing by multiples of ten, as we do with decimal numbers (digits 0–9), we scale by
multiples of two, as you would expect with binary numbers (digits 0 and 1). The
implied decimal point is actually a binary point. We need to establish some sort of
convenient scale to represent the positive integer 1. For 14-bit fractions, we define:
16384 CONSTANT +1
0100000000000000
The one bit is scaled up in binary, along with the binary point, with 14 bits to its
right to represent the fraction. A number scaled in this way has a precision of one
part in 16384. If the number is used to represent a fraction of a circle (see below),
the angular resolution is about 0.022 degrees,
Addition and subtraction of fractional numbers is done with the usual + and - oper-
ators, but some way of multiplying and dividing is needed. The words *. and /.
perform this work. To assure ourselves that these operators really work, we can
divide 1 by 1, and get 1 (16384).
Readers who wish to learn more about fractional arithmetic should read the book
Starting Forth, which offers an excellent discussion of rational numbers and frac-
tional arithmetic.
Glossary
+1 (—n)
Return the value 1.00000000000000 (binary) in 14-bit fraction notation. There is an
implied binary point just after the second-most-significant bit.
*. (nf—n)
Multiply two numbers, one of which is a fraction, to return a whole number.
/. ( n1 n2 — f )
Divide n1 by n2 and return a fractional result. The divisor must be positive.
.F (f—)
Display a fraction with four decimal places.
6.3.3 Angles
Angles are hard to work with in conventional programming environments, for two
major reasons: they usually are expressed in radians, and they are realized as float-
ing-point numbers. This can be costly in both code and time, because many practi-
cal applications (such as encoders) work in revolutions, not radians; representation
in radians wastes a fractional bit, and the arithmetic to convert back to revolutions
adds time and computational noise.
6.3.4 Transcendentals
The most often needed transcendental routines are square root, trigonometric, and
log/exponential, usually in that order. With the exception of square root, we usu-
ally employ Chebyshev polynomial approximations and consider Hart, et al., to be
the definitive reference work. In the interest of providing reasonable standards,
most of our routines apply the highest-precision polynomial that fits within the pre-
cision of the data type. The nice thing about using Hart for a source is that you can
easily adjust the precision of the algorithm to match the required accuracy of the
calculation, often with a substantial reduction of execution time. (Remember that
few analog input or output devices exceed 12 or 16 bits of precision.)
References Hart, John F. et al., Computer Approximations, Krieger Publishing Co., Inc., P.O. Box
9542, Melbourne, FL 32902–9542, (305) 724-9542.
The basic square root algorithm has many uses and, with suitable prescaling, may
be used for any fixed-point data when a root accurate to 15 bits is sufficient.
A full set of 14-bit fractional trigonometric functions, along with some support
words, is supplied, as well as a test file that loads all the required arithmetic and
which contains some useful examples.
All trig functions that can go to infinity represent their potentially infinite values as
ratios. Only in rational form are such values manipulable and meaningful; more to
the point, the most common uses of these functions involve direction cosines for
rotations. By using this representation, we affirm the purposes of the functions and
maintain the utility of their results. Reduction of a ratio to a fraction, where
needed, is done by /.
Glossary
SIN (n—f)
Sine
COS (n—f)
Cosine
TAN ( n — f 1 f2 )
Tangent
COT ( n — f 1 f2 )
Cotangent
CSC ( n — f 1 f2 )
Cosecant
SEC ( n — f 1 f2 )
Secant
ASIN (f—n)
Arc-sine
ACOS (f—n)
Arc-cosine
ATAN ( n1 n2 — n3 )
Arc-tangent of the ratio n1/n2, giving n3.
DEG (n—f)
Converts an angle in degrees into a fraction representing part of a circle.
For example, 45 degrees is 1/8 of a circle. If you type:
45 DEG .
you should get 2048.
REV (f—n)
Converts a fractional angle into an integer with two implied decimal places.
<.5 ( f1 — f2 )
Converts an angle from a fraction in the range 0–360 degrees to the range
-180 – +180 degrees.
SwiftX Pro includes an optional target-resident interpreter and high-level Forth com-
piler to provide Forth services via a serial line to a terminal or terminal emulator
from the target. This facility supports:
This facility is far less powerful than the full SwiftX development environment. It
supports programming only to the extent of adding simple high-level Forth defini-
tions; no target-resident assembler is provided. For complex programming or
debugging chores, the SwiftX host remains the environment of choice.
The target-resident interpreter and compiler option is only available on targets with
sufficient resources (RAM, writable code space) to support it.
To include the target-resident interpreter in your target, you must edit the Config.f
file in your project directory such that the flag TARGET-INTERP is true:
-1 EQU TARGET-INTERP
There are some additional configuration issues, however. In order for your target
program to use the interpreter option:
• Some or all of your target definitions must have heads in order to be found from
the terminal. This is described in Section 7.1.1 below.
• The terminal task communicating with your serial port must be configured for addi-
tional user variables and sufficient memory for a private dictionary. This is
described in Section 7.1.2 below.
SwiftX normally compiles only executable code in its target program space, making
an extremely compact system. In order to use the interpreter option, however, at
least some definitions must have heads in order to make them accessible. There are
two ways to configure your SwiftX cross-compiler for this, depending upon your
needs:
1. Put heads on all words, but retaining the ability to specify certain words to be with-
out heads.
2. Omit heads except for the selected words you wish to make available.
Option 1 is appropriate if you wish most words in your target to be available for
Managing these options involves two words to set defaults, and two to over-ride the
current default for a single definition:
• +HEADS configures the cross-compiler to put heads on all words; | (vertical bar, pro-
nounced “bar”) causes the next target definition to be compiled without a head.
• -HEADS configures the cross-compiler to compile definitions without heads; ~ (tilde)
causes the next target definition to be compiled with a head.
Both the defaults and the overrides affect all SwiftX defining words operating in the
TARGET scope, constructed with : (colon), CODE, CREATE, VARIABLE, etc. It will not
affect EQU definitions, because they compile target literals rather than actual defini-
tions.
You may change your default at any time. Thus, you may have certain files com-
piled with the +HEADS setting and others with the -HEADS setting.
An override symbol must precede the defining word you wish it to affect. (Since
these are words themselves, they must be delimited by spaces.) For example, if you
are compiling with the -HEADS default set and wish to put a head on a word that dis-
plays a user menu, you might use:
~ : MENU ...
Similarly, if you are compiling with the +HEADS default and wish to specify no head
on a word containing a password, you might use:
or
Remember, only words compiled with heads may be accessed from the target’s
interpreter, either by users or by added definitions. All words remain available in
the cross-compiler’s TARGET scope.
Glossary
+HEADS (—)
Set the cross-compiler to put heads on all subsequent target definitions.
-HEADS (—)
Set the cross-compiler to omit heads on all subsequent target definitions.
~ (—)
Cause the next target definition to have a head, regardless of the current default.
| (—)
Cause the next target definition to have no head, regardless of the current default.
The interpreter and compiler are accessed through a terminal task attached to the
serial port through which interactivity will take place. All terminal tasks have the
ability to support serial-type I/O and, potentially, an interpreter and a private dic-
tionary. (Basic principles of defining and managing terminal tasks are described in
Section 5.4.)
where n is the size of its private dictionary. The dictionary size may be zero for
tasks with no private dictionary (such tasks may still use the interpreter, but may
not compile anything). The total amount of space used by the task is the sum of n
plus all the parameters listed in Table 21. The default sizes for these parameters on
your system may be found in \Src\<CPU>\Config.f.
Table 21: Parameters governing the space allocation for a terminal task
Typical size
Name Description (bytes)
|U| Maximum size of user area 256
|S| Maximum size of data stack 256
|R| Maximum size of return stack 256
|NUM| Space reserved for output number conver- 66
sions
|PAD| Space reserved for PAD (scratch string stor- 84
age)
|TIB| Terminal input buffer (TIB) 80
The task space will be allocated out of uData when the target program is compiled.
The target-resident compiler doesn’t have different memory sections.
The locations of the user area, return stack, and data stack are permanent, as is the
location of the start of the private dictionary (H0). However, PAD “floats” above the
current top of the dictionary (the location returned by HERE), at a distance given by
|NUM|. Therefore, if you put data at PAD and then extend your dictionary (by adding
definitions), PAD will have moved and that data will no longer be accessible.
A map of the various spaces in a terminal task area is shown in Figure 21. The
arrows show the direction of growth of the various resources. Since various of
these resources are configured to grow towards each other, they effectively share a
larger pool of space than is allocated for each individually. For example, if the
return stack is small (as it tends to be), a string longer than 80 bytes may be
accepted into the terminal input buffer. This greatly improves the overall use of
space and system reliability. However, if you know your application will regularly
require more space for any particular resource, you should adjust the default allo-
cations.
High memory
addresses |U| User area
U
Return
|R| Stack
|TIB| TIB
S0
Data
Stack
|S|
|PAD| PAD
PAD
Num
|NUM|
H
Private dictionary
H0
Low memory
addresses
The terminal task that is to run the interpreter should be initialized as part of the
start-up code in your target program. You will need to CONSTRUCT this task, as
described in Section 5.4.2. You must then connect it to its serial port, as described
in your CPU-specific documentation. Finally, if you wish its behavior to be that of a
normal Forth system (accepting and interpreting user input), you must assign this
behavior to it by using a definition such as:
A number of user variables are added to the SwiftX target in order to support the
interpreter. These are described in the following glossary, along with some related
words.
Glossary
BASE ( — addr )
Contains the current radix used for input and output number conversions.
H ( — addr )
Contains the address of the next available location in the user dictionary.
HERE ( — addr )
Returns the address of the next available location in the user dictionary (equivalent
to the H @ sequence).
H0 ( — addr )
Contains the address of the start of the user dictionary.
LAST ( — addr )
Contains the address of the start of the most recent definition.
STATE ( — addr )
Contains zero if the task is in interpret mode, non-zero if it’s compiling (i.e., inside
a colon definition).
TIB ( — addr )
Returns the address of the start of the terminal input buffer.
>IN (—n)
Returns the offset from the start of the TIB indicating the next bytes to be inter-
preted.
A number of the low-level components of the interpreter are available, and may be
useful on occasion. These are summarized in the glossary below.
INTERPRET uses WORD to parse the current input stream in a loop, and uses FIND to
search the dictionary for it. It will compile or execute each word, depending on
whether it is inside a colon definition, as indicated by a non-zero value in STATE. (A
flowchart of this process is provided in the Forth Programmer’s Handbook, Figure
5.) This continues until the input stream is exhausted.
This input stream is normally received by ACCEPT into the terminal input buffer. Its
parameters (address and length) are returned by SOURCE. The high-level word that
does this, including setting parameters as necessary, is QUERY.
Glossary
QUERY (—n)
Accepts a line of text into TIB and leaves its actual length in #TIB.
SOURCE ( — c-addr n )
Returns the address and length of the input buffer.
INTERPRET (—)
Attempts to execute, or convert to a number, each word found in the current input
buffer. Throws -4 if the stack underflowed as a result of executing a word.
• Assembler
• Word lists, or scopes
• Ability to add new data types or compiler directives
• Local storage for program source
• Other advanced programming features
Source may be transmitted to the target using a terminal emulator to send a text
file. The target can interpret such source a line at a time. It will acknowledge each
line as a line typed by a user, by replying “ok” followed by a CR. Therefore, you can
pace transmission by configuring your terminal emulator to wait for a CR before
The target-resident compiler can handle references to all words that were cross-
compiled with heads, as described in Section 7.1.1. You may type WORDS to see a list
of available words.
All compiling actions that increase the size of the dictionary will check the remain-
ing space, and will abort if there is not enough for the sum of the stack size, PAD,
and the number-conversion buffer.
This section presents some simple application examples to illustrate the process of
writing and testing SwiftX programs. Since this book is designed to be independent
of the particular board or processor you’re using, these examples will necessarily
omit detailed memory mapping and hardware considerations; refer to your plat-
form-specific documentation for those. However, these examples will illustrate
some important principles:
This is a simple example that illustrates some basic principles of application organi-
zation and design. We will also describe how you would actually go about develop-
ing and testing this simple program.
There are two basic aspects to this program: the control of the I/O (consisting of
six digital switches that control various components of the washing machine plus
the standard system timer), and the logic of the washing machine’s behavior. These
follow directly from the basic design.
The colon indicates that a new word is being defined; following it is the name of
that new word, WASHER. The remainder are the previously defined words that com-
Typically, we design the highest-level routines first. This approach leads to concep-
tually correct solutions with a minimum of effort. In Forth, words must be com-
piled before they can be referenced. Thus, a listing begins with the most primitive
definitions and ends with the highest-level words. If the higher-level words are
entered first, lower-level routines are added above them in the file.
The code in this example (given in Section A.1.3) is nearly self-documenting; the few
comments show the parameters being passed to certain words and identify groups
of words. Forth allows as many comments as desired, with no penalty in object code
size or performance.
When reading,
it is obvious what RINSE does. To determine how it does it, you read:
Reading further, one finds that FAUCET is simply a constant which returns the bit
mask for the port that controls the I/O, while ON is a simple word that turns on the
selected bit.
Even from this simple example, it may be clear that Forth is not so much a language,
as a tool for building application-oriented command sets. The definition of WASHER
is based not on low-level Forth words, but on washing-machine words like SPIN and
RINSE. By “factoring” the program into tiny components like this, you make your
program not only more readable, but also easier to test. And the components are
much more likely to be reusable: here, we use words like FILL-TUB, AGITATE, and
DRAIN several times, and the ON and OFF commands frequently.
When developing this program, you would follow your top-down logic, as described
above. But when the time comes to test it using SwiftX’s XTL, you see the real con-
venience of Forth’s interactivity.
This example assumes six digital switches, which are represented as individual bits
in an 8-bit control register. For simplicity, we assume this control register is mem-
ory mapped to a port address that we’ll show here as 01. Where such a port would
be in actual address space depends, of course, upon your CPU and other engineer-
ing and design decisions beyond the scope of this manual. Timing is done using the
standard SwiftX word MS (see Section 6.2.2), which is defined in terms of your sys-
tem clock; see your platform-specific documentation for details.
If your hardware is available, your first step would be to see if it works. Even with-
out writing a formal driver or application code, you can read and write the hardware
registers by typing phrases such as:
HEX 01 C@ .
This would read the port and display its value in hex, so you can see the individual
bits. You could do things to the hardware that would cause the bit values to change
(e.g., press a button or throw a switch) and see if the bit on the port does change
appropriately. You could write to the port, for example, by typing:
1 01 C!
and see if the motor turns on. In this way, you can verify that your hardware is con-
nected and functioning before you even write a line of code.
Program access to the I/O is provided by naming the port, and then defining various
bit masks that can be used to isolate individual switches on the port:
\ Port assignments
01 CONSTANT PORT
These definitions would be put at the beginning of your source file. Naming the
port and device bits in this way provides information hiding, which means, in this
case, that if the port or bit assignments change, all you have to do is modify these
definitions, and the rest of your code will run unchanged.
You can load your source file by using the command INCLUDE <filename>, where-
upon all its definitions are available for testing. You can further exercise your I/O
by typing phrases such as:
to see what happens. Then you can exercise your low-level words, such as:
DETERGENT ADD
As you work, you can use any of the additional programmer aids provided by
SwiftX. You can also easily change your code and re-load it. But your main ally is
the intrinsically interactive nature of Forth itself.
\ Device control
: ON ( mask -- ) PORT C@ OR PORT C! ;
: OFF ( mask -- ) INVERT PORT C@ AND PORT C! ;
\ Timing functions
: SECONDS ( n -- ) 0 ?DO 1000 MS LOOP ;
: MINUTES ( n -- ) 60 * SECONDS ;
\ Wash cycles
: WASH ( -- ) FILL-TUB DETERGENT ADD AGITATE DRAIN ;
: RINSE ( -- ) FILL-TUB AGITATE DRAIN ;
\ Top-level control
: WASHER ( -- ) WASH SPIN RINSE SPIN ;
The SwiftX source for this program is in the file SwiftX\Src\Conical.f. Instruc-
tions for running this demo application using the Cross-Target Link may be found
in Section 1.5.3. Instructions for running it on a separate serial port using a second
multiprogrammed task are given in Section 5.5.
This example is a math problem that many people would assume could be solved
only by using floating point. It will illustrate how to handle a fairly complicated
equation with fixed-point arithmetic, and will demonstrate that for all the advan-
tages of using fixed-point, range and precision need not suffer.
To make the example more “concrete,” let’s weigh several huge piles of sand, gravel,
and cement. The slope of each pile, called the angle of repose, depends on the type
of material. For example, sand piles more steeply than gravel.
(In reality, these values vary widely, depending on many factors; we have chosen
approximate angles and densities for purposes of illustration.)
Here is the formula for computing the weight of a conical pile h feet tall with an
angle of repose of Θ degrees, where D is the density of the material in pounds per
cubic foot:1
3
πh D
W = ------------------------
3 tan2 ( Θ )
Let’s design our application so that we can enter parameters to specify the material,
then the height of the pile, using single letters to identify the parameter. This will
be easy to support with a terminal emulator or the XTL, and in a real device, the sin-
gle letters could easily map to special function keys. So, we might enter 1M to select
the first material, 10F to specify 10 feet, and 6I for six inches. You can enter these
selections repeatedly, and then enter = to perform the calculations and get a result.
Let’s assume that for any one type of material, the density and angle of repose
never vary. We can store both of these values, for each type of material, into a table.
Since we ultimately need each angle’s tangent, rather than the number of degrees,
we will store the tangent. For instance, the angle of repose for a pile of cement is
35°, for which the tangent is .700. We will store this as the integer 700.
Bear in mind that our goal is not just to get an answer; we are programming a com-
puter or device to get the answer for us in the fastest, most efficient, and most
accurate way possible. To write equations using fixed-point arithmetic requires an
extra amount of thought. But the effort pays off in two ways:
1. Vastly improved run-time speed, which can be very important when there are millions
of steps involved in a single calculation, or when we must perform thousands of cal-
culations every minute. Also,
2. Program size, which would be critical if, for instance, we wanted to put this applica-
tion in a hand-held device specifically designed as a pile-measuring calculator.
Forth is often used in this type of instrument, for this very reason.
Let’s approach our problem by first considering scale. The height of our piles
ranges from 5 to 50 feet. By working out our equation for a pile of cement 50 feet
high, we find that the weight will be nearly 35,000,000 pounds.
However, because our piles will not be shaped as perfect cones, and because our
values are averages, we cannot expect better than four or five decimal places of
accuracy.1 If we scale our result to tons, we get about 17,500. This value will com-
fortably fit within the range of a 16-bit number. For this reason, let’s write this
application entirely with single-length arithmetic operators.
Applications that require greater accuracy can be written using double-length arith-
metic. But we intend to show the accuracy that Forth can achieve even with 16-bit
math.
By running another test with a pile 40 feet high, we find that a difference of one-
tenth of a foot in height can make a difference of 85 tons in weight! So we decide to
scale our input to tenths of a foot, not just whole feet.
15F 2I =
1.For Math Experts: In fact, since our height will be expressed in three digits, we can’t
expect greater than three-digit precision. For purposes of our example, however, we’ll keep
better than four-digit precision.
where the function keys F and I will cause the execution of words FOOT and INCH,
respectively, to convert the feet and inches into tenths of an inch, and = will execute
the word PILE to do the calculation. Here’s how we might define FOOT and INCH:1
(The use of INCH is optional.) Thus, 23 FOOT will put the number 230 on the stack; 15
FOOT 4 INCH will put 153 on the stack, and so on. We could as easily have designed
input to be in tenths of an inch, with a decimal point, like this:
15.2
In such a case, the number-conversion routine would convert the input as a double-
length value. Since we are only doing single-precision arithmetic, PILE could simply
begin with DROP, to eliminate the high-order part.
In writing the definition of PILE, we must try to maintain the maximum number of
places of precision without overflowing 15 bits. According to the formula on
page 119, the first thing we must do is cube the argument. But let’s remember that
we will have an argument that may be as high as 50 feet, which will be 500 as a
scaled integer. Even to square 500 produces 250,000, which exceeds the capacity of
a single-precision number on a 16-bit system.
We might reason that, sooner or later in this calculation, we’re going to have to
divide by 2000 to yield an answer in tons. Thus, the phrase:
will square the argument and convert it to tons at the same time, taking advantage
of */’s double-length intermediate result. Using 500 as our test argument, the
above phrase will yield 125.
However, our pile may be as small as 5 feet, which when squared is only 25. To
divide by 2000 would produce a zero in integer arithmetic, which suggests that we
are scaling down too much.
DUP DUP 10 */
The integer result at this stage will be scaled to one place to the right of the decimal
point (25000 for 2500.0).
Now we must cube the argument. Once again, straight multiplication will produce a
double-length result, so we must use */ to scale down. We find that by using 1000
as our division, we can stay just within single-length range. Our result at this stage
1.In fact, the definitions in the file that ships with SwiftX are slightly more complicated, in
order to provide error checking and some user feedback.
will be scaled to one place to the left of the decimal point (12500 for 125000), and is
still accurate to five digits.
355 113 */
But we must also divide our argument by 3; we can do both at once with the phrase:
355 339 */
Next, we must divide our argument by the tangent squared, which we can do by
dividing the argument by the tangent twice. Because our tangent is scaled to 3 dec-
imal places, to divide by the tangent we multiply by 1000 and divide by the table
value. Thus, we will use the phrase:
1000 THETA @ */
Since we must perform this twice, let’s make it a definition, called /TAN (for “divide
by the tangent”) and use the word /TAN twice in our definition of PILE. Our result at
this point will still be scaled to one place to the left of the decimal (26711 for
267110, using our maximum test values).
All that remains is to multiply by the density of the material, of which the highest is
131 pounds per cubic foot. To avoid overflowing, let’s try scaling down by two dec-
imal places with the phrase:
DENSITY @ 100 */
By testing, we find that the result at this point for a 50-foot pile of cement will be
34,991, which just exceeds the 15-bit limit. Now is a good time to take the 2000
(pounds per ton) into account. Instead of:
DENSITY @ 100 */
we can say:
DENSITY @ 200 */
In Pounds In Tons
This application supports six different materials: cement, loose gravel, packed
gravel, dry sand, wet sand, and clay. Each material has a characteristic density and
theta, and a string to identify it for the user. This is an excellent example of an
occasion where Forth’s ability to define special data types1 comes in handy. The
defining word MATERIAL (see the file SwiftX\Src\Conical.f) can be used to define
each material:
\ Density Theta
131 700 MATERIAL CEMENT"Cement"
93 649 MATERIAL LOOSE-GRAVEL"Loose
gravel"
100 700 MATERIAL PACKED-GRAVEL"Packed
gravel"
90 754 MATERIAL DRY-SAND"Dry sand"
118 900 MATERIAL WET-SAND"Wet sand"
120 727 MATERIAL CLAY"Clay"
Each of the words defined by MATERIAL (CEMENT, etc.) will, when executed, store its
density and theta in the variables DENSITY and THETA used for the calculation, and
will put the address of the descriptive string in the variable MATTER.
A numeric parameter in the range 0–5 can be used to index into this table, and then
EXECUTE the selected xt. This is done by the word SELECT:
The highest level of the program is a loop called CALCULATE. It processes the input.
When feet and inches are entered, that value is accumulated in the variable ACCM,
which is then given as a parameter to PILE.
1.See the Forth Programmer’s Handbook, Section 2.7, and this manual, Section 4.7.
CALCULATE begins by clearing ACCM, displaying directions, and setting the default
material to CEMENT. It then enters an infinite loop in which it solicits user input and
then acts on it. Pressing ‘M’ selects the material, ‘F’ and ‘I’ set feet and inches, ‘=’
performs the actual calculation, and the Escape key exits the loop.
: CALCULATE ( -- )
0 ACCM ! .DIRECTIONS CEMENT
BEGIN #INPUT CASE
[CHAR] M OF SELECT ENDOF
[CHAR] F OF FOOT ACCM ! ENDOF
[CHAR] I OF ACCM @ SWAP INCH ACCM ! ENDOF
NIP [CHAR] = OF ACCM @ PILE 0 ACCM ! ENDOF
$1B ( Esc) OF EXIT ENDOF
ENDCASE AGAIN ;
We recommend that you read the full source for this application in the file SwiftX\
Src\Conical.f, as it provides a good example of how a program may be constructed.
As with the Washing Machine example (Section A.1), we develop and test the pro-
gram incrementally.
First, we would test the computational words by storing various values in the vari-
ables DENSITY, THETA, and ACCM, and by executing PILE with various heights. Remem-
ber that if you’re connected to your target, you can fetch and store its variables
from the keyboard, by typing phrases such as:
Next, we would construct the list of materials, and test the defining word MATERIAL
by, for example, typing 1 SELECT and then examining the values in the variables to
verify that the correct values were stored and that the behavior assigned to the new
words by MATERIAL is what you intended.
You can look at the user directions by typing .DIRECTIONS. You can adjust the mes-
sage, spacing, etc., as much as you like until you get a pleasing display.
Finally, when you are confident that the low-level components of your program are
working, you may type CALCULATE. If one of its components fails to work, you can
exercise it individually from the keyboard. For example, if you seem to be getting
the wrong material, you might type:
and see if you get the string Loose gravel. Or, if you’re getting wrong answers, you
might try:
and compare the result you get with results from a pocket calculator. Check the
values stores in DENSITY and THETA to be sure they were set properly. If they aren’t,
your problem may be with SELECT; if they are, check your computational definitions
again by executing their components.
This style of informal, interactive testing usually gets results much more quickly
than steppers, breakpoints, etc.
This section provides an alphabetical index to the Forth words that appear in the
glossaries in this book. Each word is shown with its stack arguments and with a
page number where you may find more information. If you’re viewing the PDF ver-
sion of this document, you can click on the Forth word name to go to its glossary
definition.
The stack-argument notation is described in Table 23. Where several arguments are
of the same type, and clarity demands that they be distinguished, numeric subscripts
are used.
Notation Description
a-addr A cell-wide byte address that is cell-aligned (i.e., the address is
evenly divisible by the cell size in bytes).
c-addr A cell-wide byte address that is character-aligned (because a
character is always one byte on current systems, this amounts to
an arbitrary
byte address).
addr A cell-wide byte address.
b A byte, stored as the least-significant 8 bits of a stack entry. The
remaining bits of the stack entry are zero in results or are
ignored in arguments.
c An ASCII character, stored as a byte (see above) with the parity
bit reset to zero.
d A double-precision, signed, 2’s complement integer, stored as
two stack entries (least-significant cell underneath the most-sig-
nificant cell).
On 16-bit machines, the range is from -2**31 through +2**31-1.
On 32-bit machines, the range is from -2**63 through +2**63-1.
flag A single-precision Boolean truth flag
(zero means false, non-zero means true).
i*x, j*x, etc. Zero or more cells of unspecified data type.
n A signed, single-precision, 2’s complement number. On 16-bit
machines, the range is from -2**15 through +2**15-1. On 32-bit
machines, the range is from -2**31 through +2**31-1. (Note that
Forth arithmetic rarely checks for integer overflow.) If a stack
comment is shown as n, u is also implied unless specifically
stated otherwise (e.g., + may be used to add either signed or
unsigned numbers). If there is more than one input argument,
signed and unsigned types may not be mixed.
Notation Description
+n A single-precision, unsigned number with the same positive
range as n above. An input stack argument shown as +n must
not be negative.
u A single-precision, unsigned number with a range from 0 to
2**16-1 on
16-bit machines, or 0 through 2**32-1 on 32-bit machines.
ud A double-precision, unsigned integer with a range from 0 to
2**32 on
16-bit machines, or 0 through 2**64-1 on 32-bit machines.
x A cell (single stack item), otherwise unspecified
xt Execution token. This is a value that identifies the execution
behavior of a definition. When this value is passed to EXECUTE,
the definition’s execution behavior is performed.
This installation procedure applies only to the P&E USB MultiLink BDM. The parallel
port (LPT) connected BDM does not require any additional driver installation and is
ready to use.
All necessary driver components for the P&E USB Multilink (USB-ML) BDM modules
are installed by the SwiftX installer.
Be sure to install SwiftX before connecting a USB-ML BDM module. Any P&E branded
driver CD-ROM that came with the BDM module is not needed.
After SwiftX has been installed, connect the USB-ML to a USB port on your com-
puter. This should launch the Found New Hardware Wizard.
3. Finish.
Each new USB-ML that you connect to the system (uniquely identified to the system
by its serial number) will follow this same procedure.
APPENDIX D: BIBLIOGRAPHY
Recommended Books
Introductory
Rather, E.D., et al. Forth Application Techniques. ISBN 0–9662156–1–3. FORTH, Inc. Los Angeles,
CA 90250-6694.
Rather, E.D. and Conklin, E.K. Forth Programmer’s Handbook. ISBN 0–9662156–0–5. FORTH, Inc.
Los Angeles, CA 90250-6694.
Advanced
American National Standard for Information Systems: Programming Language Forth (ANSI
X3.215–1994). American National Standards Institute, 11 W. 42nd St., New York, NY
10036, (212) 642-4900.
Koopman, P. Stack Computers, The New Wave. Downloadable from:
http://www.cs.cmu.edu/~koopman/stack_computers/.
Noble, J.V. Scientific Forth. Charlottesville, VA: Mechum Banks Publishing, 1992.
Other Publications
Bailey, G., Sanderson, D., Rather, E. “clusterFORTH, A High-Level Network Protocol,” Proceedings
of the 1984 FORTH Conference. Rochester, NY: The Institute for Applied Forth Re-
search, 1984.
Brodie, L. Starting Forth, Englewood Cliffs, NJ: Prentice-Hall, 1981, 2nd ed. 1987. Contact: Forth
Interest Group (www.forth.org).
Brodie, L. Thinking Forth, Englewood Cliffs, NJ: Prentice-Hall, 1984. Reprinted 1994 by the Forth
Interest Group (www.forth.org).
Kelly, M.G., and Spies, N. Forth: A Text and Reference. Englewood Cliffs, NJ: Prentice-Hall, 1986.
Martin, T. A Bibliography of Forth References, 3rd ed. Rochester, NY: Institute for Applied Forth
Research, 1987.
Moore, C.W. “The Evolution of Forth — An Unusual Language,” Byte, August 1980.
Pountain, R. Object Oriented Forth. New York: Academic Press, 1987.
Rather, E.D. “Forth Programming Language” Encyclopedia of Physical Science & Technology (V. 5)
Academic Press, Inc., 1987, 1992.
Rather, E.D. “Fifteen Programmers, 400 Computers, 36,000 Sensors and Forth,” Journal of Forth
Application and Research (V. 3, #2, 1985), P.O. Box 27686, Rochester, NY 14627.
Rather, E.D., Colburn, D.R., and Moore, C.W. “The Evolution of Forth,” ACM SIGPLAN Notices, Vol.
Bibliography 137
SwiftX Reference Manual
138 Bibliography
SwiftForth Reference Manual
Index
A abort 25
align
an address 51
section allocation pointer 51
angles 104
App.f 45
arithmetic precision 102
assembler 20
assembly language
decompiled 34
B background tasks 84
BASE
host vs. target 47
base (See number conversion)
benchmarks 102
BUILD 30
bye
menu equivalent 25
Index 139
SwiftForth Reference Manual
select font 27
status bar 22
comments
multi-line 41
compile
for PROM 30
for testing 30
compiler 20
control of file loading 39
error recovery 32
principles 56
search orders (See scopes)
target-resident interpreter option 107, 112–113
conditional compilation 48
configuration
of interface 27
save 28
copy
by right clicking 24
CREATE … DOES>, instances of 61
section type 62
cross-reference
generate by right clicking 23
Cross-Target Link (XTL) 20, 66
D DASM 34
data logging 71
data objects
custom 61–64
in iData 61
in uData 61
day of the week, from MJD 99
DEBUG 30
debug tools 30
disassembler/decompiler 34
LOCATE 31
memory dump 34
defining words 52–54, 56, 63
and section type 62
custom
example 63
demo program 15
how to run 16
multitasking version 92
dictionary
in target (with interpreter option) 107–109
private (with interpreter option) 109
directory paths (See path names)
directory paths, relative 40
disassemble
by right clicking 23
disassembler/decompiler 34
DOES> in cross-compiling 62
double-precision number 95
double-precision operations 102
140 Index
SwiftForth Reference Manual
E editor 33
invoke by right clicking 23
select and configure 27
error handling (See exceptions)
exceptions
manual abort 25
execute
by right clicking 23
F facility variables 83
File menu 25, 36
filenames
extension 39
determines object format 64–66
files
batch downloading 67
loading 25, 39–41, 42–43
INCLUDE vs. menu options 40
monitor 42–43
use with interpreter option 112
find
in source code ??–33, ??–33
find a word
in compiled code 33
in source 31–??
fixed-point fractions 102
font 27
H Help menu 30
hex format object file 64
history 35
command window 22
of user commands 22
I iData 51
and object files 65
INCLUDE 17
diagnostic features 27
menu equivalent 25
monitor progress 42
vs. menu/toolbar 39
initialization, target 44–46
input stream
interpreting 111
Intel HEX format 65
interactive development 36
interpreter option
case sensitive 111
configuring 49
requirements for use 107
L LABEL 34
library
adding to target 95
Index 141
SwiftForth Reference Manual
LOCATE 31, 34
by right clicking 23
log
entire session 25
session activity 36
typed commands 25
LOGGING flag 40
M memory
access 54–55
and target connection 66
configuring 49
and interpreter option 110
overview 20, 49–??
See also sections
menu
File 25, 36
Help 30
Options 26
Project 30
Tools 29
messages
system 27
modified Julian date (MJD) 98
Motorola S19 format 65
multitasker (see round-robin algorithm)
N New Project 25
“Non-existent file” 23
NUMBER 96
number conversion 47–48, 95
BASE affected by INCLUDE 40
NUMBER? 95
numbers
compiling vs. interpreting 47
negative 47
P paste
by right clicking 24
path names
absolute vs. relative 39–40
and including files 39
spaces not allowed 40
PAUSE, detailed analysis 76
polynomial approximations 104
POWER-UP 45
print 25
project 30
project directory 40
Project menu 30
142 Index
SwiftForth Reference Manual
PROM
build object file 66
create object file 64
punctuation
in numbers 96
R re-entrancy, in Forth 73
resource sharing 82
round-robin algorithm 74
RUN 29
T terminal tasks 89
private dictionary 109
user area (with interpreter option) 109
Index 143
SwiftForth Reference Manual
U uData 51
access requires connection 54, 66
user variables 78
added for interpreter option 110
144 Index