This guide tells you about the gory details you need to know to
create or maintain a port of Collapse OS. This is some pretty
hairy stuff and you should have read doc/usage, doc/impl and
doc/cross first. Is is also recommended that you use the z80
port (arch/z80/blk.fs) as a reference as you read this guide.
What is Collapse OS? It is a binary placed either in ROM on
in RAM by a bootloader. That binary, when executed, initializes
itself to a Forth interpreter. In most cases, that Forth
interpreter will have some access to a mass storage device,
which allows it to access Collapse OS' disk blocks and bootstrap
itself some more.
This binary can be separated in 5 distinct layers:
1. Arch-specific boot code (B302 for Z80)
2. Arch-specific words (B303 for Z80)
3. Arch-independant core words (low) (B210)
4. Drivers, might contain arch-specific code
5. Arch-independant core words (high) (B225)
The boot code, which is arch-specific, contains these elements:
1. Early initialization code, which initializes RSP and PSP and
then jumps to BOOT.
2. Core routines. Set lblnext, lblxt, lblcell, lblval and
Then come the implementation of core Forth words in native
assembly. This is a limited set of words that implement core
QUIT ABORT EXIT BYE RCNT SCNT * /MOD TICKS (b) (n) (br) (?br)
(next) C@ @ C! ! AND OR XOR NOT + - R> >R R~ DUP ?DUP DROP SWAP
OVER ROT EXECUTE
If your arch's native absolute jumps and calls aren't in the
form "1b opcode + 2b addr", you also need to implement a native
version of JMPi! and CALLi!. Otherwise, the forth layer will
On CPUs having I/O ports, PC! and PC@ are also needed.
This is the absolute minimum set of words that a port needs to
be functional. If it only implements those words, however, it's
going to be very slow.
Some forth core words are defined with "?:" instead of ":". If
those words are part of the native words, they're going to be
used instead of their forth version and will result in a much
Core words (low)
Then comes the part where we begin defining words in Forth.
Core words are designed to be cross-compiled, from a full Forth
interpreter. This means that it has access to more than boot
words. This comes with tricky limitations. See doc/cross.
Core words don't include (key?) and (emit) implementations be-
cause that's hardware-dependant. This is where we need to load
code that implement it, as well as any other driver code we want
to include in the binary. This includes subsystems.
We do it now because if we wait until the high layer of core
words is loaded, we'll have messed up immediates and ":" will
be broken. If we load our code before, we won't have access to
a wide vocabulary.
See doc/drivers for more details.
Core words (high)
The final layer of core words contains the BOOT word as well
as tricky immediates which, if they're defined sooner, mess
cross compilation up. Once this layer is loaded, we become
severly limited in the words we can use without messing up.
Forward labels (BOOT, main and HERE)
Because Collapse OS assemblers have limited support for forward
labels, we organize the code in order to avoid it. When
compiling Collapse OS, however, there are some cases where we
reference an address without knowing it yet. These are:
1. The initial jump to BOOT
2. The jump to the "main" (see doc/impl) routine in QUIT.
3. Initial values for HERE and CURRENT.
The XCOMPC program declares 3 labels, lblboot, lblmain and
lblhere where address of these forward references must be
written (in PC value, like any label, *not* host address).
Core words manage the lblhere references by itself, arch-
specific ports don't need to do anything about it. However, it
needs to set lblhere and lblmain at the exact PC where the
address of the corresponding routines will be written when
they're created. You can look at the z80 port for examples.
So that's the anatomy of a Collapse OS binary. How do you build
one? If your machine is already covered by a recipe, you're in
luck: follow instructions.
If you're deploying to a new machine, you'll have to write a
new xcomp (cross compilation) unit. Let's look at its
anatomy. First, we have constants. Some of them are device-
specific, but some of them are always there. SYSVARS is the
address at which the RAM starts on the system. System variables
will go there and use $80 bytes. See doc/impl.
HERESTART determines where... HERE is at startup. 0 means
"same as CURRENT".
You will likely need more constants than that, but this depends
on your architecture and drivers.
Then comes time time to load the blocks that will compile the
thing. Order is important.
First come XCOMP followed by the assembler (example, Z80A). Then
comes CPU-specific macros, constants further loader words such
as the "C" units. They always live in B301 (see doc/blk). The
loader word for this is ARCHM. It's important that it's loaded
before XCOMPC because it's being executed during xcomp, not
included in the target binary.
Now comes the real deal: XCOMPC. It's the "forth" part of xcomp
and from this point on, we're in "target" mode. Everything we
define ends up in the target binary (see doc/cross).
The first unit that comes after this is the "C" unit (example:
Z80C). "C" is for "code". It's the layers 1 and 2 from the layer
list at the top of this document.
We're done with the CPU-specific part! Now comes COREL, for
"core words (low)".
Then comes the custom part: drivers and subsystems. This part
is heavily dependant on the target system and varies a lot.
After that, you need to define a INIT word. This will be called
by BOOT right before spitting the prompt. This is usually used
to call init words of all subsystems.
All xcomp unit end with XWRAP, a helper word that loads "high"
core words and then wrap things up (set CURRENT and LATEST in
the stable ABI). You're done!
To produce a Collapse OS binary, you run that xcomp unit and
then observe the values of XORG and HERE. That will give you
the start and stop offset of your binary, which you can then
copy to your target media.
This page generated at 2023-12-05 21:05:04 from documentation in CollapseOS snapshot 20230427.