45eceaaf61
I got bitten again, I've over-designed my solution. The last time it happened, it was that memory mapping thing I was wanting to add. The indirect memory access feature I was adding was to solve a specific problem: Allow Collapse OS to cross-compile directly on a AT28 EEPROM. It began well. As long as we were staying in the assembler realm, things were looking good. However, when we got into the xcomp realm (B260), things became ugly, and I had to creep up indirection where I didn't want to. All of this because I wanted to solve my initial problem in a slightly more generalized way. The broad idea was that these indirect memory access could allow xcomp into a broad kind of memory-like devices. This idea broke on the "@" part of the equation. If I want indirections to be two-way and allow xcomp to work properly, I have to add this indirection to FIND (and possibly others) and this just isn't practical or elegant. So, I'm taking a step back and accepting that the solution I design for now is exclusively for the AT28. What I'm thinking is to add a low-level hook for memory writing, at the assembly level.
141 lines
5.4 KiB
Plaintext
141 lines
5.4 KiB
Plaintext
# Collapse OS usage guide
|
|
|
|
If you already know Forth, start here. Otherwise, read primer
|
|
first.
|
|
|
|
We begin with a few oddities in Collapse OS compared to tradi-
|
|
tional forths, then cover higher level operations.
|
|
|
|
# Signed-ness
|
|
|
|
For simplicity purposes, numbers are generally considered
|
|
unsigned. For convenience, decimal parsing and formatting
|
|
support the "-" prefix, but under the hood, it's all unsigned.
|
|
|
|
This leads to some oddities. For example, "-1 0 <" is false.
|
|
To compare whether something is negative, use the "0<" word
|
|
which is the equivalent to "0x7fff >".
|
|
|
|
# Branching
|
|
|
|
Branching in Collapse OS is limited to 8-bit. This represents
|
|
64 word references forward or backward. While this might seem
|
|
a bit tight at first, having this limit saves us a non-
|
|
negligible amount of resource usage.
|
|
|
|
The reasoning behind this intentional limit is that huge
|
|
branches are generally an indicator that a logic ought to be
|
|
simplified. So here's one more constraint for you to help you
|
|
towards simplicity.
|
|
|
|
# Interpreter I/O
|
|
|
|
The INTERPRET loop, the heart of Collapse OS, feeds itself
|
|
from the C< word, which yields a character every time it is
|
|
called. If no character is available to interpret, it blocks.
|
|
|
|
During normal operations, C< is simply a buffered layer over
|
|
KEY, which has the same behavior (but unbuffered). Before
|
|
yielding any character, the C< routine fetches a whole line
|
|
from KEY, puts it in a buffer, then yields the buffered line,
|
|
one character at a time.
|
|
|
|
Both C< and KEY can be overridden by setting an alternate
|
|
routine at the proper RAM offset (see impl.txt). For example,
|
|
C< overrides are used during LOAD so that input comes from disk
|
|
blocks instead of keyboard.
|
|
|
|
KEY overrides can be used to, for example, temporarily give
|
|
prompt control to a RS-232 device instead of the keyboard.
|
|
|
|
Interpreter output is unbuffered and only has EMIT. This
|
|
word can also be overriden, mostly as a companion to the
|
|
raison d'etre of your KEY override.
|
|
|
|
# Aliases
|
|
|
|
A common pattern in Forth is to add an indirection layer with
|
|
a pointer word. For example, if you have a word "FOO" for
|
|
which you would like to add an indirection layer, you would
|
|
rename "FOO" to "_FOO", add a variable "FOO*" pointing to
|
|
"_FOO" and re-defining "FOO" as ": FOO FOO* @ EXECUTE".
|
|
|
|
This is all well and good, but it is resource intensive and
|
|
verbose, which make us want to avoid this pattern for words
|
|
that are often used.
|
|
|
|
For this purpose, Collapse OS has two special word types:
|
|
alias and ialiases (indirect alias).
|
|
|
|
An alias is a variable that contains a pointer to another word.
|
|
When invoked, we invoke the specified pointer with minimal over-
|
|
head. Using our FOO example above, we would create an alias
|
|
with "' _FOO :* FOO". Invoking FOO will then invoke "_FOO". You
|
|
can change the alias' pointer with "*!" like this:
|
|
"' BAR ' FOO *!". FOO now invokes BAR.
|
|
|
|
A ialias is like an alias, but with a second level of indi-
|
|
rection. The variable points to a cell pointing to our word.
|
|
It works like an alias, except you have to use ":**" and "**!".
|
|
Ialiases are used by core code which point to hardcoded
|
|
addresses in RAM (because the core code is designed to run from
|
|
ROM, we can't have regular variables). You are unlikely to
|
|
need ialiases in regular code.
|
|
|
|
# Disk blocks
|
|
|
|
Disk blocks are Collapse OS' main access to permanent storage.
|
|
The system is exceedingly simple: blocks are contiguous
|
|
chunks of 1024 bytes each living on some permanent media such
|
|
as floppy disks or SD cards. They are mostly used for text,
|
|
either informational or source code, which is organized into
|
|
16 lines of 64 characters each.
|
|
|
|
Blocks are referred to by number, 0-indexed. They are read
|
|
through BLK@ and written through BLK!. When a block is read,
|
|
its 1024 bytes content is copied to an in-memory buffer
|
|
starting at BLK( and ending at BLK). Those read/write
|
|
operations are often implicit. For example, LIST calls BLK@.
|
|
|
|
When a word modifies the buffer, it sets the buffer as dirty
|
|
by calling BLK!!. BLK@ checks, before it reads its buffer,
|
|
whether the current buffer is dirty and implicitly calls BLK!
|
|
when it is.
|
|
|
|
The index of the block currently in memory is kept in BLK>.
|
|
|
|
Many blocks contain code. That code can be interpreted through
|
|
LOAD. Programs stored in blocks frequently have "loader blocks"
|
|
that take care of loading all blocks relevant to the program.
|
|
|
|
Blocks spanning multiple disks are tricky. If your media isn't
|
|
large enough to hold all Collapse OS blocks in one unit, you'll
|
|
have to make it span multiple disks. Block reference in
|
|
informational texts aren't a problem: When you swap your disk,
|
|
you mentally adjust the block number you fetch.
|
|
|
|
However, absolute LOAD operations in Collapse OS aren't aware
|
|
of disk spanning and will not work properly in your spanned
|
|
system.
|
|
|
|
Although the usage of absolute LOAD calls are minimally used
|
|
(relative LOADs are preferred), they are sometimes unavoidable.
|
|
When you span Collapse OS over multiple disks, don't forget to
|
|
adjust those absolute LOADs.
|
|
|
|
# How blocks are organized
|
|
|
|
Organization of contiguous blocks is an ongoing challenge and
|
|
Collapse OS' blocks are never as tidy as they should, but we
|
|
try to strive towards a few goals:
|
|
|
|
1. Block 0 contains documentation discovery core keys to the
|
|
uninitiated.
|
|
2. B1-B4 are for a master index of blocks.
|
|
3. B5-B259 are for programs loaded at runtime.
|
|
4. B260-B599 are for bootstrapping a new core.
|
|
5. B600-B650 are for recipes.
|
|
|
|
Recipes blocks do not live in the main blkfs, but each recipe
|
|
has its own blkfs overlay, with blocks beginning at 600.
|