commit d34f22b8a0f7c3b66c6aecc158b0e72995bdf53a
parent aed095e7171dab68aaec1575c71de62d626cf70b
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Mon, 26 Dec 2022 19:18:59 -0500
Reorganize docs
Diffstat:
24 files changed, 396 insertions(+), 405 deletions(-)
diff --git a/fs/doc/arch.txt b/fs/doc/arch.txt
@@ -122,10 +122,10 @@ end of "boothi". You can call "init" in xcomp/init.fs, but by doing so, you'll
monopolize the file handle that was opened for xcomp/init.fs.
One of the things that your "init" word has to do is to set up ConsoleIn (see
-doc/io), which until now is still on BootIn, a structure that reads the embedded
-code from memory. That code stream is about to run out. If your system is
-interactive, you'll typically want to load sys/rdln and have init call "rdln$"
-which sets ConsoleIn to RdlnIn, which then makes the system interactive.
+doc/sys/io), which until now is still on BootIn, a structure that reads the
+embedded code from memory. That code stream is about to run out. If your system
+is interactive, you'll typically want to load sys/rdln and have init call
+"rdln$" which sets ConsoleIn to RdlnIn, which then makes the system interactive.
The system is yours.
diff --git a/fs/doc/cc/lib.txt b/fs/doc/cc/lib.txt
@@ -41,8 +41,8 @@ int isdigit(char c)
### I/O
-The I/O API is a simple layer over the system I/O described at doc/io. `hdl` is
-a regular I/O handle.
+The I/O API is a simple layer over the system I/O described at doc/sys/io. `hdl`
+is a regular I/O handle.
int fgetc(int hdl) --> IO :getc
void fputc(char c, int hdl) --> IO :putc
@@ -82,7 +82,7 @@ variable number of arguments which must match the number of formatting
placeholder in `fmt`, *in reverse order* (this simplifies the implementation
logic a lot). For example, `printf(3, 2, 1, "%b %w %d")` prints `01 0002 3`.
-printf formatting arguments are described in doc/io.
+printf formatting arguments are described in doc/sys/io.
fscanf doesn't exist in sys/io yet and is only and CC stdlib. It supports only
the `%d` placeholder. Like printf, it's funky in its arguments, but in the
@@ -98,8 +98,8 @@ For example, `sscanf("%d %d %d", "5 6 7")` results in PS receiveing elements
to PS.
printf and scanf each have `f` and `s` variants. Without a variant, printing and
-scanning is done through StdOut and StdIn (see doc/io). The `f` variant allow us
-to choose another target I/O handle.
+scanning is done through StdOut and StdIn (see doc/sys/io). The `f` variant
+allow us to choose another target I/O handle.
For the `s` variant, we have a static buffer wrapped around a `MemFile` that is
used. The resulting string is a memory in that buffer and is overwritten at each
diff --git a/fs/doc/drive.txt b/fs/doc/drive.txt
@@ -1,26 +1,25 @@
# Drive API
-The sys/drive subsystem offers a unified API to read and write to mass storage.
-It does so in blocks of bytes of a definite size which we call "sector".
-Sectors in the Drive API are organized in a linear manner (LBA, Logical Block
+TODO: the Drive struct is defined in xcomp/bootlo and I can't think of an
+adequate place for this documentation. For now, it's here.
+
+The Drive struct offers a unified API to read and write to mass storage. It
+does so in blocks of bytes of a definite size which we call "sector". Sectors
+in the Drive API are organized in a linear manner (LBA, Logical Block
Addressing). If the underlying mass storage driver interfaces with a CHS
-(cylinder, head, sector) system, it's the driver's responsibility to convert
-LBA to CHS.
+(cylinder, head, sector) system, it's the driver's responsibility to convert LBA
+to CHS.
-The drive API exposes the features of the underlying driver through a specific
-data structure, called a Drive, which is 12 bytes in length in the form of 3
-fields of 4 bytes:
+Fields:
-secsz
-:sec@
-:sec!
+secsz an integer describing, in bytes, the size of sectors read and written
+ by the driver. It's often 512 bytes.
-secsz is an integer describing, in bytes, the size of sectors read and written
-by the driver. It's often 512 bytes.
+Methods:
:sec@ ( sec dst drv -- )
Read sector "sec" in memory address "dst", which needs to be a buffer at least
- "drvsecsz" in size. "drv" is a pointer to a Drive structure.
+ "secsz" in size. "drv" is a pointer to a Drive structure.
:sec! ( sec src drv -- )
Write sector "sec" from memory address "src".
diff --git a/fs/doc/uxn.txt b/fs/doc/emul/uxn.txt
diff --git a/fs/doc/file.txt b/fs/doc/file.txt
@@ -1,232 +0,0 @@
-# File subsystem
-
-The file subsystem allows the system to interact with filesystems.
-
-Files and directories all live within filesystems. More than one filesystem can
-be active at once and each of these filesystems is designated by a letter. For
-example, the boot filesystem is always "A". There's a maximum of 26 active
-filesystems.
-
-Filesystems contain files and directories. A file is a blob of data that exists
-within a directory. A directory is a container for files and other directories.
-Each filesystem has one root directory.
-
-Files and directories are referred to with strings of characters that we call
-"paths". Those paths begin with a filesystem identifier, followed by name of
-directory and file. A directory name can be followed by a "/" character to
-indicate that we want to refer to one of its children.
-
-There is also the concept of an "active" directory. When paths don't start with
-a drive letter, the path is relative to this active directory. A path starting
-with "/" refers to the root directory of the active directory's filesystem. The
-initial active directory is the boot filesystem's root directory (A:).
-
-Examples:
-
-A: root of filesystem A
-A:foo.txt file "foo.txt" inside A's root directory
-B:foo/bar.fs file "bar.fs" inside "foo" directory inside B's root
-bar.fs file "bar.fs" in active directory
-/foo.fs file "foo.fs" in active filesystem's root directory
-
-## Filesystem API
-
-When the code refers to a filesystem, it does so through a definite structure:
-
-drv -- Drive pointer (see doc/drive)
-
-:child ( dirid name fs -- id )
- Enumerate the contents of directory "dirid" and look for name "name". If
- found, returns the ID of the child (either a file or directory), otherwise,
- return 0. See below for the concept of "ID".
-
-:info ( id fs -- info )
- Returns a FSInfo structure (described below) corresponding to the specified
- ID. This structure is a singleton and is only valid until the next :info call.
-
-:open ( id fs -- hdl )
- Open file at path and return a handle through which other file-related word
- identify the target file. Once a file isn't used anymore, it should be
- closed with :close. Aborts on error.
-
-:iter ( w id fs -- )
- Iterate through all children of directory "id", ignoring "." and ".." entries.
- For each child iterated upon, call word "w" which has the signature
- "id fs --", "id" being the ID of the child.
-
-:newfile ( dirid name fs -- id )
- Create a new empty file named "name" in "dirid" and return the ID of the new
- file. Aborts on error.
-
-:newdir ( dirid name fs -- id )
- Create a new directory named "name" in "dirid" and return the ID of the new
- directory. Aborts on error.
-
-... followed by whatever data the FS implementation needs.
-
-In each method, "fs" refers to a filesystem, a pointer to the structure decribed
-above.
-
-Additionally, the Filesystem struct also has these convenience methods which are
-independent of the underlying implementation:
-
-:?newfile ( dirid name fs -- id )
- Create a new file if it doesn't exist. If it exists, return its ID.
-
-:?newdir ( dirid name fs -- id )
- Create a new directory if it doesn't exist. If it exists, return its ID.
-
-## File API
-
-The File API is a specialization of the I/O API (doc/io) for accessing files in
-a filesystem. It also works with "handles", which we call a File handle. Of
-course, it starts with the I/O prelude, but then adds its own prelude:
-
-(I/O prelude)
-:seek
-
-These words have the following meaning:
-
-:seek ( pos hdl -- )
- Place the handle at offset "pos" (in bytes).
-
-## FSInfo API
-
-The structure returned by ":info" above goes as follows:
-
-name -- a pointer to a string
-size -- size of the file, or 0 for a directory
-dir? -- whether the element is a directory
-
-## Path API
-
-The Path structure represents a path from any of the currently mounted
-filesystems. It has 2 fields: "fs", which is a pointer to a Filesystem struct
-and "id", which is the FS ID corresponding to the path. Path allocations are
-managed through a small "rolling" buffer, which means that if you want to hold
-on to a Path reference a little longer, you should copy it elsewhere.
-
-:new ( fs id -- path )
- Allocate a new Path reference with the specified fields
-
-:find ( str -- path-or-0 )
- Find FS ID corresponding to path and return Path reference or 0 if not found.
-
-:find# ( str -- path )
- Like :find, but errors out if not found.
-
-:fload ( self -- )
- Open specified path and interpret it as Forth source.
-
-:floaded? ( self -- f )
- Returns whether this particular path has ever been loaded with :fload.
-
-:chdir ( self -- )
- Change current directory to path. In subsequent path finds, if the path
- doesn't start with "/", the search will start from this directory.
- Aborts if path is not found.
-
-:open ( self -- file )
-:info ( self -- file )
-:child ( name self -- path-or-0 )
-:iter ( w self -- )
- Convenience proxies to the corresponding methods in the Filesystem API.
-
-:iterdirs ( w self -- )
- Calls :iter but filters the call to 'w' to directories only. On top of this,
- an additional "info" argument is passed to 'w', making its signature
- "id fs info -- "
-
-:iterfiles ( w self -- )
- Same as :iterdirs, but for files.
-
-## Global variables
-
-The File subsystem has 2 important global variables:
-
-bootfs is a pointer to the Filesystem structure from which the system was
-booted. It's used only until the File subsystem is initialized.
-
-curpath is a Path bind that points to the "current directory". It is initialized
-to the root directory of bootfs but can be changed with Path :chdir.
-
-## Paths
-
-Paths uniquely identify a directory or a file on the current set of mounted
-filesystems. Paths can take 3 forms: absolute, FS relative and relative.
-
-Absolute paths begin with a drive letter ("A" is the boot drive, "B" is the
-second one, etc.) followed by ":", followed by a relative path. Example:
-
-a:lib/str.fs
-
-FS relative are path relative to the currently "active" filesystem, that is, the
-filesystem that contains the "current directory". Such paths begin by a "/"
-followed by a relative path. Example:
-
-/lib/str.fs
-
-Relative paths are paths relative to the "current directory". These paths begin
-directly with a name. Example for a "current directory" set to "/lib":
-
-str.fs
-
-## File ID design considerations
-
-When we refer to a file or directory ID, we refer to a single 32-bit number
-uniquely identifying the file or directory in the volume. From this number, we
-must be able to find the file or directory in the volume so that we can open it
-or enumerate it. The ID of the root directory is always zero.
-
-That IDs are 32-bit make their manipulation straightforward. One might fear that
-32 bits are not enough to identify all elements of big filesystems.
-
-On many filesystems, 32 bits are enough. For example, in ext4, inodes always fit
-32 bits, even in 64-bit mode.
-
-For FAT32, it's another matter. The straightforward way to derive an ID from an
-element is to return the offset of its DirEntry and divide it by 32. This means
-that this ID scheme could only address 64GB volumes.
-
-This would mean that the File API would be broken on a subset of filesystems.
-Does it mean that Dusk couldn't read them? No, only that file/dir enumeration
-would have to go through FS-specific tools. I think that this inconvenience is
-worth it if it means an overall simpler API.
-
-## Path literals
-
-There are 2 words for Path/File shortcuts: p" and f".
-
-p" foo" is a shortcut for S" foo" curpath :find# and f" foo" is a shortcut for
-p" foo" Path :open.
-
-## MemFile
-
-MemFile is a structure that extends File and provides read/write/seek
-capabilities to a memory buffer. It extends File with those words:
-
-:new ( sz -- hdl )
- Allocate a new buffer of size "sz" and return it.
-
-:buf( ( hdl -- a )
- Address of the buffer.
-
-:)buf ( hdl -- a )
- Address following the last byte of the buffer.
-
-:ptr ( hdl -- a )
- Address corresponding to current position.
-
-## File loading shortcuts
-
-Feeding the Forth intepreter with the contents of a file is something you'll
-want to do fairly often, which might not sit well with the verbosity of Path's
-API. A shortcut to finding a Path and then loading it is "f<<". This word,
-followed by a path to load in the input stream, with call :fload on that path.
-
-It happens frequently that some piece of code depends on some other so we want
-to load these files first. However, some units are depended upon by more than
-one units and we don't want to load these pieces of code twice. To this end,
-whenever a file is loaded, we record its ID in a linked list to remember we
-loaded it. If you use the "?f<<" word instead of "f<<", the specified file will
-be loaded only if it wasn't already loaded.
diff --git a/fs/doc/color.txt b/fs/doc/gr/color.txt
diff --git a/fs/doc/gr/rect.fs b/fs/doc/gr/rect.fs
@@ -0,0 +1,56 @@
+# Rectangles
+
+Provides a Rect structure that helps with operations on rectangles.
+
+## API
+
+Fields:
+
+x
+y
+width
+height
+
+:new ( x y width height -- rect )
+ Allocate a new rectangle with specified values.
+
+:tmpnew ( x y width height -- rect )
+ Allocate new rectangle in system scratchpad (doc/lib/alloc).
+
+:topleft ( self -- x y )
+ Top-left point of the rectangle.
+
+:bottomright ( self -- x y )
+ Bottom-right point of the rectangle.
+
+:= ( other self -- f )
+ Whether the rectangle has the same field values as "other".
+
+:null? ( self -- f )
+ Whether the rectangle has a 0 width or height.
+
+:haspoint? ( x y self -- f )
+ Whether coordinates "x,y" are inside the rectangle.
+
+:hasrect? ( other self -- f )
+ Wether rectangle "other" is entirely contained (can be equal) in rectangle
+ "self".
+
+:intersects? ( other self -- f )
+ Whether one part of "other" intersects with "self" (can be contained).
+
+:intersection ( other self -- rect )
+ Yields a rectangle (created with :tmpnew) that represents the intersection of
+ "other" and "self". If there is no intersection, will yield a null rectangle.
+
+:copy ( other self -- )
+ Copy values in all fields of "other" into "self".
+
+:move ( x y self -- )
+ Move "self"'s top-left point to "x,y".
+
+:resize ( width height self -- )
+ Resize "self" to "width,height".
+
+:print ( self -- )
+ Print a human readable representation of "self".
diff --git a/fs/doc/grid.txt b/fs/doc/grid.txt
@@ -1,75 +0,0 @@
-# Grid subsystem
-
-The grid is a matrix of characters that represents what is seen on a screen. It
-has a fixed number of columns (COLS) and lines (LINES) and maintains a current
-position (pos) as a single number encoded as "y*COLS+x".
-
-The grid is implemented as a IO structure extending ByteWriter (see doc/io). Its
-"pos" field is the "cursor" position on the screen and the IO screen represents
-the terminal screen: whenever a byte is written to it through the IO methods,
-the character is written at cursor position and that cursor is advanced by one.
-
-If a NL character ($0a) is written to it, the grid skips to the next line. If a
-BS character ($08) is written to it, the cursor goes back one character.
-
-In newline conditions (NL character or wrapping around the end of line), we
-clear the next line and move the cursor there. If we're at the end of the
-screen, we scroll if the underlying driver allows it. Otherwise, we wrap around
-to the top.
-
-The grid subsystem defines the Grid structure as well as a "grid" structbind to
-it. During initialization, what you'll want to do is create an instance of the
-Grid from the driver and bind it to "grid".
-
-## Spit mode
-
-Sometimes, we want to write things to screen that are at a position other than
-the cursor and we don't want to update the cursor while writing there. Moreover,
-we don't want the special handling of the regular mode (newline handling). One
-such example is the ":dbgnum1!" word.
-
-In these cases, you'll want to enable the "spit" mode with ":spiton", do your
-thing, then go back to regular mode with ":spitoff".
-
-## Driver implementation
-
-To implement the grid, we need an underlying driver to extend it and implement
-its methods, namely:
-
-:cell! ( c pos -- )
- Set content of the cell at "pos" to character "c".
-
-:cursor! ( pos -- )
- Move cursor to "pos".
-
-:newln ( oldln -- newln )
- Prepare new line under line number "newln" and return the line number of that
- prepared line as "newln". Normally, "newln" is "oldln+1", but if scrolling is
- involved, then "newln" will be "oldln".
-
-## API
-
-:pcell! ( c self -- )
- Set content of the cell at current pos to character "c".
-
-:clrline ( ln self -- )
- Set all cells in line number "ln" to spaces.
-
-:linefeed ( self -- )
- Clear a new line below the current one, scrolling if needed, then set pos to
- the beginning of that line
-
-:spiton ( pos self -- )
- Enable "spit mode" starting at position "pos". This doesn't affect regular
- position.
-
-:spitoff ( self -- )
- Disable "spit mode".
-
-:dbgnum1! ( n self -- )
- Spit "n", formatted with ".x", at the top right corner of the screen. Useful
- for debugging purposes. To debug live numbers, you can combine this with
- sys/loop.
-
-:dbgnum2! ( n self -- )
- Same as :dbgnum1!, but one slot to the left.
diff --git a/fs/doc/index.txt b/fs/doc/index.txt
@@ -13,6 +13,10 @@ If you're reading this from a Dusk system, then you're ready to read doc/usage.
## Contents of this documentation
+Documentation about specific units have the same path in the documentation as
+they have in the system and are not listed below. For example, for documentation
+about sys/io, you'll want to open doc/sys/io.
+
usage General usage guide
dict Dictionary of system word
install Deploy Dusk to another machine
@@ -21,11 +25,6 @@ dirs Directory structure
arch Architecture details
impl Implementation details
code Code conventions
-io I/O API
-drive Drive API
-file File API
-alloc Memory allocation API
-ps2 PS/2 subsystem
x86 i386 implementation details
asm/ Assemblers documentation
cc/ C compiler documentation
diff --git a/fs/doc/alloc.txt b/fs/doc/lib/alloc.txt
diff --git a/fs/doc/rect.fs b/fs/doc/rect.fs
@@ -1,56 +0,0 @@
-# Rectangles
-
-Provides a Rect structure that helps with operations on rectangles.
-
-## API
-
-Fields:
-
-x
-y
-width
-height
-
-:new ( x y width height -- rect )
- Allocate a new rectangle with specified values.
-
-:tmpnew ( x y width height -- rect )
- Allocate new rectangle in system scratchpad (doc/alloc).
-
-:topleft ( self -- x y )
- Top-left point of the rectangle.
-
-:bottomright ( self -- x y )
- Bottom-right point of the rectangle.
-
-:= ( other self -- f )
- Whether the rectangle has the same field values as "other".
-
-:null? ( self -- f )
- Whether the rectangle has a 0 width or height.
-
-:haspoint? ( x y self -- f )
- Whether coordinates "x,y" are inside the rectangle.
-
-:hasrect? ( other self -- f )
- Wether rectangle "other" is entirely contained (can be equal) in rectangle
- "self".
-
-:intersects? ( other self -- f )
- Whether one part of "other" intersects with "self" (can be contained).
-
-:intersection ( other self -- rect )
- Yields a rectangle (created with :tmpnew) that represents the intersection of
- "other" and "self". If there is no intersection, will yield a null rectangle.
-
-:copy ( other self -- )
- Copy values in all fields of "other" into "self".
-
-:move ( x y self -- )
- Move "self"'s top-left point to "x,y".
-
-:resize ( width height self -- )
- Resize "self" to "width,height".
-
-:print ( self -- )
- Print a human readable representation of "self".
diff --git a/fs/doc/sys/file.txt b/fs/doc/sys/file.txt
@@ -0,0 +1,232 @@
+# File subsystem
+
+The file subsystem allows the system to interact with filesystems.
+
+Files and directories all live within filesystems. More than one filesystem can
+be active at once and each of these filesystems is designated by a letter. For
+example, the boot filesystem is always "A". There's a maximum of 26 active
+filesystems.
+
+Filesystems contain files and directories. A file is a blob of data that exists
+within a directory. A directory is a container for files and other directories.
+Each filesystem has one root directory.
+
+Files and directories are referred to with strings of characters that we call
+"paths". Those paths begin with a filesystem identifier, followed by name of
+directory and file. A directory name can be followed by a "/" character to
+indicate that we want to refer to one of its children.
+
+There is also the concept of an "active" directory. When paths don't start with
+a drive letter, the path is relative to this active directory. A path starting
+with "/" refers to the root directory of the active directory's filesystem. The
+initial active directory is the boot filesystem's root directory (A:).
+
+Examples:
+
+A: root of filesystem A
+A:foo.txt file "foo.txt" inside A's root directory
+B:foo/bar.fs file "bar.fs" inside "foo" directory inside B's root
+bar.fs file "bar.fs" in active directory
+/foo.fs file "foo.fs" in active filesystem's root directory
+
+## Filesystem API
+
+When the code refers to a filesystem, it does so through a definite structure:
+
+drv -- Drive pointer (see doc/drive)
+
+:child ( dirid name fs -- id )
+ Enumerate the contents of directory "dirid" and look for name "name". If
+ found, returns the ID of the child (either a file or directory), otherwise,
+ return 0. See below for the concept of "ID".
+
+:info ( id fs -- info )
+ Returns a FSInfo structure (described below) corresponding to the specified
+ ID. This structure is a singleton and is only valid until the next :info call.
+
+:open ( id fs -- hdl )
+ Open file at path and return a handle through which other file-related word
+ identify the target file. Once a file isn't used anymore, it should be
+ closed with :close. Aborts on error.
+
+:iter ( w id fs -- )
+ Iterate through all children of directory "id", ignoring "." and ".." entries.
+ For each child iterated upon, call word "w" which has the signature
+ "id fs --", "id" being the ID of the child.
+
+:newfile ( dirid name fs -- id )
+ Create a new empty file named "name" in "dirid" and return the ID of the new
+ file. Aborts on error.
+
+:newdir ( dirid name fs -- id )
+ Create a new directory named "name" in "dirid" and return the ID of the new
+ directory. Aborts on error.
+
+... followed by whatever data the FS implementation needs.
+
+In each method, "fs" refers to a filesystem, a pointer to the structure decribed
+above.
+
+Additionally, the Filesystem struct also has these convenience methods which are
+independent of the underlying implementation:
+
+:?newfile ( dirid name fs -- id )
+ Create a new file if it doesn't exist. If it exists, return its ID.
+
+:?newdir ( dirid name fs -- id )
+ Create a new directory if it doesn't exist. If it exists, return its ID.
+
+## File API
+
+The File API is a specialization of the I/O API (doc/sys/io) for accessing files
+in a filesystem. It also works with "handles", which we call a File handle. Of
+course, it starts with the I/O prelude, but then adds its own prelude:
+
+(I/O prelude)
+:seek
+
+These words have the following meaning:
+
+:seek ( pos hdl -- )
+ Place the handle at offset "pos" (in bytes).
+
+## FSInfo API
+
+The structure returned by ":info" above goes as follows:
+
+name -- a pointer to a string
+size -- size of the file, or 0 for a directory
+dir? -- whether the element is a directory
+
+## Path API
+
+The Path structure represents a path from any of the currently mounted
+filesystems. It has 2 fields: "fs", which is a pointer to a Filesystem struct
+and "id", which is the FS ID corresponding to the path. Path allocations are
+managed through a small "rolling" buffer, which means that if you want to hold
+on to a Path reference a little longer, you should copy it elsewhere.
+
+:new ( fs id -- path )
+ Allocate a new Path reference with the specified fields
+
+:find ( str -- path-or-0 )
+ Find FS ID corresponding to path and return Path reference or 0 if not found.
+
+:find# ( str -- path )
+ Like :find, but errors out if not found.
+
+:fload ( self -- )
+ Open specified path and interpret it as Forth source.
+
+:floaded? ( self -- f )
+ Returns whether this particular path has ever been loaded with :fload.
+
+:chdir ( self -- )
+ Change current directory to path. In subsequent path finds, if the path
+ doesn't start with "/", the search will start from this directory.
+ Aborts if path is not found.
+
+:open ( self -- file )
+:info ( self -- file )
+:child ( name self -- path-or-0 )
+:iter ( w self -- )
+ Convenience proxies to the corresponding methods in the Filesystem API.
+
+:iterdirs ( w self -- )
+ Calls :iter but filters the call to 'w' to directories only. On top of this,
+ an additional "info" argument is passed to 'w', making its signature
+ "id fs info -- "
+
+:iterfiles ( w self -- )
+ Same as :iterdirs, but for files.
+
+## Global variables
+
+The File subsystem has 2 important global variables:
+
+bootfs is a pointer to the Filesystem structure from which the system was
+booted. It's used only until the File subsystem is initialized.
+
+curpath is a Path bind that points to the "current directory". It is initialized
+to the root directory of bootfs but can be changed with Path :chdir.
+
+## Paths
+
+Paths uniquely identify a directory or a file on the current set of mounted
+filesystems. Paths can take 3 forms: absolute, FS relative and relative.
+
+Absolute paths begin with a drive letter ("A" is the boot drive, "B" is the
+second one, etc.) followed by ":", followed by a relative path. Example:
+
+a:lib/str.fs
+
+FS relative are path relative to the currently "active" filesystem, that is, the
+filesystem that contains the "current directory". Such paths begin by a "/"
+followed by a relative path. Example:
+
+/lib/str.fs
+
+Relative paths are paths relative to the "current directory". These paths begin
+directly with a name. Example for a "current directory" set to "/lib":
+
+str.fs
+
+## File ID design considerations
+
+When we refer to a file or directory ID, we refer to a single 32-bit number
+uniquely identifying the file or directory in the volume. From this number, we
+must be able to find the file or directory in the volume so that we can open it
+or enumerate it. The ID of the root directory is always zero.
+
+That IDs are 32-bit make their manipulation straightforward. One might fear that
+32 bits are not enough to identify all elements of big filesystems.
+
+On many filesystems, 32 bits are enough. For example, in ext4, inodes always fit
+32 bits, even in 64-bit mode.
+
+For FAT32, it's another matter. The straightforward way to derive an ID from an
+element is to return the offset of its DirEntry and divide it by 32. This means
+that this ID scheme could only address 64GB volumes.
+
+This would mean that the File API would be broken on a subset of filesystems.
+Does it mean that Dusk couldn't read them? No, only that file/dir enumeration
+would have to go through FS-specific tools. I think that this inconvenience is
+worth it if it means an overall simpler API.
+
+## Path literals
+
+There are 2 words for Path/File shortcuts: p" and f".
+
+p" foo" is a shortcut for S" foo" curpath :find# and f" foo" is a shortcut for
+p" foo" Path :open.
+
+## MemFile
+
+MemFile is a structure that extends File and provides read/write/seek
+capabilities to a memory buffer. It extends File with those words:
+
+:new ( sz -- hdl )
+ Allocate a new buffer of size "sz" and return it.
+
+:buf( ( hdl -- a )
+ Address of the buffer.
+
+:)buf ( hdl -- a )
+ Address following the last byte of the buffer.
+
+:ptr ( hdl -- a )
+ Address corresponding to current position.
+
+## File loading shortcuts
+
+Feeding the Forth intepreter with the contents of a file is something you'll
+want to do fairly often, which might not sit well with the verbosity of Path's
+API. A shortcut to finding a Path and then loading it is "f<<". This word,
+followed by a path to load in the input stream, with call :fload on that path.
+
+It happens frequently that some piece of code depends on some other so we want
+to load these files first. However, some units are depended upon by more than
+one units and we don't want to load these pieces of code twice. To this end,
+whenever a file is loaded, we record its ID in a linked list to remember we
+loaded it. If you use the "?f<<" word instead of "f<<", the specified file will
+be loaded only if it wasn't already loaded.
diff --git a/fs/doc/sys/grid.txt b/fs/doc/sys/grid.txt
@@ -0,0 +1,76 @@
+# Grid subsystem
+
+The grid is a matrix of characters that represents what is seen on a screen. It
+has a fixed number of columns (COLS) and lines (LINES) and maintains a current
+position (pos) as a single number encoded as "y*COLS+x".
+
+The grid is implemented as a IO structure extending ByteWriter (see doc/sys/io).
+Its "pos" field is the "cursor" position on the screen and the IO screen
+represents the terminal screen: whenever a byte is written to it through the IO
+methods, the character is written at cursor position and that cursor is advanced
+by one.
+
+If a NL character ($0a) is written to it, the grid skips to the next line. If a
+BS character ($08) is written to it, the cursor goes back one character.
+
+In newline conditions (NL character or wrapping around the end of line), we
+clear the next line and move the cursor there. If we're at the end of the
+screen, we scroll if the underlying driver allows it. Otherwise, we wrap around
+to the top.
+
+The grid subsystem defines the Grid structure as well as a "grid" structbind to
+it. During initialization, what you'll want to do is create an instance of the
+Grid from the driver and bind it to "grid".
+
+## Spit mode
+
+Sometimes, we want to write things to screen that are at a position other than
+the cursor and we don't want to update the cursor while writing there. Moreover,
+we don't want the special handling of the regular mode (newline handling). One
+such example is the ":dbgnum1!" word.
+
+In these cases, you'll want to enable the "spit" mode with ":spiton", do your
+thing, then go back to regular mode with ":spitoff".
+
+## Driver implementation
+
+To implement the grid, we need an underlying driver to extend it and implement
+its methods, namely:
+
+:cell! ( c pos -- )
+ Set content of the cell at "pos" to character "c".
+
+:cursor! ( pos -- )
+ Move cursor to "pos".
+
+:newln ( oldln -- newln )
+ Prepare new line under line number "newln" and return the line number of that
+ prepared line as "newln". Normally, "newln" is "oldln+1", but if scrolling is
+ involved, then "newln" will be "oldln".
+
+## API
+
+:pcell! ( c self -- )
+ Set content of the cell at current pos to character "c".
+
+:clrline ( ln self -- )
+ Set all cells in line number "ln" to spaces.
+
+:linefeed ( self -- )
+ Clear a new line below the current one, scrolling if needed, then set pos to
+ the beginning of that line
+
+:spiton ( pos self -- )
+ Enable "spit mode" starting at position "pos". This doesn't affect regular
+ position.
+
+:spitoff ( self -- )
+ Disable "spit mode".
+
+:dbgnum1! ( n self -- )
+ Spit "n", formatted with ".x", at the top right corner of the screen. Useful
+ for debugging purposes. To debug live numbers, you can combine this with
+ sys/loop.
+
+:dbgnum2! ( n self -- )
+ Same as :dbgnum1!, but one slot to the left.
diff --git a/fs/doc/io.txt b/fs/doc/sys/io.txt
diff --git a/fs/doc/loop.txt b/fs/doc/sys/loop.txt
diff --git a/fs/doc/mouse.txt b/fs/doc/sys/mouse.txt
diff --git a/fs/doc/ps2.txt b/fs/doc/sys/ps2.txt
diff --git a/fs/doc/screen.fs b/fs/doc/sys/screen.fs
diff --git a/fs/doc/usage.txt b/fs/doc/usage.txt
@@ -404,11 +404,11 @@ to add some complexity on the I/O front: the need to have redirectable and
abstract I/Os for applications and the need to have a console that reads line by
line.
-In the middle of the boot process, sys/io is loaded (see doc/io). This subsystem
-introduces the StdIn and StdOut structures (with their "stdin" ( -- c ) and
-"stdout" ( c -- ) proxies) and, by default, plugs new ConsoleIn and ConsoleOut
-structures into them. These structures simply plug themselves into "key" and
-"emit".
+In the middle of the boot process, sys/io is loaded (see doc/sys/io). This
+subsystem introduces the StdIn and StdOut structures (with their "stdin" ( -- c
+) and "stdout" ( c -- ) proxies) and, by default, plugs new ConsoleIn and
+ConsoleOut structures into them. These structures simply plug themselves into
+"key" and "emit".
From that point on, the system interpret loop feeds itself from "stdin". "emit"
and "stdout" become synonymous, the latter being preferred. "emit" becomes the
@@ -422,6 +422,6 @@ a whole line is ready to be interpreted, that is fed to stdin.
## Loading files
Dusk's interpreter can be fed with the contents of files through various words
-such as :fload, f<< and ?f<<. Refer to doc/file.
+such as :fload, f<< and ?f<<. Refer to doc/sys/file.
If you want to compile C source files, you'll want to look at doc/cc.
diff --git a/fs/gr/color.fs b/fs/gr/color.fs
@@ -1,5 +1,3 @@
-\ Color encodings. see doc/color
-
$01 const COLOR_RGB24
: r8g8b8>rgb24 ( r8 g8 b8 -- n ) swap 8 lshift or swap 16 lshift or ;
diff --git a/fs/gr/rect.fs b/fs/gr/rect.fs
@@ -1,4 +1,3 @@
-\ Rectangles. see doc/rect
require /sys/scratch.fs
struct[ Rect
diff --git a/fs/sys/file.fs b/fs/sys/file.fs
@@ -1,4 +1,3 @@
-\ File subsystem, see doc/file
0 S" sys" bootfs Filesystem :child S" io.fs" bootfs Filesystem :child
bootfs swap fload
diff --git a/fs/sys/mouse.fs b/fs/sys/mouse.fs
@@ -1,5 +1,3 @@
-\ Mouse subsystem. see doc/mouse
-
struct[ Mouse
$01 const BTN_LEFT
$02 const BTN_RIGHT
diff --git a/fs/sys/screen.fs b/fs/sys/screen.fs
@@ -1,5 +1,3 @@
-\ Screen subsystem. see doc/screen
-
struct[ Screen
sfield width
sfield height