duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit ec74406cecccf4e7ac41d351ff635d8b835f61d4
parent 2efcf748fd620c05cbc2513e31119d3395a4c8bf
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Wed, 10 Aug 2022 11:00:55 -0400

Harmonize dictionary and linked lists

Dictionary entries are now a specialized form of linked lists.

Diffstat:
Mfs/cc/gen.fs | 2+-
Mfs/doc/arch.txt | 24+++++++++++++++++++-----
Mfs/lib/xdict.fs | 8++++----
Mfs/tests/kernel.fs | 2+-
Mfs/xcomp/bootlo.fs | 21++++++++++++---------
Mfs/xcomp/i386.fs | 23+++++++++++------------
Mfs/xcomp/pc/kernel.fs | 2+-
Mfs/xcomp/tools.fs | 8++++----
Mposix/vm.c | 28++++++++++++++--------------
9 files changed, 67 insertions(+), 51 deletions(-)

diff --git a/fs/cc/gen.fs b/fs/cc/gen.fs @@ -206,7 +206,7 @@ ASTIDCNT wordtbl gentbl ( node -- ) parentnode dup ast.func.locsize swap to ast.func.cursf ; :w ( Ident ) dup identfind ?dup if ( inode dnode ) nip decl>op else ( inode ) - ast.ident.name current find ?dup _assert mem>op then ; + ast.ident.name sysdict find ?dup _assert mem>op then ; :w ( UnaryOp ) _debug if ." unaryop: " dup printast nl> .ops then dup genchildren diff --git a/fs/doc/arch.txt b/fs/doc/arch.txt @@ -6,21 +6,24 @@ This Forth is a Subroutine Thread Code (STC) Forth, that is, each reference to words is a native call instead of being a reference. This means that we don't have a "next" interpret loop. It's calls all the way down. +# Linked lists + +The linked list is a data structure that is heavily used in Dusk: dictionaries +are a specialized form of linked lists. A linked list is a structure where the +first element is a 4 bytes pointer to the next element. + # Dictionary structure Words in this Forth are embedded in a dictionary, which is a list of entries each pointing to the previous entry. We keep that last added entry in "current". +Dictionaries are a form of linked list. The structure of each entry is: Xb name 4b link to metadata -4b link to previous entry +4b link to previous entry --> this is where we link 1b name length + immediate ---> this is where we link - -When we refer to a word in Dusk OS, we always refer to its first executable -byte, right after the name length field. This way, we can call it directly. "previous entry" field in an entry refers to this same place. @@ -29,6 +32,17 @@ The link to metadata is a linked list, initialized to 0. See doc/usage. The length field is a 7 bit length with the 8th bit reserved for the "immediate" flag (1=immediate). +When we refer to a "word" in Dusk OS, we always refer to its first executable +byte, right after the name length field. When what you have is a word, you can +call it. + +When we refer to an "entry", we refer to the data structure. This means that an +entry is a pointer to the "previous entry" field. To get a word from an entry, +we add 5 bytes. + +Except for words specifically made for manipulating dictionary entries, we +rarely deal with "entry" pointers. We most often deal with word pointers. + # Cross-compilation When we use the word "cross-compiled" below, it means that the binary that is diff --git a/fs/lib/xdict.fs b/fs/lib/xdict.fs @@ -1,7 +1,7 @@ \ Extra dictionaries \ Create and use dictionaries besides the system one. Such dictionaries use the \ same words as words for the system dictionary. It does so by fiddling with -\ "current". +\ "sysdict". \ Usage: You begin by allocating a new dict structure with "newxdict <name>". \ Then, you just need to use "x" words like "xentry" and "x'". If you need @@ -16,10 +16,10 @@ \ mydict x' foo execute 1+ c@ .x1 -> 02 \ mydict x' bar execute .x1 -> 2a -0 value currentbkp +0 value dictbkp : newxdict create 4 allot0 ; -: xdict[ ( 'dict -- ) current to currentbkp @ to current ; -: ]xdict ( 'dict -- ) current swap ! currentbkp to current ; +: xdict[ ( 'dict -- ) sysdict to dictbkp @ to sysdict ; +: ]xdict ( 'dict -- ) sysdict swap ! dictbkp to sysdict ; : xdictproxy ( w -- ) doer , does> ( 'dict 'w -- ) over xdict[ swap >r @ execute r> ]xdict ; ' ' xdictproxy x' diff --git a/fs/tests/kernel.fs b/fs/tests/kernel.fs @@ -66,7 +66,7 @@ current .x \ preventry : bar ; : baz ; -' baz preventry ' bar #eq +' baz preventry e>w ' bar #eq \ metadata and linked lists ' bar emeta 0 #eq diff --git a/fs/xcomp/bootlo.fs b/fs/xcomp/bootlo.fs @@ -1,11 +1,15 @@ -," ;" 0 , current , $81 c, here to current +," w>e" 0 , sysdict , 3 c, here 5 - to sysdict ] + 5 - [ exit, +," ;" 0 , sysdict , $81 c, here w>e to sysdict ' [ execute, ' exit, execute, exit, -," dict," 0 , current , 5 c, here to current ] +," dict," 0 , sysdict , 5 c, here w>e to sysdict ] dup 1+ swap c@ tuck move, rot> , , c, ; -," entry" 0 , current , 5 c, here to current ] - current nextmeta rot dict, here to current 0 to nextmeta ; -," :" 0 , current , 1 c, here to current ] +," entry" 0 , sysdict , 5 c, here w>e to sysdict ] + sysdict nextmeta rot dict, here w>e to sysdict 0 to nextmeta ; +," :" 0 , sysdict , 1 c, here w>e to sysdict ] word entry ] ; +: e>w 5 + ; +: current sysdict e>w ; : immediate current 1- dup c@ $80 or swap c! ; : ['] ' litn ; immediate : to+ ['] +! [to] ; @@ -112,6 +116,7 @@ alias else endof immediate : llnext @ ; : llend ( ll -- lastll ) begin dup @ ?dup while nip repeat ( ll ) ; : lladd ( ll -- newll ) here swap llend ! here 0 , ; +: llcnt ( ll -- count ) A>r 0 >A begin ?dup while A+ llnext repeat A> r>A ; \ Emitting $20 const SPC $0d const CR $0a const LF $08 const BS @@ -140,8 +145,6 @@ alias noop [then] dup wordlen swap 9 - over - ( sl sa ) swap ; : .word ( w -- ) wordname[] rtype ; : words ( -- ) current begin dup while dup .word spc> preventry repeat drop ; -: dictcnt ( 'dict -- count ) - A>r 0 >A begin ?dup while A+ preventry repeat A> r>A ; \ Entry metadata 4 &+@ emetatype @@ -182,11 +185,11 @@ alias noop [then] _getinst + to? ?dup if execute else @ execute then ; : _parens ( 'struct off ) compiling if litn litn compile (struct()) else swap (struct()) then ; -: 'structsz ( 'struct -- sz ) @ dictcnt CELLSZ * ; +: 'structsz ( 'struct -- sz ) @ llcnt CELLSZ * ; : structsz ( w -- sz ) does' 'structsz ; : struct ( cnt -- ) doer >r here 0 , 0 , 0 0 begin ( 'dict off current ) - 0 ( meta ) word dict, here ( 'dict off current ) + 0 ( meta ) word dict, here w>e ( 'dict off current ) swap dup , CELLSZ + swap next ( 'dict off current ) nip swap ! immediate does> ( ??? 'struct -- ??? *to* ) diff --git a/fs/xcomp/i386.fs b/fs/xcomp/i386.fs @@ -25,7 +25,7 @@ 0 to realmode : values ( n -- ) >r begin 0 value next ; 25 values L1 L2 lblmainalias lbltoptr lbltoexec lblbootptr lblin< lblcurword - lblnextmeta lblret lblcurrent lblemit lblparsec lblparseh lblparseud + lblnextmeta lblret lblsysdict lblemit lblparsec lblparseh lblparseud lblerrmsg lblrtype lblhere lblmovewrite lblwrite lblcwrite lblfind lblcompiling lblareg lblidt $8000 const HERESTART \ TODO: find a better place @@ -136,8 +136,8 @@ xcode heremax xcode here wcall, (val) pc to lblhere HERESTART , -xcode current - wcall, (val) pc to lblcurrent 0 , +xcode sysdict + wcall, (val) pc to lblsysdict 0 , pc to lblcompiling 0 , xcode compiling @@ -624,25 +624,24 @@ pc to lblfind cl [esi] mov, [ebp] inc, pc ( loop ) - di dx mov, - di dec, - al di 0 d) mov, + di dx mov, \ entry + al di 4 d) mov, \ len al $3f i) and, \ 3f instead of 7f? we reserve space for another flag. al cl cmp, forward jnz, to L1 ( skip1 ) \ same length - di 8 i) sub, - di cx sub, + di 4 i) sub, + di cx sub, \ beginning of name range si [ebp] mov, repz, cmpsb, forward jnz, to L2 ( skip2 ) \ same contents + dx 5 i) add, \ word [ebp] dx mov, ret, L2 forward! ( skip2 ) cl al mov, L1 forward! ( skip1 ) - dx 5 i) sub, dx dx 0 d) mov, dx dx test, ( pc ) abs>rel jnz, ( loop ) @@ -662,7 +661,7 @@ xcode (wnf) xcode ' ( "name" -- w ) wcall, word - dx lblcurrent m) mov, + dx lblsysdict m) mov, lblfind abs>rel call, [ebp]z? xwordlbl (wnf) abs>rel jz, @@ -813,14 +812,14 @@ pc ( literal handling ) xwordlbl litn abs>rel jnz, \ compiling ret, \ not compiling, nothing to do -xcode runword ( str -- ) pc lblcurrent pc>addr ! +xcode runword ( str -- ) pc w>e lblsysdict pc>addr ! wcall, parse AX pspop, ax ax test, ( pc ) abs>rel jnz, \ is a literal \ not a literal lblcurword pspushN, - dx lblcurrent m) mov, + dx lblsysdict m) mov, lblfind abs>rel call, [ebp]z? xwordlbl (wnf) abs>rel jz, diff --git a/fs/xcomp/pc/kernel.fs b/fs/xcomp/pc/kernel.fs @@ -22,7 +22,7 @@ pc to L1 \ segment with ffff limits 0 L2 jmpfar, 0 to realmode -xcode int13h ( drv head cyl sec dst -- ) pc lblcurrent pc>addr ! +xcode int13h ( drv head cyl sec dst -- ) pc w>e lblsysdict pc>addr ! BX pspop, AX pspop, cl al mov, \ sec AX pspop, ch al mov, \ cyl diff --git a/fs/xcomp/tools.fs b/fs/xcomp/tools.fs @@ -19,10 +19,10 @@ newxdict xbindict \ to current org+binstart. Once this is done, the xdict can't be traversed \ anymore and becomes opaque binary contents. : orgifydict ( xdict -- ) - @ begin ( a ) - 5 - dup @ ( 'prev prev ) - ?dup while ( 'prev prev ) - dup xoffset + ( 'prev oldprev newprev ) rot ! ( prev ) repeat drop ; + @ begin ( entry ) + dup @ ( entry next ) + ?dup while ( entry next ) + dup xoffset + ( entry old new ) rot ! ( entry ) repeat drop ; LF value _last 0 value _incomment? diff --git a/posix/vm.c b/posix/vm.c @@ -22,8 +22,8 @@ The VM is little endian. #define SYSVARSSZ 0x80 #define SYSVARS ((PSTOP-STACKSZ)-SYSVARSSZ) #define HERE SYSVARS -#define CURRENT (HERE+4) -#define NEXTMETA (CURRENT+4) +#define SYSDICT (HERE+4) +#define NEXTMETA (SYSDICT+4) #define INRD (NEXTMETA+4) #define EMIT (INRD+4) #define ABORT (EMIT+4) @@ -75,21 +75,21 @@ static dword rpop() { dword n = rpeek(); vm.RSP += 4; return n; } static void rpush(dword d) { vm.RSP -= 4; sd(vm.RSP, d); } static dword here() { return gd(HERE); } static void allot(dword n) { sd(HERE, here()+n); } -static dword current() { return gd(CURRENT); } +static dword sysdict() { return gd(SYSDICT); } static dword _find(dword dict, byte *name, byte slen) { dword a = dict; byte len; while (memchk(a)) { - len = gb(a-1) & 0x3f; - if ((len == slen) && (memcmp(name, &vm.mem[a-9-len], len)==0)) { - return a; + len = gb(a+4) & 0x3f; + if ((len == slen) && (memcmp(name, &vm.mem[a-4-len], len)==0)) { + return a+5; } - a = gd(a-5); + a = gd(a); } return 0; } static dword find(char *name) { - return _find(current(), (byte*)name, strlen(name)); + return _find(sysdict(), (byte*)name, strlen(name)); } static void cwrite(byte b) { sb(here(), b); @@ -114,9 +114,9 @@ static void _entry(byte *name, byte slen) { memcpy(&vm.mem[here()], name, slen); allot(slen); dwrite(gd(NEXTMETA)); - dwrite(current()); + dwrite(sysdict()); cwrite(slen); - sd(CURRENT, here()); + sd(SYSDICT, here()-5); sd(NEXTMETA, 0); } static void entry(char *name) { @@ -670,7 +670,7 @@ static void FIND() { // op: 55 static void APOS() { // op: 56 WORD(); - ppush(current()); + ppush(sysdict()); FIND(); if (!ppeek()) WNF(); } @@ -706,7 +706,7 @@ static void RUNWORD() { // op: 5b if (vm.compiling) LITN(); } else { ppush(CURWORD); - ppush(current()); + ppush(sysdict()); FIND(); if (!ppeek()) { WNF(); return; } if (vm.compiling && !((gb(ppeek()-1) & 0x80) /* immediate */)) { @@ -933,7 +933,7 @@ static void sysconst(char *name, dword val) { static void buildsysdict() { sd(HERE, 0); - sd(CURRENT, 0); + sd(SYSDICT, 0); entry("noop"); retwr(); for (int i=0x04; i<OPCNT; i++) { if (ops[i] && opnames[i]) { opentry(i); retwr(); } @@ -947,7 +947,7 @@ static void buildsysdict() { sysalias("abort", ABORT); sysalias("main", MAINLOOP); sysval("here", HERE); - sysval("current", CURRENT); + sysval("sysdict", SYSDICT); sysval("nextmeta", NEXTMETA); sysconst("heremax", HEREMAX); sysconst("curword", CURWORD);