duskos

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

commit 5cff8c8e52213881ade1059ae72e41a6ebed53df
parent 5ef6c1fb84ed08b38cf007b6490853b1d72d26f5
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Tue,  9 Aug 2022 13:48:01 -0400

Make "struct" into something more elegant and convenient

and include it into bootlo because I'm going to use it in fatlo.

See doc/usage.

Diffstat:
MMakefile | 2+-
Mfs/cc/cc.fs | 2+-
Mfs/cc/gen.fs | 2+-
Mfs/cc/tok.fs | 4++--
Mfs/doc/usage.txt | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Mfs/lib/scratch.fs | 34+++++++++++++++++++---------------
Mfs/sys/file.fs | 6++----
Mfs/sys/scratch.fs | 3+--
Mfs/tests/kernel.fs | 21+++++++++++++++++++++
Mfs/tests/lib/all.fs | 1-
Mfs/xcomp/bootlo.fs | 38++++++++++++++++++++++++++++++++++++--
11 files changed, 134 insertions(+), 29 deletions(-)

diff --git a/Makefile b/Makefile @@ -21,7 +21,7 @@ pc.bin: dusk buildpc.fs $(ALLSRCS) pc.img: mbr.bin pc.bin dd if=/dev/zero of=$@ bs=1M count=1 # We need to reserve (-R) enough sectors for MBR + pc.bin - mformat -M 512 -d 1 -R 48 -i $@ :: + mformat -M 512 -d 1 -R 56 -i $@ :: dd if=mbr.bin of=$@ bs=1 seek=62 conv=notrunc dd if=pc.bin of=$@ bs=1 seek=512 conv=notrunc mcopy -sQ -i $@ fs/* :: diff --git a/fs/cc/cc.fs b/fs/cc/cc.fs @@ -3,7 +3,7 @@ require sys/scratch.fs require sys/xhere.fs 1 value _debug S" /cc/vm" findpath# ( hdl ) -scratch[ ARCH c@+ dup 3 + c, move, ," .fs" ]scratch ( hdl fname ) +syspad :[ ARCH c@+ dup 3 + c, move, ," .fs" syspad :] ( hdl fname ) fchild dup bool const HASCC ( hdl ) HASCC not [if] drop ." Unsupported arch for CC" nl> \s [then] ( hdl ) fload diff --git a/fs/cc/gen.fs b/fs/cc/gen.fs @@ -232,7 +232,7 @@ ASTIDCNT wordtbl gentbl ( node -- ) r> ( selectedop ) if op1<>op2 else selop1 then ; \ TODO: this doesn't work with lvalues yet :w ( List ) - dup childcount dup 1+ 4 * scratchallot dup >r ( node len a ) + dup childcount dup 1+ 4 * syspad :allot dup >r ( node len a ) over >r tuck ! 4 + swap firstchild begin ( a node ) dup ast.const.value ( a node value ) rot tuck ! ( node a ) 4 + swap nextsibling next ( a node ) 2drop diff --git a/fs/cc/tok.fs b/fs/cc/tok.fs @@ -59,7 +59,7 @@ create _ 10 c, ," 09AZaz__$$" ( c ) else ( EOF ) drop 0 then ; : _writesym ( c3? c2? c1 len -- str ) - 4 scratchallot dup >r ( c3? c2? c1 len a ) + 4 syspad :allot dup >r ( c3? c2? c1 len a ) over >r c!+ ( c a ) begin c!+ next drop r> ( str ) ; \ Returns the next token as a string or 0 when there's no more token to consume. @@ -87,7 +87,7 @@ create _ 10 c, ," 09AZaz__$$" cc< cc< ''' = not if _err then ( c ) ''' tuck ( ' c ' ) 3 _writesym endof of ident-or-lit? \ identifier or number literal - r@ ( c ) A>r MAXTOKSZ scratchallot >A A>r ( R:tok ) + r@ ( c ) A>r MAXTOKSZ syspad :allot >A A>r ( R:tok ) 0 Ac!+ ( len placeholder ) begin ( c ) Ac!+ cc< dup ident-or-lit? not until to putback r> ( buf ) A> over 1+ - ( tok len ) over c! r>A diff --git a/fs/doc/usage.txt b/fs/doc/usage.txt @@ -82,3 +82,53 @@ Each metadata element has this structure: 4b link to next 4b type ID ( any other type-specific data ) + +# Structures + +Structures are an effective way to address offsets from base addresses while +keeping the general namespace clean. Structures have a name and a list of fields +and are declared thus: + +3 struct Foo bar baz :bleh + +This describes an 12 byte wide struct with 3 fields. All fields in structs are +always contiguous and 4 bytes wide. + +The name is a string identifying the field. It has no existence in the system +dictionary and will only be used in the context of that structure, so name +clashes are not a problem. Field names can be any word except "'(" and "')" +which are reserved + +A field name starting with : is a "method". This means that it behaves like an +alias instead of like a value. The ":" stays in the name, you have to include it +when you invoke the method. + +You create new instances with "instance", followed by the struct name, followed +by the name of your new instance. This *doesn't* allocate and initialize the +memory associated to the fields. You have to do it yourself. + +Accessing fields is where the fun begins. You refer to a field by calling the +intance's name, followed by the field name. This will refer to the particular +address in a way that obeys "to" semantics. + +There are two special field names, "'(" and "')" which yield the starting and +ending address of the struct instance. These words don't obey "to" semantics. + +The struct name can itself be used like an instance. When you refer to the +struct name, it will refer to the last instance being used. This is useful in +methods, when you want to have to kind of reference to "self". + +Example: + +3 struct Foo bar baz :bleh +: mybleh ." hello! " Foo baz . ; +instance Foo MyFoo 1 , 2 , ' mybleh , +instance Foo OtherFoo 3 , 4 , ' mybleh , +MyFoo bar . \ prints 1 +OtherFoo bar . \ prints 3 +: myword 42 to MyFoo baz ; myword +MyFoo baz . \ prints 42 +1 to+ MyFoo baz +MyFoo baz . \ print 43 +MyFoo :bleh \ print "hello! 2" +OtherFoo :bleh \ print "hello! 4" diff --git a/fs/lib/scratch.fs b/fs/lib/scratch.fs @@ -1,5 +1,4 @@ \ Scratchpads -?f<< /lib/struct.fs \ Scratchpads are circular buffers for placing semi-temporary strings (or \ other sequences). The scratchpad has a running pointer and when we need @@ -9,24 +8,29 @@ \ The system scratchpad lives at sys/scratch. -struct Scratchpad - bfield scratchsize - bfield scratch> - 'bfield scratch( -0 value _here +8 struct Scratchpad + size ptr :buf( :)buf :allot :[]>str :[ :] -: scratchpad$ ( size "name" -- ) create dup , here CELLSZ + , allot ; -: scratch) scratch( scratchsize + ; -: scratchallot ( n -- a ) - scratch> over + scratch) >= if ." scratch reload!" nl> scratch( to scratch> then - scratch> swap to+ scratch> ( a ) ; +: _buf( Scratchpad ') ; +: _buf) _buf( Scratchpad size + ; +: _allot ( n -- a ) + Scratchpad ptr over + _buf) >= if + ." scratch reload!" nl> _buf( to Scratchpad ptr then + Scratchpad ptr swap to+ Scratchpad ptr ( a ) ; \ push a range to the scratchpad as a string -: []>str ( a u -- str ) - dup 1+ scratchallot ( src u dst-1 ) >r dup r@ c!+ swap ( src dst u ) move r> ; +: _[]>str ( a u -- str ) + dup 1+ _allot ( src u dst-1 ) >r dup r@ c!+ swap ( src dst u ) move r> ; + +0 value _here \ Open a scratch area for writing -: scratch[ ( -- ) here to _here scratch> to here ; +: _[ ( -- ) here to _here Scratchpad ptr to here ; \ Stop writing to the scratch area and restore here \ Returns the address of the beginning of the written area -: ]scratch ( -- a ) scratch> here to scratch> _here to here ; +: _] ( -- a ) here to@! Scratchpad ptr _here to here ; + +: scratchpad$ ( size -- ) + dup , Scratchpad ') , + ['] _buf( , ['] _buf , ['] _allot , ['] _[]>str , ['] _[ , ['] _] , allot ; + diff --git a/fs/sys/file.fs b/fs/sys/file.fs @@ -40,14 +40,12 @@ create _buf $100 allot \ We need a private scratchpad here because some cursors can be quite \ long-lived. If we use the system scratchpad, short-lived data will overwrite \ our cursors. -$200 scratchpad$ filespad +instance Scratchpad filespad $200 scratchpad$ \ This creates a "f<" reader with the file descriptor embedded in it. This \ allows for a straightforward override of input/output words. : [f<] ( curfd -- word ) - filespad to@! Scratchpad >r - scratch[ litn compile getc exit, ]scratch - r> to Scratchpad ; + filespad :[ litn compile getc exit, filespad :] ; : require word dup findpath# floaded? not if stype abort" required" else drop then ; diff --git a/fs/sys/scratch.fs b/fs/sys/scratch.fs @@ -9,5 +9,4 @@ \ TODO: investigate why CC has memory corruption when running tests with a $4000 \ syspad. -$8000 scratchpad$ syspad -syspad to Scratchpad +instance Scratchpad syspad $8000 scratchpad$ diff --git a/fs/tests/kernel.fs b/fs/tests/kernel.fs @@ -77,4 +77,25 @@ floaded # 0 ( file doesn't exist ) floaded? not # S" /tests/harness.fs" findpath floaded? # + +\ Structures + +3 struct Foo bar baz :bleh +: mybleh Foo bar Foo baz + ; +instance Foo MyFoo 1 , 2 , ' mybleh , +instance Foo OtherFoo 3 , 4 , ' mybleh , +MyFoo '( @ 1 #eq +MyFoo ') MyFoo '( - 3 CELLSZ * #eq +MyFoo bar 1 #eq +OtherFoo bar 3 #eq +: myword 42 to MyFoo baz ; myword +MyFoo baz 42 #eq +1 to+ MyFoo baz +MyFoo baz 43 #eq +MyFoo :bleh 44 #eq +OtherFoo :bleh 7 #eq +: myword MyFoo bar ; +myword 1 #eq +OtherFoo bar 3 #eq +myword 1 #eq testend diff --git a/fs/tests/lib/all.fs b/fs/tests/lib/all.fs @@ -3,6 +3,5 @@ f<< /tests/lib/core.fs f<< /tests/lib/bit.fs f<< /tests/lib/str.fs f<< /tests/lib/xdict.fs -f<< /tests/lib/struct.fs f<< /tests/lib/crc.fs f<< /tests/lib/io.fs diff --git a/fs/xcomp/bootlo.fs b/fs/xcomp/bootlo.fs @@ -78,7 +78,8 @@ : &c@ ( n -- ) doer , does> @ c@ ; : &+@ ( n -- ) doer , does> @ + @ ; : &+! ( n -- ) doer , does> @ + ! ; -: field ( off -- ) doer , does> ( a 'w ) @ + to? ?dup if execute else @ then ; +: ?toexec ( a -- ??? ) to? ?dup if execute else @ then ; +: field ( off -- ) doer , does> ( a 'w ) @ + ?toexec ; \ A structure method. Called with a strucure as the top argument and will \ execute the word pointer at a specific offset with that structure pointer \ till on the top of PS. @@ -105,8 +106,10 @@ alias else endof immediate ?dup if begin [compile] then ?dup not until then compile rdrop ; immediate \ Linked lists. See doc/usage. -alias @ llnext +: llnext @ ; : llend ( ll -- lastll ) begin dup @ ?dup while nip repeat ( ll ) ; +: llcnt ( ll -- count ) + A>r 0 >A begin dup @ ?dup while A+ nip repeat drop A> r>A ; : lladd ( ll -- newll ) here swap llend ! here 0 , ; \ Emitting @@ -161,6 +164,37 @@ alias noop [then] litn litn compile _ else swap _ then ; immediate +\ Structures +\ Structure's structure: +\ 4b link to field list +\ Field's structure: +\ 4b next +\ Xb string + +create _currentinst CELLSZ allot +: (struct()) ( off -- a ) _currentinst @ + ; +: (struct) ( off ) _currentinst @ + ?toexec ; +: (struct:) ( off ) _currentinst @ + to? ?dup if execute else @ execute then ; +: _parens ( off ) compiling if litn compile (struct()) else (struct()) then ; +: struct ( cnt -- ) + doer >r here 0 , + begin ( ll ) lladd word c@+ dup c, move, next drop immediate +does> ( ??? 'struct -- ??? *to* ) + word case ( 'struct R:str ) + S" '(" of s= drop 0 _parens endof + S" ')" of s= llcnt CELLSZ * ( off ) _parens endof + \ find field in list + 0 swap @ begin ( cnt ll ) + ?dup not if curword stype abort" field doesn't exist!" then + dup 4 + curword s= if leave else llnext swap 1+ swap then + next ( cnt ll ) drop CELLSZ * ( off ) + curword 1+ c@ ':' = if ['] (struct:) else ['] (struct) then + compiling if swap litn execute, else execute then + endcase ; +: _inst! _currentinst ! ; +: instance ' doer , here _currentinst ! immediate does> + dup CELLSZ + compiling if litn compile _inst! else _inst! then @ execute ; + \ Drive API \ Anticipating lib/drive : drvsecsz ( drv -- sz ) @ ;