On Chuck Moore's colorForth
Nov. 11, 2002
Real programmers write Forth kernels in assembler and CAD packages in Forth.
The former in 6600 bytes of object code and the latter in about 4000 32-bit
words of object code.
How does he do that?
First some basic metrics. The word interpreter is 24 bytes and 'find' loop is
35 bytes. colorForth has a kernel that takes up 11kb but is only comprised of
6600 bytes of object code. This includes the colorForth kernel, user and
graphics interface. The rest is dictionary expansion room for approx. 640 new
definitions (128 for MACRO, 512 for FORTH). That leaves about 1000 bytes for
kernel extensions (MACROs for basic operations). Application code will need to
point 'here' after block 162 decimal or address A200h.
Blocks are 256 bytes long and start at block 24 (address 3000h, 12298 decimal)
where the default warm start loads from. Code/dictionary go below that. Stacks
are at 0A0000h.
colorForth is a simple multi-tasker that uses two tasks: 'god' (graphic ouput
display) and 'main' (usually 'keyboard').'main' switches to 'god' while
waiting for 'key' input. 'god' updates the video display every time that it is
switched to. 'switch' (called within god) copies the output image at 'frame'
to the AGP video memory at 'displ'.
According to Chuck's web site, OKAD is written in about 500 lines of code.
c.f.: http://colorforth.com/vlsi.html
Examining his other colorForth code on display at:
http://www.merlintec.com/download/color.html
a nominal length for a line of code is about 8 words. So OKAD is nominally
4000 words or 16kb of source code. Compiled object code will be about the
same order of size including dictionary overhead (data arrays not included).
And I do mean 'words'. colorForth is written around the concept of a 'word',
i.e. a 32 bit word. Numbers and strings are all multiples of 32 bit words.
Numbers are retained in a binary format with four bits of color type and a
hex/decimal bit flag, single precision number 'words' are retained as signed
27 bit binary values.
Alpha-numeric strings are comprised of 4 bits of color information with the
remaining 28 bits available for packed Huffman character encoded strings.
Input is a word at a time, either an alpha-numeric string or a number.
Color is intrinsic to the individual 32-bit words. colorForth is not line
oriented, it is _word_ oriented.
The Huffman coding was chosen to optimally encode the strings used in the
dictionary names peculiar to colorForth and OKAD into the most compact form.
(Write a different app with different names and you may want to re-cast the
Huffman encoding for your apps character frequencies.)
Numeric variables are maintained in their block location. see:
http://colorforth.com/parsed.html
Looking at the colorForth user interface, it is evident that it was designed
by and for Chuck's specific way of thinking and coding. It enforces a word
model as the basic unit of colorForth syntax.
The user interface first selects a color, which then specifies an input
method. For basic input, each word is executed/enstacked at the inception of
the next command.
The block editor changes from execute/enstack to insert/delete, otherwise the
input methods remain the same.
Back to the original question: How does he do that?
First, learn _all_ the CPU opcodes, not just the commonly used ones. Chuck's
code uses opcodes that don't appear in dis-assembly of compiler output.
Secondly, learn the characteristics of the hardware platform. Do prototyping
to figure out how to do straigtforward operations. Other peoples code (OPC)
will have a bias for their goals, not yours. OPC will also usually have
irrelevant generalities. Map your required functions to the hardware.
Third, keep the user interface to the bare minimum. This is the most expensive
part of code. (I recently did a vertical scrollbar in C. The basic
functionality took 644 bytes of object code. The finished version that
_looked_ good with 3D outlines, but provided no extra functionality, took over
1300 bytes of code.) colorForth uses about 600 bytes for the basic input,
number conversion and Huffman word packing. Chuck mentions that the basic
kernel is less than 2k, so the rest (4.5k) goes into the user interface and
CAD capable graphics.
Finally, Chuck talks about moving everything closer to the front of the
development effort: run-time to compile-time, compile-time to edit-time,
edit-time to design time. Do the design up front and code entry/debugging is
only 10% of the development effort.
To sum it up:
1. Know your tools, hardware and software, inside out.
2. Keep the user interface as simple as possible.
3. Prototype first, design second and code last.
Chuck has been designing colorForth for 20 years. It has been a process of
elimination as well as invention. The whole point of colorForth is to
implement OKAD in a manner usable to Chuck for the purpose of designing the
X18 stack processor and similar designs. colorForth was designed as a specific
purpose programming language rather than general purpose. This goes a long way
towards explaining why colorForth seems so hostile to collaborative
programming. It was explicitly created as the requisite base for OKAD.
The rigor with which colorForth and OKAD were created are on the same order
as that of G. Spencer Brown's "The Laws of Form" or Whitehead and Russel's
"Principia Mathematica". Consider it a logical proof of fitting a VLSI CAD
design package into about 25kb along with an open-ended programming language.
Comparing anyone elses code to colorForth/OKAD without taking the years of
design refinement into consideration is unjust. And expecting to be able to
create new colorForth software platforms that are as elegant is just plain
silly. The ruthless, brutal design methodology that is colorForth is a true
'Zen of Computing' and can take years to acquire. YMMV.
Return to colorForth index