From e8cc3040d162f8474c11aeae104a0029a2617ce3 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Sat, 28 Nov 2020 11:59:15 -0500 Subject: [PATCH] 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. --- blk.fs | 11 +++++---- doc/impl.txt | 78 ++++++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 61 insertions(+), 28 deletions(-) diff --git a/blk.fs b/blk.fs index 1d443e6..d58310d 100644 --- a/blk.fs +++ b/blk.fs @@ -1130,16 +1130,17 @@ lblexec BSET L1 FSET ( B284 ) L2 FSET ( B286 ) HL INCd, HL INCd, LDDE(HL), EXDEHL, ( does ) THEN, ( continue to compiledWord ) ( ----- 289 ) -( compiled word +( compiled word. HL points to its first wordref, which we'll + execute now. 1. Push current IP to RS - 2. Set new IP to the second atom of the list - 3. Execute the first atom of the list. ) + 2. Set new IP to PFA+2 + 3. Execute wordref ) IX INCd, IX INCd, 0 IX+ C LDIXYr, 1 IX+ B LDIXYr, ( While we inc, dereference into DE for execute call later. ) - LDDE(HL), - HL INCd, + LDDE(HL), ( DE is new wordref ) + HL INCd, ( HL is new PFA+2 ) B H LDrr, C L LDrr, ( --> IP ) JR, lblexec BWR ( execute-B287 ) ( ----- 290 ) diff --git a/doc/impl.txt b/doc/impl.txt index 8e58175..b5dc728 100644 --- a/doc/impl.txt +++ b/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 6. Error: undefined word. -# Executing a word +# What is a 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 (regular nonnative word), 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. +A word is a place in memory having a particular structure. Its +first byte is a "word type" byte (see below), followed by a +structure that depends on the word type. This structure is +generally refered to as the Parameter Field (PF). # 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" 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 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. 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 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. +# 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 There are some core variables in the core system that are