| www.delorie.com/gnu/docs/gforth/gforth_189.html | search |
![]() Buy GNU books! | |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Code and ;code
Gforth provides some words for defining primitives (words written in
machine code), and for defining the machine-code equivalent of
DOES>-based defining words. However, the machine-independent
nature of Gforth poses a few problems: First of all, Gforth runs on
several architectures, so it can provide no standard assembler. What's
worse is that the register allocation not only depends on the processor,
but also on the gcc version and options used.
The words that Gforth offers encapsulate some system dependences (e.g.,
the header structure), so a system-independent assembler may be used in
Gforth. If you do not have an assembler, you can compile machine code
directly with , and c,(36).
doc-assembler doc-init-asm doc-code doc-end-code doc-;code doc-flush-icache
If flush-icache does not work correctly, code words
etc. will not work (reliably), either.
The typical usage of these code words can be shown most easily by
analogy to the equivalent high-level defining words:
: foo code foo
<high-level Forth words> <assembler>
; end-code
: bar : bar
<high-level Forth words> <high-level Forth words>
CREATE CREATE
<high-level Forth words> <high-level Forth words>
DOES> ;code
<high-level Forth words> <assembler>
; end-code
|
In the assembly code you will want to refer to the inner interpreter's registers (e.g., the data stack pointer) and you may want to use other registers for temporary storage. Unfortunately, the register allocation is installation-dependent.
In particular, ip (Forth instruction pointer) and rp
(return stack pointer) are in different places in gforth and
gforth-fast. This means that you cannot write a NEXT
routine that works on both versions; so for doing NEXT, I
recomment jumping to ' noop >code-address, which contains nothing
but a NEXT.
For general accesses to the inner interpreter's registers, the easiest
solution is to use explicit register declarations (see section `Variables in Specified Registers' in GNU C Manual) for
all of the inner interpreter's registers: You have to compile Gforth
with -DFORCE_REG (configure option --enable-force-reg) and
the appropriate declarations must be present in the machine.h
file (see mips.h for an example; you can find a full list of all
declarable register symbols with grep register engine.c). If you
give explicit registers to all variables that are declared at the
beginning of engine(), you should be able to use the other
caller-saved registers for temporary storage. Alternatively, you can use
the gcc option -ffixed-REG (see section `Options for Code Generation Conventions' in GNU C Manual) to
reserve a register (however, this restriction on register allocation may
slow Gforth significantly).
If this solution is not viable (e.g., because gcc does not allow
you to explicitly declare all the registers you need), you have to find
out by looking at the code where the inner interpreter's registers
reside and which registers can be used for temporary storage. You can
get an assembly listing of the engine's code with make engine.s.
In any case, it is good practice to abstract your assembly code from the
actual register allocation. E.g., if the data stack pointer resides in
register $17, create an alias for this register called sp,
and use that in your assembly code.
Another option for implementing normal and defining words efficiently
is to add the desired functionality to the source of Gforth. For normal
words you just have to edit `primitives' (see section 14.3.1 Automatic Generation). Defining words (equivalent to ;CODE words, for fast
defined words) may require changes in `engine.c', `kernel.fs',
`prims2x.fs', and possibly `cross.fs'.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
| webmaster donations bookstore | delorie software privacy |
| Copyright © 2003 by The Free Software Foundation | Updated Jun 2003 |