Improve impl's word execution documentation
Add an example, which I think helps a lot to grasp the idea. Also, improve comments in Z80 boot code.
This commit is contained in:
parent
038ca61ea5
commit
e8cc3040d1
11
blk.fs
11
blk.fs
@ -1130,16 +1130,17 @@ lblexec BSET L1 FSET ( B284 ) L2 FSET ( B286 )
|
|||||||
HL INCd, HL INCd, LDDE(HL), EXDEHL, ( does )
|
HL INCd, HL INCd, LDDE(HL), EXDEHL, ( does )
|
||||||
THEN, ( continue to compiledWord )
|
THEN, ( continue to compiledWord )
|
||||||
( ----- 289 )
|
( ----- 289 )
|
||||||
( compiled word
|
( compiled word. HL points to its first wordref, which we'll
|
||||||
|
execute now.
|
||||||
1. Push current IP to RS
|
1. Push current IP to RS
|
||||||
2. Set new IP to the second atom of the list
|
2. Set new IP to PFA+2
|
||||||
3. Execute the first atom of the list. )
|
3. Execute wordref )
|
||||||
IX INCd, IX INCd,
|
IX INCd, IX INCd,
|
||||||
0 IX+ C LDIXYr,
|
0 IX+ C LDIXYr,
|
||||||
1 IX+ B LDIXYr,
|
1 IX+ B LDIXYr,
|
||||||
( While we inc, dereference into DE for execute call later. )
|
( While we inc, dereference into DE for execute call later. )
|
||||||
LDDE(HL),
|
LDDE(HL), ( DE is new wordref )
|
||||||
HL INCd,
|
HL INCd, ( HL is new PFA+2 )
|
||||||
B H LDrr, C L LDrr, ( --> IP )
|
B H LDrr, C L LDrr, ( --> IP )
|
||||||
JR, lblexec BWR ( execute-B287 )
|
JR, lblexec BWR ( execute-B287 )
|
||||||
( ----- 290 )
|
( ----- 290 )
|
||||||
|
78
doc/impl.txt
78
doc/impl.txt
@ -12,29 +12,12 @@ it. As a general rule, we go like this:
|
|||||||
5. If yes, push that number to PS, goto 1
|
5. If yes, push that number to PS, goto 1
|
||||||
6. Error: undefined word.
|
6. Error: undefined word.
|
||||||
|
|
||||||
# Executing a word
|
# What is a word?
|
||||||
|
|
||||||
At its core, executing a word is pushing the wordref on PS and
|
A word is a place in memory having a particular structure. Its
|
||||||
calling EXECUTE. Then, we let the word do its things. Some
|
first byte is a "word type" byte (see below), followed by a
|
||||||
words are special, but most of them are of the "compiled"
|
structure that depends on the word type. This structure is
|
||||||
type (regular nonnative word), and that's their execution that
|
generally refered to as the Parameter Field (PF).
|
||||||
we describe here.
|
|
||||||
|
|
||||||
First of all, at all time during execution, the Interpreter
|
|
||||||
Pointer (IP) points to the wordref we're executing next.
|
|
||||||
|
|
||||||
When we execute a compiled word, the first thing we do is push
|
|
||||||
IP to the Return Stack (RS). Therefore, RS' top of stack will
|
|
||||||
contain a wordref to execute next, after we EXIT.
|
|
||||||
|
|
||||||
At the end of every compiled word is an EXIT. This pops RS, sets
|
|
||||||
IP to it, and continues.
|
|
||||||
|
|
||||||
A compiled word is simply a list of wordrefs, but not all those
|
|
||||||
wordrefs are 2 bytes in length. Some wordrefs are special. For
|
|
||||||
example, a reference to (n) will be followed by an extra 2 bytes
|
|
||||||
number. It's the responsibility of the (n) word to advance IP
|
|
||||||
by 2 extra bytes.
|
|
||||||
|
|
||||||
# Stack management
|
# Stack management
|
||||||
|
|
||||||
@ -84,6 +67,10 @@ The entry type is simply a number corresponding to a type which
|
|||||||
will determine how the word will be executed. See "Word types"
|
will determine how the word will be executed. See "Word types"
|
||||||
below.
|
below.
|
||||||
|
|
||||||
|
The vast majority of the time, a dictionary entry refers to a
|
||||||
|
word. However, sometimes, it refers to something else. A "hook
|
||||||
|
word" (see bootstrap.txt) is such an example.
|
||||||
|
|
||||||
# Word types
|
# Word types
|
||||||
|
|
||||||
There are 6 word types in Collapse OS. Whenever you have a
|
There are 6 word types in Collapse OS. Whenever you have a
|
||||||
@ -94,7 +81,7 @@ number is the word type and the word's behavior depends on it.
|
|||||||
jumped to directly.
|
jumped to directly.
|
||||||
|
|
||||||
1: compiled. This word's PFA contains a list of wordrefs and its
|
1: compiled. This word's PFA contains a list of wordrefs and its
|
||||||
execution is described in "Execution model" above.
|
execution is described in "Executing a compiled word" below.
|
||||||
|
|
||||||
2: cell. This word is usually followed by a 2-byte value in its
|
2: cell. This word is usually followed by a 2-byte value in its
|
||||||
PFA. Upon execution, the address of the PFA is pushed to PS.
|
PFA. Upon execution, the address of the PFA is pushed to PS.
|
||||||
@ -111,6 +98,51 @@ pushing it to PS, we execute it.
|
|||||||
|
|
||||||
5: ialias. Same as alias, but with an added indirection.
|
5: ialias. Same as alias, but with an added indirection.
|
||||||
|
|
||||||
|
# Executing a compiled word
|
||||||
|
|
||||||
|
At its core, executing a word is pushing the wordref on PS and
|
||||||
|
calling EXECUTE. Then, we let the word do its things. Some
|
||||||
|
words are special, but most of them are of the "compiled"
|
||||||
|
type, and that's their execution that we describe here.
|
||||||
|
|
||||||
|
First of all, at all time during execution, the Interpreter
|
||||||
|
Pointer (IP) points to the wordref we're executing next.
|
||||||
|
|
||||||
|
When we execute a compiled word, the first thing we do is push
|
||||||
|
IP to the Return Stack (RS). Therefore, RS' top of stack will
|
||||||
|
contain a wordref to execute next, after we EXIT.
|
||||||
|
|
||||||
|
At the end of every compiled word is an EXIT. This pops RS, sets
|
||||||
|
IP to it, and continues.
|
||||||
|
|
||||||
|
A compiled word is simply a list of wordrefs, but not all those
|
||||||
|
wordrefs are 2 bytes in length. Some wordrefs are special. For
|
||||||
|
example, a reference to (n) will be followed by an extra 2 bytes
|
||||||
|
number. It's the responsibility of the (n) word to advance IP
|
||||||
|
by 2 extra bytes.
|
||||||
|
|
||||||
|
To be clear: It's not (n)'s word type that is special, it's a
|
||||||
|
regular "native" word. It's the compilation of the (n) type,
|
||||||
|
done in LITN, that is special. We manually compile a number
|
||||||
|
constant at compilation time, which is what is expected in (n)'s
|
||||||
|
implementation. Similar special things happen in (s), (br),
|
||||||
|
(?br) and (loop).
|
||||||
|
|
||||||
|
For example, the word defined by ": FOO 42 EMIT ;" would have
|
||||||
|
an 8 bytes PF: a 2b ref to (n), 2b with 0x002a, a 2b ref to EMIT
|
||||||
|
and then a 2b ref to EXIT.
|
||||||
|
|
||||||
|
When executing this word, we first set IP to PF+2, then exec
|
||||||
|
PF+0, that is, the (n) reference. (n), when executing, reads IP,
|
||||||
|
pushes that value to PS, then advances IP by 2. This means that
|
||||||
|
when we return to the "next" routine, IP points to PF+4, which
|
||||||
|
next will execute. Before executing, IP is increased by 2, but
|
||||||
|
it's the "not-increased" value (PF+4) that is executed, that is,
|
||||||
|
EMIT. EMIT does its thing, doesn't touch IP, then returns to
|
||||||
|
"next". We're still at PF+6, which then points to EXIT. EXIT
|
||||||
|
pops RS into IP, which is the value that IP had before FOO was
|
||||||
|
called. The "next" dance continues...
|
||||||
|
|
||||||
# System variables
|
# System variables
|
||||||
|
|
||||||
There are some core variables in the core system that are
|
There are some core variables in the core system that are
|
||||||
|
Loading…
Reference in New Issue
Block a user