Collapse OS Documentation Browser


asm/ code/ hw/ arch.txt avr.txt blk.txt blksrv.txt bootstrap.txt cross.txt design.txt dict.txt dis.txt drivers.txt ed.txt emul.txt faq.txt grid.txt hal.txt impl.txt intro.txt me.txt primer.txt ps2.txt rxtx.txt sdcard.txt sega.txt selfhost.txt spi.txt usage.txt

Harmonized Assembler Layer

The HAL is a set of macros whose goal is to make it possible to
make some parts of high-level code faster without having to
write code for each platform. The secondary goal of it is to
reduce the size of the native part of each port by moving words
that aren't critical into HAL code.

The idea is that each supported CPU has a set of code-emitting
macros that all follow the same API.

The HAL is *not* for general purposes. It is specially designed
for Collapse OS itself. Trying to generate another kind of
binary with it is likely a bad idea.

It is also not complete or orthogonal. The idea is to use it in
combination with INLINE (see doc/usage.txt). The HAL alone
doesn't do much, but along with the inlining of core words, you
should be able to achieve pretty much any computation you need.

Ops targets

This API revolves around PS. Some symbols have consistent
meaning across ops:

>x  Pop PS into.
x>  Push in PS.
@   Peek from PS. Copy the value without popping it.
>!  Replace PS TOS.
i   This operation involved an immediate value which needs to
    be supplied as an argument to the word.

Macro arguments

HAL macros generally require no argument. It's only when they
have a "i" signature (immediate) that they need to be supplied
with a number to hardcode in their instructions.


Jump words all require a numerical argument which will be
written next to them. For absolute jumps, it's easy: You use
labels. For example, you use "LSET mylabel" to mark, then
"mylabel JMPi," to jump.

Relative jump offsets are computed with "BR" and "FMARK". You
can use either labels or BEGIN, markers. Examples:

LSET L1 .. L1 BR JRi, \ backward jump with label
BEGIN, .. BR JRi, \ backward jump with BEGIN,
FJR JRi, .. FMARK \ forward jump with FJR
FJR JRi, TO L1 .. L1 FMARK \ forward jump with labels

The HAL convenience layer also has structures jumps helpers:

42 i>, BEGIN, INLINE 1- @Z, BR Z? ^? ?JRi, \ loop 42 times

Jump arguments

Wrapping one's head around jumping can be a challenge,
especially with a cross-CPU API. For JMPw and JMPi, it's rather
easy: the immediate or w are expected to contain an absolute
address to jump to.

For relative jump words (JRi, JRNZi, etc.), things must be
clarified: The expected argument is a CPU-specific offset. You
will seldom determine that offset yourself, but will instead use
BR and FMARK, which will use the CPU-specific JROFF and JROPLEN
constants to compute a proper offset.

Conditional jumps

The HAL only allows relative conditional jumps through the ?JRi,
word. The jump can be conditional to the value of two flags:
Zero and Carry. A condition must be selected before ?JRi, is
used. The words to select the condition are Z? (jump if Z is
set) C? (jump if C is set) and ^? (invert jump condition).

On "good old" register based CPUs, these words don't emit
anything, they simply select the opcode that ?JRi, will emit.
On stack-based CPUs, things are different because the
conditional jump is generally based on a flag placed on the
stack, so these words will emit the code that will place the
proper value on the stack.

The flag selection word has to be called before BR/FJR. The
proper form looks like this:

Z? L1 BR ?JRi,
C^? FJR ?JRi,

Convenience words like IFZ, IFNC, etc. take care of selecting
the proper flag.

HAL and high level flow words

The HAL implements all words required for ASMH, which implements
high level flow words such as IFZ, IFC, THEN, etc.

Those words are often bundled together, and alone, in the same
block because they're often re-used by assemblers.

See doc/asm/intro.txt for details.


The "," suffix is omitted below, but it's always there to
indicate that the effect of these word is to write (,) stuff to

On many CPUs, Z and C flags are set after a large part of the
arithmetic ops, but that can't be assumed in the HAL. C and Z
flags are set only after an op that specifies it, and it can't
be assumed anymore after running another op.

"Saves" means that the flag's value is kept intact so it has the
save value after the op as before it.

i>        Push immediate value to PS. Saves C.
(i)>      Push indirect immediate value to PS
>(i)      Pop PS into immediate address i
(i)+      Increase 16 bit number at address i
(i)-      Decrease 16 bit number at address i. Sets Z.
>IP       Pop PS into IP (Interpreter Pointer)
IP>       Push IP to PS
IP+       Increase IP by 1.
>JMP      Pop address from PS and jump to it.
JMPi      Inconditional jump to PC i
CALLi     Push PC+X to PS, then JMPi. X=length of CALL op
JRi       Inconditional jump with offset i
Z?        Make next ?JRi jump if Z is set
C?        Make next ?JRi jump if C is set
^?        Invert current flag selection (not Z, not C)
?JRi      Write a conditional jump for the current selection
@Z        Sets Z according to value in TOS
C>!       Writes C as a 0 or 1 to TOS
Z>!       Writes Z as a 0 or 1 to TOS

Native words and C/Z effects

Some native words affect (or don't) the C/Z flags in an
harmonized manner across arches. These are the "guaranteed"

<<        Affects C
>>        Affects C
+         Affects C
-         Affects C
A-        Affects Z

This of course only works when you INLINE them. Any run through
the "next" routine destroys C and Z.

Collapse OS and its documentation are created by Virgil Dupras and licensed under the GNU GPL v3.

This documentation browser by James Stanley. Please report bugs on github or to

This page generated at 2022-01-16 21:05:03 from documentation in CollapseOS snapshot 20220115.