docs: rename doc/ to Documentation/, add incremental org export
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sat, 10 Oct 2026 18:44:53 +0000 (21:44 +0300)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sat, 10 Oct 2026 18:44:53 +0000 (21:44 +0300)
- Rename doc/ to Documentation/ via git mv (history preserved) to match
  the house convention; update AGENTS.md references accordingly.
- "Tools/Update web site" now exports via the shared incremental
  exporter (svjatoslav_commons/Tools/Org export incremental): only
  changed Documentation/*.org pages are re-exported, in one Emacs
  batch process; .org-export-state added to .gitignore.
- Expand opcodes 20-29 documentation: per-opcode descriptions, stack
  effects, notes and examples in Documentation/opcodes_20_29.org,
  mirrored as comment blocks in emulator/opcodes_20_29.asm.

30 files changed:
.gitignore
AGENTS.md
Documentation/5TH_ET.txt [new file with mode: 0644]
Documentation/index.org [new file with mode: 0644]
Documentation/language.org [new file with mode: 0644]
Documentation/numbers.png [new file with mode: 0644]
Documentation/opcodes_00_09.org [new file with mode: 0644]
Documentation/opcodes_10_19.org [new file with mode: 0644]
Documentation/opcodes_20_29.org [new file with mode: 0644]
Documentation/opcodes_30_39.org [new file with mode: 0644]
Documentation/opcodes_40_49.org [new file with mode: 0644]
Documentation/screenshots/dictionary.png [new file with mode: 0644]
Documentation/screenshots/start.png [new file with mode: 0644]
Documentation/screenshots/text editor.png [new file with mode: 0644]
Documentation/virtual machine.org [new file with mode: 0644]
Tools/Update web site
doc/5TH_ET.txt [deleted file]
doc/index.org [deleted file]
doc/language.org [deleted file]
doc/numbers.png [deleted file]
doc/opcodes_00_09.org [deleted file]
doc/opcodes_10_19.org [deleted file]
doc/opcodes_20_29.org [deleted file]
doc/opcodes_30_39.org [deleted file]
doc/opcodes_40_49.org [deleted file]
doc/screenshots/dictionary.png [deleted file]
doc/screenshots/start.png [deleted file]
doc/screenshots/text editor.png [deleted file]
doc/virtual machine.org [deleted file]
emulator/opcodes_20_29.asm

index 90a65f0..3646344 100755 (executable)
@@ -3,3 +3,6 @@ bin/
 
 .aider*
 *.html
+
+# Incremental org export cache (Tools/Update web site)
+.org-export-state
index 35e5a23..e0496ef 100644 (file)
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -110,10 +110,10 @@ Write standard ASCII when editing; conversion tools handle encoding.
 
 # Documentation
 
-- `doc/index.org` — Project overview, installation, architecture
-- `doc/language.org` — Complete Fifth language reference
-- `doc/virtual machine.org` — Virtual CPU architecture
-- `doc/opcodes_00_09.org` through `doc/opcodes_40_49.org` — Opcode details
+- `Documentation/index.org` — Project overview, installation, architecture
+- `Documentation/language.org` — Complete Fifth language reference
+- `Documentation/virtual machine.org` — Virtual CPU architecture
+- `Documentation/opcodes_00_09.org` through `Documentation/opcodes_40_49.org` — Opcode details
 
 # File Organization
 
@@ -122,7 +122,7 @@ emulator/        # x86 real-mode assembly (FASM)
 kernel/          # Virtual CPU assembly
 imageFile/f/     # Fifth source files (FSCII encoded)
 imageFile/f/lib/ # Fifth libraries
-doc/             # Org-mode documentation (edit .org, not .html)
+Documentation/   # Org-mode documentation (edit .org, not .html)
 Tools/           # QuickBASIC utilities for file conversion
 floppy image/    # QEMU scripts, disk images
 ```
@@ -134,7 +134,7 @@ floppy image/    # QEMU scripts, disk images
 1. Implement in `emulator/opcodes_XX_XX.asm`
 2. Add entry to dispatch table in `emulator/emulator.asm`
 3. Add macro in `kernel/define.asm`
-4. Document in `doc/opcodes_XX_XX.org`
+4. Document in `Documentation/opcodes_XX_XX.org`
 5. Add high-level word in `imageFile/f/5th_boot` if needed
 
 ## Adding a New Fifth Word
diff --git a/Documentation/5TH_ET.txt b/Documentation/5TH_ET.txt
new file mode 100644 (file)
index 0000000..7fde517
--- /dev/null
@@ -0,0 +1,269 @@
+.( loading editor ) update\r
+.( done        )\r
+.( ETh - for text editor help )\r
+\r
+var handletxt\r
+var handlebuf\r
+Dstralloc const        editfile\r
+var shiftx  var        shifty\r
+var curlocx var        curlocy\r
+Dstr \listF\TXT_ET" tmphelpfile\r
+\r
+: disppage ( --        )\r
+handletxt @\r
+dynp shifty @ 50 * +\r
+0 1 at!\r
+1270 type ;\r
+\r
+: fclose (  close opened file )\r
+handletxt @ dup        if dynde handletxt off else drop then ;\r
+\r
+: ETnewpage fclose 27100 dynal dup handletxt ! dynp\r
+FF swap        27100 cfill ;\r
+\r
+var tmp1\r
+: fopen        ( strhand -- )\r
+fclose\r
+dup editfile Dstr2Dstr fsDloadnew dup push dynp        ( addrinp       R: handinp )\r
+27100 dynal dup        handletxt ! dynp        ( addrinp addrout       R: handinp )\r
+FF over        27100 cfill\r
+tmp1 off\r
+i dyns do              ( addrinp addrout )\r
+over c@                        ( addrinp addrout c )\r
+dup FE = if\r
+       drop\r
+       50 tmp1 @ - + tmp1 off\r
+else\r
+       dup FD = if\r
+               drop tmp1 @ tab ( addrinp addrout numspaces )\r
+               tmp1 @ over + tmp1 ! + 0\r
+       else\r
+               over c! 1+ 0\r
+               tmp1 @ 1+ tmp1 !\r
+       then\r
+       drop\r
+then\r
+swap 1+        swap\r
+loop 2drop\r
+pop dynde ; rh tmp1\r
+\r
+: dispchar ( x y -- )\r
+2dup\r
+swap shiftx @ -\r
+swap shifty @ -        1+\r
+at!\r
+50 * + handletxt @ dynp        + c@ emit ;\r
+\r
+: dispcur curlocx @ curlocy @ dispchar ;\r
+\r
+: displine ( line )\r
+0 over shifty @        - 1+ at!\r
+50 * handletxt @ dynp +        shiftx @ + 50 type ;\r
+\r
+: dispstatbar\r
+colneg\r
+0 0 at!        50 do space loop\r
+0 0 at!        ." col:" curlocx @ .\r
+7 0 at!        ." line:" curlocy @ .\r
+11 0 at! ." ascii:" curlocy @ 50 * curlocx @ + handletxt @ dynp        + c@ .\r
+1B 0 at! ." file:" editfile Dstr.\r
+49 0 at! ." F1-help"\r
+colnorm        ;\r
+\r
+: charins ( char x y )\r
+50 * handletxt @ dynp +                ( char x addr )\r
+over push\r
++ dup dup 1+ 4F        pop - cmove     ( char addr )\r
+c! ;\r
+\r
+: charcut ( x y        -- char )\r
+over push\r
+50 * handletxt @ dynp +        +\r
+dup c@ swap                    ( char addr )\r
+dup dup        1+ swap                 ( char addr addr+1 addr )\r
+4F pop - dup push cmove                ( char addr )\r
+pop + FF swap c! ;\r
+\r
+: lineins ( line )\r
+50 * dup push handletxt        @ dynp +                ( addr )\r
+dup dup        50 + handletxt @ dyns 50 - pop - cmove  ( addr )\r
+FF swap        50 cfill ;\r
+\r
+: linecut ( line )\r
+50 * dup push handletxt        @ dynp +                ( addr )\r
+dup 50 + swap handletxt        @ dyns 50 - pop - cmove ;\r
+\r
+: screenaim\r
+0 curlocy @ 1E - 794 bound shifty !\r
+disppage ;\r
+\r
+var tmp1\r
+: length       ( line -- length )\r
+50 * 4F        + handletxt @ dynp +    ( addr )\r
+51 do\r
+       i tmp1 !\r
+       dup c@ FF - if pop drop 0 push then\r
+       1-\r
+loop\r
+drop\r
+tmp1 @ ; rh tmp1\r
+\r
+var tmp2 var tmp3\r
+: fsavechar ( char ) tmp2 @ swap over c! 1+ tmp2 ! ;\r
+: fsave        ( -- )\r
+27200 dynal dup        dynp tmp2 !\r
+0\r
+7CF do\r
+       i length if drop pop 1+ 0 push then\r
+loop\r
+0 swap for             ( desthand )\r
+       tmp3 off\r
+       i 50 * handletxt @ dynp +\r
+       0 i length for  ( desthand srcaddr )\r
+               dup c@\r
+               i tab 8 = if tmp3 @ if FD fsavechar tmp3 off then then\r
+               dup FF = if\r
+                       drop tmp3 @ 1+ tmp3 !\r
+               else\r
+                       tmp3 @ do FF fsavechar loop tmp3 off\r
+                       fsavechar\r
+               then\r
+               1+\r
+       loop drop\r
+       FE fsavechar\r
+loop\r
+tmp2 @ over dynp - over        dynresize\r
+dup editfile fsDsave\r
+dynde ;        rh tmp2 rh tmp3\r
+\r
+str TXT_default" tmpdefault\r
+\r
+: ET\r
+handletxt @ if\r
+disppage\r
+until\r
+       colneg dispcur dispstatbar KBD_FW@ colnorm dispcur\r
+\r
+       dup 415 = if                                            ( DEL )\r
+               curlocx @ curlocy @ charcut drop\r
+               curlocy @ displine\r
+       then\r
+\r
+       dup FC = if                                             ( BACKSPACE )\r
+       curlocx @ if\r
+               curlocx @ 1- curlocy @ charcut drop\r
+               curlocy @ displine\r
+               drop 413\r
+       else\r
+               curlocy @ if\r
+                       curlocy @ 1- dup length dup curlocx !   ( y-1 strlen )\r
+                       swap 50 * handletxt @ dynp +    ( strlen y1addr )\r
+                       2dup + swap 50 +                ( strlen dest src )\r
+                       swap rot 50 swap - cmove\r
+                       curlocy @ linecut\r
+                       drop 410\r
+                       disppage\r
+               then\r
+       then\r
+       then\r
+\r
+       dup FD = if                                             ( TAB )\r
+               curlocx @ tab\r
+               dup do FF curlocx @ curlocy @ charins loop\r
+               curlocx @ + curlocx !\r
+               curlocy @ displine\r
+       then\r
+\r
+       dup FE = if                                             ( ENTER )\r
+               curlocy @ 7CF < if\r
+                       curlocy @ 1+ lineins\r
+                       curlocx @ 0\r
+                       50 curlocx @ - do\r
+                               over curlocy @ charcut\r
+                               over curlocy @ 1+ charins\r
+                               1+\r
+                       loop 2drop\r
+                       curlocx off\r
+                       drop 412\r
+                       disppage\r
+               then\r
+       then\r
+\r
+       dup 418 = if curlocy @ 3A - curlocy ! then              ( PG-UP )\r
+       dup 419 = if curlocy @ 3A + curlocy ! then              ( PG-DOWN )\r
+       dup 416 = if curlocx off then                           ( HOME )\r
+       dup 417 = if curlocy @ length curlocx ! then            ( END )\r
+       dup 401 = if tmphelpfile fsdisp disppage then           ( F1 )\r
+       dup 402 = if fsave then                                 ( F2 )\r
+       dup 403 = if fclose drop 1B then                        ( F3 )\r
+       dup 400 = if done 0 0 at! screen cls drop -1 then       ( ESC )\r
+\r
+       0 over F0 bound? if -1 else 0 then                      ( NORMAL KEY )\r
+       over FF = if drop -1 then\r
+       if\r
+               curlocx @ curlocy @ charins\r
+               curlocy @ displine\r
+               411\r
+       then\r
+\r
+       dup 411 = if curlocx @ 1+ curlocx ! then               ( RIGHT )\r
+       dup 413 = if curlocx @ 1- curlocx ! then               ( LEFT )\r
+       dup 412 = if curlocy @ 1+ curlocy ! then               ( DOWN )\r
+       dup 410 = if curlocy @ 1- curlocy ! then               ( UP )\r
+       drop\r
+\r
+       0 curlocx @ 4F bound curlocx !\r
+       0 curlocy @ 7CF bound curlocy !\r
+\r
+       curlocy @ shifty @ - 3B > if screenaim then\r
+\r
+       curlocy @ shifty @ - 3B - 0 = if\r
+               0 0 8 screen scrollf\r
+               shifty @ 1+ shifty !\r
+               curlocy @ displine\r
+       then\r
+\r
+       curlocy @ shifty @ - -1 < if screenaim then\r
+\r
+       curlocy @ shifty @ - 1+ 0 = if\r
+               0 0 -8 screen scrollf\r
+               shifty @ 1- shifty !\r
+               curlocy @ displine\r
+       then\r
+\r
+loop\r
+else\r
+       tmpdefault editfile str2Dstr\r
+       ETnewpage\r
+       ET\r
+then ;\r
+\r
+: ETl\r
+fopen\r
+curlocx        off\r
+curlocy        off\r
+shiftx off\r
+shifty off\r
+ET ;\r
+\r
+: ETs\r
+editfile Dstr2Dstr\r
+fsave ." saved " ;\r
+\r
+: ETh tmphelpfile fs. ;\r
+\r
+rh handletxt\r
+rh handlebuf\r
+rh editfile\r
+rh shiftx rh shifty\r
+rh curlocx rh curlocy\r
+rh tmphelpfile\r
+rh disppage\r
+rh fclose rh fopen\r
+rh dispchar rh dispcur\r
+rh displine rh dispstatbar\r
+rh charins rh charcut\r
+rh lineins rh linecut\r
+rh screenaim rh        length\r
+rh fsavechar rh        fsave\r
+rh ETnewpage rh        tmpdefault\r
diff --git a/Documentation/index.org b/Documentation/index.org
new file mode 100644 (file)
index 0000000..fedd6a9
--- /dev/null
@@ -0,0 +1,359 @@
+#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
+#+TITLE: Fifth - virtual machine, operating system, programming language
+#+LANGUAGE: en
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+  .flex-center {
+    display: flex;            /* activate flexbox */
+    justify-content: center;  /* horizontally center anything inside   */
+  }
+
+  .flex-center video {
+    width: min(90%, 1000px); /* whichever is smaller wins */
+    height: auto;            /* preserve aspect ratio */
+  }
+
+  .responsive-img {
+    width: min(100%, 1000px);
+    height: auto;
+  }
+</style>
+#+end_export
+
+
+* General
+- This program is free software: released under Creative Commons Zero
+  (CC0) license
+
+- Program author:
+  - Svjatoslav Agejenko
+  - Homepage: https://svjatoslav.eu
+  - Email: mailto://svjatoslav@svjatoslav.eu
+
+- [[https://www.svjatoslav.eu/projects/][Other software projects hosted at svjatoslav.eu]]
+
+** Source code
+- [[https://www2.svjatoslav.eu/gitweb/?p=fifth.git;a=snapshot;h=HEAD;sf=tgz][Download latest snapshot in TAR GZ format]]
+
+- [[https://www2.svjatoslav.eu/gitweb/?p=fifth.git;a=summary][Browse Git repository online]]
+
+- Clone Git repository using command:
+  : git clone https://www3.svjatoslav.eu/git/fifth.git
+
+* Introduction
+
+Fifth is self-hosting hobby computing environment that integrates a
+[[id:9b251eb9-aff6-4025-94bf-25e89e26d54a][custom virtual machine]], a [[id:da7fff9b-0b67-4843-828a-52a404d7f401][Forth-inspired programming language]], and
+operating system.
+
+At its core lies a stack-based virtual CPU with two stacks (data and
+return), approximately 50 instructions, and a 4GB flat address
+space. This virtual machine executes the Fifth language — a concise,
+interactive, and extensible environment where every operation is a
+command that can be defined, redefined, or extended by the user. The
+language uses a custom character encoding (FSCII) with unique
+representations for control characters (e.g., space as FF instead of
+20 in ASCII) and features an innovative hexadecimal number system
+visualized as squares split into four triangles, each representing a
+single bit—similar to Bibi-binary.
+
+It includes a disk-based filesystem, a built-in text editor, 2D
+graphics capabilities, mouse and keyboard drivers, and tools for file
+management and memory allocation.
+
+Released under the CC0 public domain license, Fifth is free for anyone
+to use, study, and modify. Whether you're a retro computing
+enthusiast, a systems programming student, or a curious developer.
+
+** Screenshots
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:screenshots/start.png]]
+
+Startup screen diplaying Fifth logo and full file list.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:screenshots/dictionary.png]]
+
+Sample words defined. Most of the words are commands that can be
+executed interactively from the command line or from a file. When
+executed, they can be selectively compiled or interpreted.
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:screenshots/text editor.png]]
+
+Built in text editor.
+
+* Installation
+Just unpack all files, witout altering original directory structure,
+somewhere in your hard disk. For example:
+
+: C:\MISC\FIFTH\
+
+To run fifth you need minimally just 2 files:
+- EMULATOR.COM :: Virtual CPU emulator
+- DISK.RAW :: Virtual disk file
+
+For more information, please refer to [[id:0759f3e0-28bb-4901-9e4f-09ef41732173][Fifth distribution directory
+tree description]].
+
+* Fifth distribution directory tree description
+:PROPERTIES:
+:CUSTOM_ID: ID-0759f3e0-28bb-4901-9e4f-09ef41732173
+:ID:       0759f3e0-28bb-4901-9e4f-09ef41732173
+:END:
+After downloading and unpacking the ZIP file you shoud get directory
+tree similar to this:
+
+#+BEGIN_VERSE
+*DOC*                   - Fifth documentation
+  *commands*            - documentation on Fifth built-in commands
+  *modules*             - documentation on additional commands, realized as loadable modules
+  *shots*               - Fifth screenshots
+
+*imageFile*             - files contained within 'disk.raw', just an extracted form.
+
+*source*                - source files
+  *emulator*            - emulator source
+  *util*                - utilites
+
+*disk.raw*                - Virtual disk file, has filesystem inside.
+*emulator.com*            - main executable.
+#+END_VERSE
+
+* Requirements
+** Software
+- MS-DOS 6.22 with HIMEM.SYS loaded.
+- Mouse driver (optional, if you have a mouse).
+- CPU is initialized into [[https://en.wikipedia.org/wiki/Unreal_mode][Unreal Mode]] during operation.
+- To recompile ASM sources, you can use FASM (Flat Assembler).
+- To run Quick Basic utilities, use Microsoft Quick Basic 4.5.
+- VESA support through BIOS or external driver (UNIVBE).
+
+** Hardware
+- A minimum of a i386 CPU.
+- 64 KB of free RAM below 640KB.
+- 2 MB of free [[https://en.wikipedia.org/wiki/Extended_memory][extended memory]].
+- A VESA-compatible video card.
+
+* Numbers representation within Fifth
+
+Because we are in full experimentation mode here (no regard for
+compatibility whatsoever), why not to try also alternative number
+representation ?
+
+Here alternative hexadecimal number representation format is devised:
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:numbers.png][file:numbers.png]]
+
+Essentially square is split into 4 triangles. Each triangle represents
+one bit.
+
+Fifth uses this hexadecimal format as primary throughout entire
+system.
+
+See also: [[https://en.wikipedia.org/wiki/Bibi-binary][Bibi-binary]].
+
+* Disk file map and its data structures
+
+The `disk.raw` file is a raw disk image that contains both the boot
+code (loaded before filesystem initialization) and the filesystem
+structure. The disk layout is as follows:
+
+** Disk Allocation Table
+| Offset  | Length  | Description                                                          |
+|---------+---------+----------------------------------------------------------------------|
+| 0       | ~4 KiB  | Operating system kernel in virtual CPU byte-code                     |
+| 4 KiB   | ~32 KiB | Human readable, early system initialization code                     |
+| 37 KiB  | ~65 KiB | FAT (File Allocation Table)                                          |
+| 101 KiB | ~16 MiB | Filesystem data area (stores file contents and directory structures) |
+
+** FAT Entry Format
+
+The FAT tracks which disk sectors belong to each file.
+
+|     Code | Meaning                                      |
+|----------+----------------------------------------------|
+|       -2 | Last sector of a file chain                  |
+|       -1 | Unused (empty) sector                        |
+| 0 -- ... | Pointer to the next sector in the file chain |
+
+** File Directory Entry Format
+| Offset | Length | Description                                         |
+|--------+--------+-----------------------------------------------------|
+|      0 |      4 | File extension (4-byte FSCII string, e.g., "TXT ")  |
+|      4 |     16 | Filename (16-byte FSCII string, padded with spaces) |
+|     20 |      4 | First block address                                 |
+|     24 |      4 | File size in bytes                                  |
+|     28 |      4 | Last modification timestamp (seconds since epoch)   |
+
+The directory entries are stored within the filesystem data
+area. Directory is just a file that list other files.
+
+* Core architecture
+
+Fifth core is simply some amount of already compiled into machine code
+and linked together modules (entries in other words). In compilation
+process modules is compiled one by one and simply stored on top of
+already existing and growing core. Separately from core is kept
+dictionary, this is special list that contain names of compiled
+modules, variables etc. and they locations in core. Constants use
+dictionary space only. Random word can be removed from dictionary at
+any time. Currently dictionary can contain at most 1000 entries.
+
+** Dictionary entry format
+| offset | length | description           |
+|--------+--------+-----------------------|
+|      0 |      4 | 0 &lt; previous entry |
+|        |        | 0 = last              |
+|        |        | -1 = empty            |
+|--------+--------+-----------------------|
+|      4 |     15 | module name string    |
+|--------+--------+-----------------------|
+|     19 |      1 | entry type            |
+|--------+--------+-----------------------|
+|     20 |      4 | entry data            |
+
+Core headers as linked list of module names make up something like
+dictionary.  When some entry address is needed compiler can quickly
+run through headers backwards and find needed entry.
+
+** Possible module types
+
+| type | description    | "execute" action           |
+|------+----------------+----------------------------|
+|    0 | data           | compile "num" instruction  |
+|      |                | with address to module     |
+|------+----------------+----------------------------|
+|    1 | submodule      | compile "call" instruction |
+|      |                | with address to module     |
+|------+----------------+----------------------------|
+|    2 | imm. submodule | immediately call to module |
+
+** Memory map
+
+| location | size   | description                 |
+|----------+--------+-----------------------------|
+|        0 | ~4096  | core                        |
+|  1500000 | ~32000 | highlevel Fifth boot code   |
+|  200000h |        | core startup messages area  |
+|  5200000 |        | end of dynamic memory space |
+
+* Dynamically loadable modules
+** Keyboard driver
+#+BEGIN_VERSE
+
+KBD_@           ( -- code ) get scancodes for pressed keys from keyboard.
+KBD_down?       ( key -- result ) check is key with specified scancode
+                currently pressed down.
+KBD_SC2FSCII    ( code -- FSCII ) convert key scancode into FSCII code,
+                or in FSK (Fifth standard keycode).
+KBD_F@          ( -- FSCII ) read pressed key FSCII or FSK, returns -1 if no
+                keys are pressed.
+KBD_FW@         ( -- FSCII ) read pressed key FSCII or FSK, if no keys is
+                are pressed then waits until there is.
+
+                FSK
+                ---
+In HEX.
+
+FC      backspace
+FD      TAB
+FE      enter
+FF      space
+
+400     ESC
+401 ... F1 ...
+410     up
+411     right
+412     down
+413     left
+414     INS
+415     DEL
+416     home
+417     end
+418     PG/UP
+419     PG/DN
+#+END_VERSE
+** Mouse driver
+#+BEGIN_VERSE
+mousex  var     Mouse x coordinate.
+mousey  var     Mouse y coordinate.
+mousekeyl var   Mouse left key.
+mousekeym var   Mouse middle key.
+mousekeyr var   Mouse right key.
+mousec  var     Display current mouse coordinates in top left part of screen,
+                if true. (good for debugging)
+mousepointer var  Image buffer, holding current mouse pointer.
+mouseadd        ( ModuleAddr x1 x2 y1 y2 -- ) Add specified area on screen,
+                into mause click buffer. If any mouse button is clicked on
+                that area, module at "ModuleAddr" will be executed.
+mousebe var     Amount of buffer elements.
+mousedo         ( -- ) Updates mouse coordinates and keys. Parse mouse
+                click buffer, and draw mouse cursor to "screen".
+#+END_VERSE
+** 2D graphic library
+
++ lineh ( color len x y imgbuf -- ) :: draws horisontal line from X,Y
+  coordinates to right, with specified length.
+
++ linev ( color len x y imgbuf -- ) :: draws vertical line down, from
+  coordinates X,Y, with specified length.
+
++ box ( color x2 x1 y2 y1 imgbuf -- ) :: draws rectangular box. x2
+  bust be >= x1, y2 must be >= y1.
+
+  #+begin_example
+    x1,y1-----------+
+      |             |
+      |             |
+      +-----------x2,y2
+  #+end_example
+
++ flipv ( imgbuf -- ) :: flip image vertically.
+
++ imgcoltrans ( ImgBuf Color ToColor -- ) :: Translate all pixels in
+  specified image with "Color" into "ToColor".
+
++ imgfill ( color x y imgbuf -- ) :: Fill image region starting at
+  location X & Y with specified color.
+
+** Trigonometry functions
+
+
+*** sin ( a -- result )
+:PROPERTIES:
+:CUSTOM_ID: ID-9a66ca9c-eb5f-45aa-8116-71763081f2fb
+:ID:       9a66ca9c-eb5f-45aa-8116-71763081f2fb
+:END:
+
+Return sine of angle "a", where the:
+
+- Input is scaled such that: 360 degrees = 2000 units (i.e., 1 unit =
+  0.18 degrees).
+
+- The output is scaled to a 16-bit integer range of -10000 to 10000,
+  where ±10000 represents ±1.0 in floating-point terms.
+
+This fixed-point representation allows efficient computation using
+precomputed lookup tables, avoiding floating-point operations which
+are not supported by the virtual CPU's integer-only instruction
+set. The lookup table provides fast, sine values within the system's
+precision.
+
+*** cos ( a -- result )
+
+Return cosine of angle "a", using the same scaling and fixed-point
+representation as the [[id:9a66ca9c-eb5f-45aa-8116-71763081f2fb][sin]] function. Input angles are scaled (360° =
+2000 units), and outputs range from -10000 to 10000. Precomputed
+values in a lookup table ensure high performance for trigonometric
+calculations.
diff --git a/Documentation/language.org b/Documentation/language.org
new file mode 100644 (file)
index 0000000..39073ce
--- /dev/null
@@ -0,0 +1,860 @@
+:PROPERTIES:
+:ID:       da7fff9b-0b67-4843-828a-52a404d7f401
+:END:
+#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
+#+TITLE: Fifth - language
+#+AUTHOR: Svjatoslav Agejenko
+#+LANGUAGE: en
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+  .flex-center {
+    display: flex;            /* activate flexbox */
+    justify-content: center;  /* horizontally center anything inside   */
+  }
+
+  .flex-center video {
+    width: min(90%, 1000px); /* whichever is smaller wins */
+    height: auto;            /* preserve aspect ratio */
+  }
+
+  .responsive-img {
+    width: min(100%, 1000px);
+    height: auto;
+  }
+</style>
+#+end_export
+
+
+- [[file:5TH_ET.txt][Example Fifth source file - text editor]]
+
+* Fifth source format
+
+Fifth uses a different character table and codes than ASCII (still
+almost similar). I call it FSCII (Fifth Standard Code for Information
+Interchange) for example space character is not 32 but 255 instead.  I
+plan to use mainly HEX numbers, and create new characters to represent
+numeric values. So typical nemric characters "0123..."  is treated
+like ordinary letters.
+
+** FSCII
+
+|    DEC | HEX   | function                               |
+|--------+-------+----------------------------------------|
+| 0 - 15 | 0 - F | HEX numbers                            |
+|    252 | FC    | backspace                              |
+|    253 | FD    | tabulator (TAB)                        |
+|    254 | FE    | carriage return (CR)                   |
+|    255 | FF    | space                                  |
+|   else |       | ordinary characters, same as in ASCII. |
+
+* Fifth commands
+** Compilation & miscellaneous
+*** init ( -- )
+
+- Description :: First module, control is passed to on startup. Contains
+  initialization routines. Also it is the last core module. All new
+  modules on top of it comes as result of executing external source
+  files.
+
+*** head <name> ( -- )
+
+- Description :: Compiles new dictionary entry without specifying new
+  module type.
+- Example ::
+  : head myentry
+
+*** : <name> ( -- )
+
+- Description :: Creates new code module.
+
+*** ; ( -- )
+
+- Description :: Ends module (immideate).
+- Example ::
+  : : hello ." hi there" ;
+
+*** const <name> ( n -- )
+
+- Description :: Defines new constant.
+- Example ::
+  : 2147483647 const max
+
+*** :i <name> ( -- )
+
+- Description :: Same as =:= but this module will be executed
+  immideately even in compile mode.
+- Example ::
+  : :i ( 41 scan ;
+
+*** create <name> ( -- )
+
+- Description :: Same as =head=, but specify module type as data.
+- Example ::
+  : create LotoResults 5 , 13 , 52 , 12 , 11 , 3 ,
+
+*** allot ( n -- )
+
+- Description :: Allocate *n* bytes in dictionary.
+- Example ::
+  : create MyArray 100 allot
+
+*** " <string>" ( -- )
+
+- Description :: Compile string and its size into core.
+- Example ::
+  : create Mystring " This is it's contects"
+
+*** str <name> <string>" ( -- )
+
+- Description :: Just shorter way for defining strings.
+- Example ::
+  : str Mystring This is it's contenc"
+
+*** var <name> ( -- )
+
+- Description :: Define new 32 bit variable.
+- Example ::
+  : var result
+
+*** ' <module> ( -- n )
+
+- Description :: Return memory address of given entry.
+- Example ::
+  : ' init
+
+*** forget <name> ( -- )
+
+- Description :: Erases from RAM given entry and all entries what was
+  defined after it.
+- Example ::
+  : forget myprog
+
+*** [ ( -- )
+
+- Description :: Set interpret mode (immideate).
+
+*** ] ( n -- )
+
+- Description :: Set compile mode and compile top stack element in as
+  literal. Together =[ .... ]= combination provides good way to
+  compute some values only once, at compile time, rather than every
+  time while program is running.
+- Example ::
+  : : calculate - [ 4 MyConst1 + MyConst2 * ] ;
+
+*** defer <name> ( -- )
+
+- Description :: Creates new module, with jump instruction. Later
+  address where to jump can be modified by =is= command. This
+  provides method of forward referencing. So you can use modules what
+  not yet exist.
+
+*** is ( address1 address2 -- )
+
+- Description :: *address1* - where to jump, *address2* - address of
+  module created by =defer= command.
+- Example ::
+  : defer dispver
+  : : run dispver ." running ..." ;
+  :        ... whatever ...
+  : : (dispver ." Version 9.99 " ;
+  : ' (dispver ' dispver is
+
+  Now if I type "run" on the screen appears:
+  : Version 9.99 running ...
+
+*** asc <char> ( -- )
+
+- Description :: Reads char ascii code and treats it as literal
+  (immideate).
+- Example ::
+  : : BreakLine 30 do asc - emit loop ;
+
+  same as:
+  : : BreakLine 30 do    45 emit loop ;
+
+*** dyninc ( handle -- )
+
+- Description :: Execute code in dynamic memory handle. Automatically
+  deallocates it when done.
+
+*** include ( filenumber -- )
+
+- Description :: Execute code in specified file.
+
+*** words ( -- )
+
+- Description :: Display existing blocks in core.
+
+*** bye ( -- )
+
+- Description :: Exit from Fifth.
+
+*** fkey ( -- c )
+
+- Description :: Read one byte from input stream.
+
+*** sadd ( c addr -- )
+
+- Description :: Add one byte *c* to string located at *addr* and
+  updates string length.
+
+*** scan ( c -- )
+
+- Description :: Read input stream and store it to =pad= until it
+  finds *c*. It ignores all *c* bytes until it finds any non *c*
+  byte. Is useful for breaking text lines into words.
+- Example ::
+  :              c  is:  "
+  :       input stream:  """"This is test !"aoeu idh
+  :              result:  This is test !
+
+*** skey ( -- c )
+
+- Description :: So called safe =fkey=. Reads data from input stream
+  but converts characters with ASCII codes: 9 13 10 to spaces.
+
+*** str=str? ( adr1 adr2 -- result )
+
+- Description :: Compares string at *adr1* with string at *adr2*,
+  returns true flag if they are equal or false if they are not.
+  true = -1, false = 0.
+
+*** find ( -- addr )
+
+- Description :: Searches whole dictionary for word in =pad=. If
+  found, returns its address, if not, returns 0.
+
+*** execute ( -- )
+
+- Description :: Execute word located in =pad=. Depending on =mode=.
+
+*** dta ( addr -- DataAddr )
+
+- Description :: Calculates address of dictionary entry data area,
+  from entry point.
+
+*** 2num ( -- num result )
+
+- Description :: Attempt to convert string located in =pad= into
+  numeric value. If succeed returns number and true as result. If
+  not, returns whatever and false as result.
+
+*** dadd ( addr length -- )
+
+- Description :: Add to dictionary data located at *addr*, with
+  specified length.
+
+*** lit ( n -- )
+
+- Description :: Act with number depending on =mode=. When
+  interpreting, leaves it in stack.
+
+*** incmod ( addr -- )
+
+- Description :: Add to dictionary data located at *addr*+1, length
+  is taken from *addr*.
+
+*** here ( -- n )
+
+- Description :: Return =h= contents.
+
+*** mode ( var, 8 bit )
+
+- Description :: Holds input stream parser operation mode. 0 =
+  interpreting, 1 = compiling.
+
+*** pad ( var, 128 bytes )
+
+- Description :: Holds temporary strings.
+
+*** h ( var, 32 bit )
+
+- Description :: Pointer to free byte in memory, always at the end of
+  the dictionary. Each time when something is stored by =c,= command,
+  pointer is increased.
+
+*** lp ( var, 32 bit )
+
+- Description :: Pointer to last dictionary word. Each time when new
+  word is compiled or erased by =forget=, this pointer is updated.
+
+*** modulechk ( Dstr<filename> -- )
+
+- Description :: Check if module is loaded, if not immideately load it.
+
+*** ne ( entrydata entrytype -- )
+
+- Description :: Compile new dictionary entry. Its name must be in
+  =pad=.
+
+** Conditionals & control flow
+*** if ( flag -- )
+
+- Description :: =if 1.. else 2.. then= or =if 1.. then=
+  construction. Conditional execution (immideate). Performs "1.." if
+  *flag* was true, elseway performs "2.." if exist. Execution
+  continues after word =then=.
+- Example ::
+  : 1 if ." nonzero" else ." zero" then
+
+*** >= ( n1 n2 -- result )
+
+- Description :: True if (n1 = n2) or (n1 > n2).
+- Example ::
+  : 5 3 >= if ." first number is greater or equal" then
+
+*** <= ( n1 n2 -- result )
+
+- Description :: True if (n1 = n2) or (n1 < n2).
+
+*** = ( n1 n2 -- result )
+
+- Description :: True if n1 = n2.
+
+*** do ( count -- )
+
+- Description :: =do .. loop= construction (immideate). Performs ".."
+  *count* times. In every step *count* is decreased until it is 0.
+- Example ::
+  : : test 5 do i .d loop ;
+  result: 4 3 2 1 0
+
+*** doexit ( -- )
+
+- Description :: Exit from =do .. loop=.
+
+*** for ( count top -- )
+
+- Description :: =for .. loop= construction (immideate). Performs ".."
+  (top - count) times. In every step *count* is increased until it
+  reaches *top*.
+- Example ::
+  : : test 4 10 for i .d loop ;
+  result: 4 5 6 7 8 9
+
+*** forexit ( -- )
+
+- Description :: Exit from =for .. loop=.
+
+*** until ( -- )
+
+- Description :: =until .. loop= construction (immideate). Performs
+  ".." until flag become true. False by default. Top of return stack
+  holds flag.
+
+*** done ( -- )
+
+- Description :: Exit from =until .. loop=.
+
+** Disk & file access
+*** diskload ( FromDisk ToMem amount -- )
+
+- Description :: Load specified amount of bytes from disk into memory.
+
+*** disksave ( FromMem ToDisk amount -- )
+
+- Description :: Save specified amount of bytes from memory into disk.
+
+*** format ( -- )
+
+- Description :: Erase all files.
+
+*** fsDfilesize@ ( handle -- size )
+
+- Description :: Return size of opened file.
+
+*** fsDcurloc@ ( handle -- location )
+
+- Description :: Return current location in file.
+
+*** fsDupdated@ ( handle -- updated? )
+
+- Description :: Return true if file was updated, ie. write operations
+  occurred.
+
+*** fssave ( FromMem DestFileHandle amount -- )
+
+- Description :: Save data to file.
+
+*** fsload ( SrcFileHandle ToMem amount -- )
+
+- Description :: Load data from file.
+
+*** fseof ( handle -- bytesLeft )
+
+- Description :: Return amount of bytes left till end of file. Useful
+  before read operation.
+
+*** fsls ( -- )
+
+- Description :: List all files and lists (directories, folders) in
+  current path.
+
+*** fslsr ( -- )
+
+- Description :: Same as =fsls= but recursively scans also sub lists.
+
+*** fscl ( DynStrHand -- )
+
+- Description :: Change list (path).
+
+*** fscreate ( DynStrHand -- DescPnt )
+
+- Description :: Create new file or list. Can create multiple lists at
+  once.
+- Example ::
+  When creating:
+  : "\listGAMES\listSTRATEGY\listSIMWORLD\5th-runme"
+  and only =\listGAMES\= already exist, then =listSTRATEGY= and
+  =listSIMWORLD= lists will be created, and empty file =5th-runme=
+  placed in there.
+
+*** fsDsave ( DynHand<data> DynStrHand<filename> -- )
+
+- Description :: Create new file and save all data from dynamic memory
+  block to it.
+
+*** fsDload ( DynStr<SrcFileName> DynHand<DataDest> -- )
+
+- Description :: Load whole file into dynamic memory block.
+
+*** fsDloadnew ( DynStr<SrcFileName> -- DynHand<DataDest> )
+
+- Description :: Load whole file into new dynamic memory block.
+
+** Dynamic memory
+*** dynal ( size -- handle )
+
+- Description :: Allocate dynamic memory block and return its handle.
+
+*** dynde ( handle -- )
+
+- Description :: Deallocate dynamic memory block.
+
+*** dynp ( handle -- addr )
+
+- Description :: Returns pointer to memory where dynamic block data
+  begins.
+
+*** dyns ( handle -- size )
+
+- Description :: Returns size of dynamic block.
+
+*** dynresize ( NewSize handle -- )
+
+- Description :: Nondestructively resize dynamic block.
+
+*** dync@ ( addr handle )
+
+- Description :: Read one byte from dynamic block.
+
+*** dync! ( byte addr dynhandle )
+
+- Description :: Write one byte to dynamic block.
+
+*** dyn@ ( addr handle )
+
+- Description :: Read 32 bit number from dynamic block. Address will
+  specify which number, not byte.
+
+*** dyn! ( 32BitNum addr dynhandle )
+
+- Description :: Write 32 bit number to dynamic block. Address will
+  specify which number, not byte.
+
+*** dyncon ( size "name" -- )
+
+- Description :: Allocate dynamic block with specified size, and
+  create constant holding its handle.
+- Example ::
+  : 100 dyncon MyNewBlock
+
+*** dyn. ( handle -- )
+
+- Description :: Write content of dynamic memory block to screen.
+
+** Graphics and text
+*** . ( n -- )
+
+- Description :: Print number on screen.
+
+*** d. ( n -- )
+
+- Description :: Print number on screen in decimal.
+
+*** ? ( addr -- )
+
+- Description :: Print 32 bit value located at *addr*.
+
+*** ." <string>" ( -- )
+
+- Description :: Print string into screen. Immideately compiles.
+- Example ::
+  : : greeting ." Hello, World" ;
+
+*** tab. ( -- )
+
+- Description :: Print tabulator.
+
+*** calccol ( b g r -- c )
+
+- Description :: Calculate color what best matches given Blue Green &
+  Red values. Values must be in range 0 - 255.
+
+*** imgalloc ( xsize ysize -- imgbuf )
+
+- Description :: Allocate image buffer for specified size.
+
+*** imgsize ( imgbuf -- )
+
+- Description :: Print on the screen X & Y size of image buffer.
+
+*** point ( x y imgbuf -- addr )
+
+- Description :: Returns memory address for specified pixel.
+
+*** pset ( color x y imgbuf -- )
+
+- Description :: Set graphic point.
+
+*** boxf ( x1 x2 y1 y2 imgbuf color -- )
+
+- Description :: Draw filled box.
+
+*** cls ( imgbuf -- )
+
+- Description :: Clear image buffer.
+
+*** setpal ( b g r color -- )
+
+- Description :: Set palette value for specified color. Values must be
+  in range 0 - 63.
+
+*** putchar ( char color x y imgbuf -- )
+
+- Description :: Put graphic character in imagebuffer to specified (x
+  & y) location.
+
+*** scroll ( x y imgbuf -- )
+
+- Description :: Scroll in imgbuf.
+
+*** scrollf ( color x y screen -- )
+
+- Description :: Scroll and fill empty space with given color.
+
+*** at! ( x y -- )
+
+- Description :: Set cursor location.
+
+*** curc! ( color -- )
+
+- Description :: Set text color.
+
+*** curb! ( color -- )
+
+- Description :: Set background color.
+
+*** colnorm ( -- )
+
+- Description :: Set text color to normal.
+
+*** colneg ( -- )
+
+- Description :: Set text color to negative (selected).
+
+*** dyntype ( dynhandle -- )
+
+- Description :: Display content of dynamic memory on screen.
+
+*** fsdisp ( file -- )
+
+- Description :: Clear screen, display file, and wait for key.
+
+*** type ( addr length -- )
+
+- Description :: Types on the screen string, from memory at *addr*
+  and specified length.
+
+*** write ( addr -- )
+
+- Description :: Types on the screen string, from memory at *addr*+1,
+  length is taken from *addr*.
+
+*** screen ( const, 32 bit )
+
+- Description :: Holds handle of screen buffer.
+
+*** copyscreen ( SrcImgHandle DestImgHandle -- )
+
+- Description :: Copy content of source image to destination image.
+  Source and destination images must have same size.
+
+** Math, memory & stack manipulation
+*** off ( n -- )
+
+- Description :: Writes 0 to given address, good for zeroing variable.
+- Example ::
+  : MyVariable off
+
+*** on ( n -- )
+
+- Description :: Writes -1 (true flag) to given address.
+- Example ::
+  : MyVariable on
+
+*** 2dup ( n1 n2 -- n1 n2 n1 n2 )
+*** 2drop ( n1 n2 -- )
+*** nip ( n1 n2 -- n2 )
+*** neg ( n1 -- -n1 )
+:PROPERTIES:
+:CUSTOM_ID: ID-a7cf0a47-40f1-49bc-afde-f6e86ac2c6d8
+:ID:       a7cf0a47-40f1-49bc-afde-f6e86ac2c6d8
+:END:
++ See also: [[id:861f65e6-7ecb-43f0-9927-396855fb993f][abs ( n -- |n| )]]
+
+- Description :: Invert sign (negate) of a numerical value.
+
+*** bit@ ( n bit -- result )
+
+- Description :: Return specified bit from n.
+- Example ::
+  : 38 2 bit@
+    result will be 1
+
+*** to32bit  ( n1 n2 n3 n4 -- n32 )
+
+- Description :: Treat 4 last stack elements as bytes and unite them
+  into 32 bit double word. Most significant byte on top.
+- Example ::
+  : 12 76 23 11 to32bit
+  result: 186076172
+
+*** to8bit ( n32 -- n1 n2 n3 n4 )
+
+- Description :: Break 32 bit number into 4 bytes. Useful if you need
+  to send 32 bit numbers though 8 bit COM port.
+- Example ::
+  : 186076172 to8bit
+  result: 12 76 23 11
+
+*** mod ( n1 n2 -- reminder )
+
+- Description :: Divide *n1* by *n2* and returns reminder.
+- Example ::
+  : 12 5 mod
+  result: 2
+
+*** bound ( low n high -- n )
+
+- Description :: Check if *n* is in given bounds (upper and lower
+  bounds are both inclusive). If *n* if outside of bounds, increase or
+  decrease its value accordingly to stay within bounds.
+- Examples ::
+  : 5 80 15 bound
+  result: 15
+
+  : 5 10 15 bound
+  result: 10
+
+  : 5 -10 15 bound
+  result: 5
+
+*** bound? ( low n high -- result )
+
+- Description :: Returns true if *n* is in the given bounds. Upper and
+  lower bounds are both inclusive.
+
+*** tab ( col -- spaces )
+
+- Description :: Calculate amount of spaces to add to reach next
+  tabulation from given column.
+
+*** count ( addr -- addr+1 n )
+
+- Description :: Useful for returning bytes from constantly
+  incareasing address. Module =type= is nice example.
+
+*** c, ( n -- )
+
+- Description :: Store one byte at memory specified by =h=. And
+  incarease =h= by 1.
+
+*** , ( n -- )
+
+- Description :: Store 32 bit number at memory specified by =h=. And
+  incarease =h= by 4.
+
+*** cmove ( addr1 addr2 n -- )
+
+- Description :: Copy *n* amount of bytes from memory at *addr1* to
+  memory at *addr2*.
+
+*** rnd ( limit -- result )
+
+- Description :: Generates random number in range 0 to =limit= - 1.
+
+*** abs ( n -- |n| )
+:PROPERTIES:
+:CUSTOM_ID: ID-861f65e6-7ecb-43f0-9927-396855fb993f
+:ID:       861f65e6-7ecb-43f0-9927-396855fb993f
+:END:
++ See also: [[id:a7cf0a47-40f1-49bc-afde-f6e86ac2c6d8][neg ( n1 -- -n1 )]]
+
+- Description :: Returns absolute value of *n*.
+
+** Dynamic & static strings
+
+Fifth supports both static and dynamic strings. Static strings must
+have predefined space reserved, and string mustn't exceed this
+length. They manipulation is faster. But they use more memory. Static
+string memory address is used to refer to the string.
+
+Dynamic strings can have at any time length form 0 to 0FFh, They take
+up only memory they currently need. They are held in dynamic memory
+blocks, so dynamic block handle is used to refer to this string.
+
+Both types of strings are stored in the way, where first (0th) byte
+holds current string length, following bytes are string itself.
+
+*** Dstral ( -- handle )
+
+- Description :: Allocate new dynamic string.
+
+*** Dstrlen ( handle -- length )
+
+- Description :: Return string length.
+
+*** c+Dstr ( chr handle -- )
+
+- Description :: Add one byte to end of the string.
+
+*** c+lDstr ( chr handle -- )
+
+- Description :: Add one byte to left side (beginning) of the string.
+
+*** Dstr. ( handle -- )
+
+- Description :: Write content of string into screen.
+
+*** Dstrsure ( size Dstr -- )
+
+- Description :: Makes sure that at least requested *size* (amount of
+  characters) is allocated for given dynamic string.
+
+*** Dstr2str ( handle address -- )
+
+- Description :: Copy dynamic string into static memory space.
+
+*** str2Dstr ( address handle -- )
+
+- Description :: Copy static string into dynamic string.
+
+*** Dstr+str ( Dstr addr -- )
+
+- Description :: Add content of dynamic string to static string.
+
+*** D" any string" ( -- Dstr )
+
+- Description :: Moves specified string into dynamic string called
+  =defDstr=.
+
+*** D> any_string ( -- Dstr )
+
+- Description :: Moves specified string into dynamic string called
+  =defDstr=. Space marks end of string!
+
+*** D>2 any_string ( -- Dstr )
+
+- Description :: Moves specified string into dynamic string called
+  =defDstr2=. Space marks end of string!
+
+*** Dstr+Dstr ( Dstr1 Dstr2 -- )
+
+- Description :: Adds *Dstr1* to *Dstr2* and places result into
+  *Dstr2*.
+
+*** Dstrclear ( Dstr -- )
+
+- Description :: Clears content of dynamic string.
+
+*** Dstr2Dstr ( Dstr1 Dstr2 -- )
+
+- Description :: Moves *Dstr1* to *Dstr2*.
+
+*** Dstr ( data" name -- )
+
+- Description :: Creates new dynamic string and moves specified data
+  into it. Then creates new constant with given *name* holding
+  created dynamic string handle.
+- Example ::
+  : Dstr Hello, my name is Sven!" message      \ creates it
+  : message Dstr.                              \ tests it
+
+*** Dstrlscan ( char Dstr -- loc )
+
+- Description :: Searches dynamic string for *char*, from left to
+  right, returns first found *char* location in string, or 0, if not
+  found.
+
+*** Dstrrscan ( char Dstr -- loc )
+
+- Description :: Searches dynamic string for *char*, from right to
+  left, returns first found *char* location in string, or 0, if not
+  found.
+
+*** Dstrlscane ( char Dstr -- loc )
+
+- Description :: Same as =Dstrlscan= but returns string length+1 as
+  location.
+
+*** Dstrleft ( amo Dstr -- )
+
+- Description :: Only specified amount of characters from left remains
+  in dynamic string. ie. cut right part out.
+
+*** Dstrright ( amo Dstr -- )
+
+- Description :: Only specified amount of characters from right
+  remains in dynamic string. ie. cut left part out.
+
+*** Dstrcutl ( amo Dstr -- )
+
+- Description :: Cut specified amount of characters from left of
+  dynamic string out.
+
+*** Dstrsp ( char Dstr1 Dstr2 -- )
+
+- Description :: Separate dynamic string in *Dstr1* into two parts,
+  using *char* as separator. First part will be stored in *Dstr2*,
+  second part in *Dstr1*.
+- Example ::
+  : asc \                               \ ..separator
+  : D> listF\listLIB\5TH_DRVMOUSE       \ ..separate from
+  : defDstr2                            \ ..place result in
+  : Dstrsp              \ separation command
+  : defDstr Dstr.       \ will be: listLIB\5TH_DRVMOUSE
+  : defDstr2 Dstr.      \ will be: listF
+
+*** Dv ( addr -- )
+
+- Description :: Allocates empty dynamic string, and places its
+  handle into given address.
+
+*** Df ( addr -- )
+
+- Description :: Reads dynamic string handle from given address and
+  deallocates (frees) it.
+- Example ::
+  : var mystring1
+  : : testmodule
+  : mystring1 Dv            \ allocates string
+  :
+  :         <whatever>
+  :
+  : mystring1 Df ;          \ deallocates it again when no longer needed.
diff --git a/Documentation/numbers.png b/Documentation/numbers.png
new file mode 100644 (file)
index 0000000..0ccd07b
Binary files /dev/null and b/Documentation/numbers.png differ
diff --git a/Documentation/opcodes_00_09.org b/Documentation/opcodes_00_09.org
new file mode 100644 (file)
index 0000000..ddc530e
--- /dev/null
@@ -0,0 +1,628 @@
+#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
+#+TITLE: Fifth - virtual machine opcodes 0 -- 9
+#+AUTHOR: Svjatoslav Agejenko
+#+LANGUAGE: en
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+  .flex-center {
+    display: flex;            /* activate flexbox */
+    justify-content: center;  /* horizontally center anything inside   */
+  }
+
+  .flex-center video {
+    width: min(90%, 1000px); /* whichever is smaller wins */
+    height: auto;            /* preserve aspect ratio */
+  }
+
+  .responsive-img {
+    width: min(100%, 1000px);
+    height: auto;
+  }
+</style>
+#+end_export
+
+* Overview
+
+This document describes virtual machine opcodes 0 through 9. These are
+the fundamental instructions for program flow control, stack
+manipulation, and basic I/O operations.
+
+*Quick Reference:*
+
+| Opcode | Name | Stack Effect     | Bytecode Size | Purpose                         |
+|--------+------+------------------+---------------+---------------------------------|
+|      0 | nop  | --               | 1 byte        | Do nothing (placeholder)        |
+|      1 | halt | --               | 1 byte        | Exit emulator                   |
+|      2 | kbd@ | -- scancode      | 1 byte        | Read keyboard input             |
+|      3 | num  | -- n             | 5 bytes       | Push literal 32-bit number      |
+|      4 | jmp  | --               | 5 bytes       | Unconditional jump              |
+|      5 | call | -- (R: -- ret)   | 5 bytes       | Call subroutine                 |
+|      6 | 1+   | n -- n+1         | 1 byte        | Increment by 1                  |
+|      7 | 1-   | n -- n-1         | 1 byte        | Decrement by 1                  |
+|      8 | dup  | n -- n n         | 1 byte        | Duplicate top of stack          |
+|      9 | drop | n --             | 1 byte        | Discard top of stack            |
+
+* 0: nop (No Operation)
+:PROPERTIES:
+:CUSTOM_ID: opcode-nop
+:ID:       4f0dee8a-647e-4d91-a252-aaf4782b5edc
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value             |
+|------------+-------------------|
+| Opcode     | 0                 |
+| Name       | nop               |
+| Stack      | ( -- )            |
+| Bytecode   | Single byte: =00= |
+
+*Description*
+
+Does nothing. Execution continues immediately to the next instruction.
+This opcode is handled as the entry point to the emulator's instruction
+fetch loop, meaning it effectively "falls through" to the next opcode.
+
+*When to Use:*
+
+- Padding bytecode for alignment purposes
+- Placeholder during development or debugging
+- Safe target for jump instructions when you need a "do nothing" branch
+- Filling unused entries in jump tables
+
+*Example:*
+
+#+BEGIN_SRC
+00              ; nop - do nothing
+03 05 00 00 00  ; num 5 - push 5 onto stack
+#+END_SRC
+
+No observable effect. The instruction pointer simply advances to the
+next opcode.
+
+* 1: halt (Stop Execution)
+:PROPERTIES:
+:CUSTOM_ID: opcode-halt
+:ID:       7c8841d3-2335-4ee9-b6b9-518d05354841
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value             |
+|------------+-------------------|
+| Opcode     | 1                 |
+| Name       | halt              |
+| Stack      | ( -- )            |
+| Bytecode   | Single byte: =01= |
+
+** Description
+
+Terminates the emulator process cleanly. This is the only proper way
+to exit the Fifth environment. When executed, the emulator:
+
+1. Restores text video mode (mode 3)
+2. Closes the virtual disk file handle
+3. Restores the original keyboard interrupt handler
+4. Returns control to DOS
+
+** When to Use
+
+- Terminating the program cleanly and exiting the Fifth environment
+- Implementing a "quit" or "bye" command in REPL
+- Shutting down after fatal errors
+
+** Example
+
+#+BEGIN_SRC
+01              ; halt - exit emulator immediately
+#+END_SRC
+
+In Fifth source code, this is typically invoked via the =bye= word,
+which compiles to the halt opcode.
+
+* 2: kbd@ (Keyboard Input)
+:PROPERTIES:
+:CUSTOM_ID: opcode-kbd-read
+:ID:       820b1b90-4f4c-4ab1-b49f-9b4a52ea2528
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value             |
+|------------+-------------------|
+| Opcode     | 2                 |
+| Name       | kbd@              |
+| Stack      | ( -- scancode )   |
+| Bytecode   | Single byte: =02= |
+
+** Description
+
+Reads a keyboard scancode from the internal ring buffer and pushes it
+onto the data stack. This is a non-blocking operation: if no key is
+pending, it pushes 0 immediately.
+
+** Scan Code Behavior
+
+The keyboard hardware generates scan codes for every key event:
+
+- *Make code*: Generated when a key is pressed (values 1-127)
+- *Break code*: Generated when a key is released (make code + 128)
+
+For example:
+- Pressing 'A' produces scan code =1E=
+- Releasing 'A' produces scan code =9E= (1E + 80 hex)
+
+** Common Scan Codes (US QWERTY)
+
+| Key         | Make Code | Break Code |
+|-------------+-----------+------------|
+| Escape      | 01        | 81         |
+| 1-9         | 02-0A     | 82-8A      |
+| 0           | 0B        | 8B         |
+| Enter       | 1C        | 9C         |
+| Space       | 39        | B9         |
+| Left Arrow  | 4B        | CB         |
+| Right Arrow | 4D        | CD         |
+| Up Arrow    | 48        | C8         |
+| Down Arrow  | 50        | D0         |
+| A           | 1E        | 9E         |
+| Z           | 2C        | AC         |
+
+** When to Use
+
+- Building interactive programs (games, text editors)
+- Reading raw keyboard input without translation to characters
+- Detecting key press/release events separately
+- Implementing custom keyboard drivers or input handlers
+
+** Example
+
+Basic key reading:
+
+#+BEGIN_SRC
+02              ; kbd@ - read scancode
+                ; data stack now contains: scancode (or 0 if no key)
+#+END_SRC
+
+** Return Values
+
+- Returns =0= if no key is available in the buffer
+- Returns scancode (1-255) when a key event is pending
+- Each call consumes one scancode from the buffer
+
+** Important Notes
+
+- This returns raw scan codes, not ASCII characters
+- Use a keyboard layout file (like =5TH_KBD_US=) to translate scan
+  codes to FSCII characters
+- The buffer holds 128 scan codes; older codes are overwritten if full
+
+* 3: num (Push Literal Number)
+:PROPERTIES:
+:CUSTOM_ID: opcode-num
+:ID:       8721dc8c-b237-4e9a-a509-0ded1c02329b
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value                                    |
+|------------+------------------------------------------|
+| Opcode     | 3                                        |
+| Name       | num                                      |
+| Stack      | ( -- n )                                 |
+| Bytecode   | =03= followed by 4 bytes (little-endian) |
+
+** Description
+
+Pushes a 32-bit literal value onto the data stack. The value is encoded
+directly in the instruction stream immediately after the opcode byte.
+After execution, the instruction pointer advances by 4 bytes.
+
+** Bytecode Format
+
+#+BEGIN_SRC
+03 xx xx xx xx
+│  └──────────┘ 32-bit value (little-endian)
+└ opcode
+#+END_SRC
+
+** When to Use
+
+- Loading constant values for calculations
+- Pushing memory addresses onto the stack
+- Setting up parameters for function calls
+- Initializing counters, pointers, and loop variables
+
+** Example
+
+Push the value =0x12345678=:
+
+#+BEGIN_SRC
+03              ; num opcode
+78 56 34 12     ; 32-bit value 0x12345678 (little-endian)
+                ; stack now contains: 0x12345678
+#+END_SRC
+
+In Fifth source code, simply write a number:
+
+#+BEGIN_SRC fifth
+12345678        ; Compiles to: 03 78 56 34 12
+FF              ; Compiles to: 03 FF 00 00 00
+1000            ; Compiles to: 03 00 10 00 00
+#+END_SRC
+
+** Important Notes
+
+- Numbers in Fifth source code are **hexadecimal by default**
+- Use =d.= to display numbers in decimal for debugging
+- All 32 bits are pushed; high bytes are zero-filled for small values
+- The value is stored in little-endian byte order in bytecode
+
+* 4: jmp (Unconditional Jump)
+:PROPERTIES:
+:CUSTOM_ID: opcode-jmp
+:ID:       a5c53b60-ffe9-4ba4-ab87-30c2ccc51a45
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value                                    |
+|------------+------------------------------------------|
+| Opcode     | 4                                        |
+| Name       | jmp                                      |
+| Stack      | ( -- )                                   |
+| Bytecode   | =04= followed by 4-byte target address   |
+
+** Description
+
+Transfers execution unconditionally to the specified address. The
+target address is embedded in the instruction stream immediately after
+the opcode. No return address is saved.
+
+** Bytecode Format
+
+#+BEGIN_SRC
+04 aa aa aa aa
+│  └──────────┘ 32-bit target address (little-endian)
+└ opcode
+#+END_SRC
+
+** When to Use
+
+- Creating infinite loops (combined with conditional exits)
+- Skipping over code blocks
+- Implementing forward jumps in control structures
+- Jump tables and dispatch mechanisms
+
+** Example
+
+Jump to address =0x1000=:
+
+#+BEGIN_SRC
+04              ; jmp opcode
+00 10 00 00     ; target address 0x1000 (little-endian)
+                ; execution continues at 0x1000
+#+END_SRC
+
+Create an infinite loop:
+
+#+BEGIN_SRC
+; At address 0x100:
+04 00 01 00 00  ; jmp 0x100 - infinite loop
+#+END_SRC
+
+Skip over code:
+
+#+BEGIN_SRC
+04 ...          ; jmp to skip_target
+...             ; code to skip
+; skip_target:
+#+END_SRC
+
+** Important Notes
+
+- The address is a **virtual address** in the VM's address space
+- The emulator adds =xms_addr= to convert to a physical memory address
+- No return address is saved; use =call= for subroutines
+
+* 5: call (Call Subroutine)
+:PROPERTIES:
+:CUSTOM_ID: opcode-call
+:ID:       66efbd35-c2b6-4657-ba0f-ff00a3a2c312
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property     | Value                                        |
+|--------------+----------------------------------------------|
+| Opcode       | 5                                            |
+| Name         | call                                         |
+| Stack        | ( -- )                                       |
+| Return Stack | ( -- ret-addr )                              |
+| Bytecode     | =05= followed by 4-byte target address       |
+
+** Description
+
+Calls a subroutine at the specified address. The return address (the
+address of the instruction immediately following this call) is saved
+on the return stack. Use =ret= (opcode 11) to return to the caller.
+
+** Bytecode Format
+
+#+BEGIN_SRC
+05 aa aa aa aa
+│  └──────────┘ 32-bit target address (little-endian)
+└ opcode
+#+END_SRC
+
+** When to Use
+
+- Calling reusable code blocks (functions, procedures)
+- Implementing Forth word definitions
+- Building modular programs with separate subroutines
+- Recursion (with proper stack management)
+
+** Example
+
+#+BEGIN_SRC
+; Main code at 0x100:
+05 00 20 00 00      ; call 0x2000
+03 01 00 00 00      ; num 1 (this is where we return to)
+
+; Subroutine at 0x2000:
+...                 ; subroutine code
+0B                  ; ret - return to caller
+#+END_SRC
+
+** Stack Effects
+
+| Stack        | Before | After     |
+|--------------+--------+-----------|
+| Data Stack   | ...    | ...       |
+| Return Stack | ...    | ret-addr  |
+
+The return address is the virtual address immediately after the 4-byte
+argument (i.e., the address of the next instruction).
+
+** Important Notes
+
+- The return stack is **separate** from the data stack
+- The return stack is also used by =push= and =pop= opcodes
+- Always balance =call= with =ret= to avoid return stack corruption
+- Nesting depth is limited by return stack size
+
+* 6: 1+ (Increment)
+:PROPERTIES:
+:CUSTOM_ID: opcode-1plus
+:ID:       76fe1c8f-756d-406e-9e8a-4ecc8f1d7369
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 6                  |
+| Name       | 1+                 |
+| Stack      | ( n -- n+1 )       |
+| Bytecode   | Single byte: =06=  |
+
+** Description
+
+Adds 1 to the value on top of the data stack, modifying it in place.
+This is a highly efficient single-byte operation.
+
+** When to Use
+
+- Incrementing loop counters
+- Advancing pointers through arrays or buffers
+- Computing successor values
+- Any situation where you need to add exactly 1
+
+** Example
+
+#+BEGIN_SRC
+03 05 00 00 00  ; num 5    - stack: [ 5 ]
+06              ; 1+       - stack: [ 6 ]
+06              ; 1+       - stack: [ 7 ]
+#+END_SRC
+
+** Efficiency Comparison
+
+| Operation   | Bytecode                   | Size  |
+|-------------+---------------------------+-------|
+| 1+          | =06=                       | 1 byte|
+| 1 +         | =03 01 00 00 00= =18=      | 6 bytes|
+
+Use =1+= instead of =1 += for better code density.
+
+** Important Notes
+
+- Modifies the value in place (no additional stack space needed)
+- Works identically on signed and unsigned 32-bit values
+- For adding larger values, use =+= (opcode 24)
+
+* 7: 1- (Decrement)
+:PROPERTIES:
+:CUSTOM_ID: opcode-1minus
+:ID:       523f93a3-359e-4a6d-b296-df25008db403
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 7                  |
+| Name       | 1-                 |
+| Stack      | ( n -- n-1 )       |
+| Bytecode   | Single byte: =07=  |
+
+** Description
+
+Subtracts 1 from the value on top of the data stack, modifying it in
+place. This is a highly efficient single-byte operation.
+
+** When to Use
+
+- Decrementing loop counters
+- Moving pointers backward through arrays or buffers
+- Computing predecessor values
+- Counting down to zero
+
+** Example
+
+#+BEGIN_SRC
+03 0A 00 00 00  ; num 10   - stack: [ 10 ]
+07              ; 1-       - stack: [ 9 ]
+07              ; 1-       - stack: [ 8 ]
+#+END_SRC
+
+** Common Pattern: Countdown Loop
+
+#+BEGIN_SRC
+: loop ( n -- )
+  begin
+    dup .        ; display counter
+    1- dup       ; decrement and copy for test
+  0= until       ; loop until zero
+  drop           ; clean up
+;
+
+A loop          ; prints A, 9, 8, ... 1
+#+END_SRC
+
+** Important Notes
+
+- Modifies the value in place (no additional stack space needed)
+- Works identically on signed and unsigned 32-bit values
+- For subtracting larger values, use =-= (opcode 25)
+
+---------------------------------------------------------------------
+
+* 8: dup (Duplicate)
+:PROPERTIES:
+:CUSTOM_ID: opcode-dup
+:ID:       2a6a449a-fc76-421c-a81c-c2024a15fc78
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 8                  |
+| Name       | dup                |
+| Stack      | ( n -- n n )       |
+| Bytecode   | Single byte: =08=  |
+
+** Description
+
+Duplicates the value on top of the data stack, pushing a copy. The
+original value remains, and an identical copy is placed on top.
+
+** When to Use
+
+- Preserving a value before consuming operations
+- Using the same value multiple times in a calculation
+- Displaying values without losing them
+- Setting up parameters for operations that consume values
+
+** Example
+
+#+BEGIN_SRC
+03 2A 00 00 00  ; num 42   - stack: [ 42 ]
+08              ; dup      - stack: [ 42 42 ]
+#+END_SRC
+
+** Common Patterns
+
+*** Read and Keep Address
+
+#+BEGIN_SRC
+addr dup @      ; stack: [ addr value ]
+                ; read from address while keeping the address
+#+END_SRC
+
+*** Display and Keep
+
+#+BEGIN_SRC
+value dup .     ; display value while keeping it on stack
+#+END_SRC
+
+*** Test Without Consuming
+
+#+BEGIN_SRC
+value dup 0=    ; test if zero, keep original value
+if
+  ...           ; handle zero case (value still on stack)
+then
+drop            ; now consume it
+#+END_SRC
+
+** Important Notes
+
+- Increases stack depth by 1
+- Often paired with =drop= to test values without consuming them
+- For duplicating the second stack item, use =over= (opcode 22)
+
+---------------------------------------------------------------------
+
+* 9: drop (Discard)
+:PROPERTIES:
+:CUSTOM_ID: opcode-drop
+:ID:       4600dbeb-1833-4e7d-af7e-f6cc6c98d022
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 9                  |
+| Name       | drop               |
+| Stack      | ( n -- )           |
+| Bytecode   | Single byte: =09=  |
+
+** Description
+
+Removes and discards the value from the top of the data stack. The
+value is completely lost.
+
+** When to Use
+
+- Cleaning up the stack after calculations
+- Discarding values that are no longer needed
+- Consuming function results you don't need
+- Balancing stack operations
+
+** Example
+
+#+BEGIN_SRC
+03 2A 00 00 00  ; num 42   - stack: [ 42 ]
+03 64 00 00 00  ; num 100  - stack: [ 42 100 ]
+09              ; drop     - stack: [ 42 ]
+09              ; drop     - stack: [ ]
+#+END_SRC
+
+** Common Patterns
+
+*** Discard Unused Return Values
+
+#+BEGIN_SRC
+some-operation drop    ; call operation, ignore result
+#+END_SRC
+
+*** Execute for Side Effect Only
+
+#+BEGIN_SRC
+addr @ drop    ; read from memory, discard value
+               ; useful for prefetching or triggering hardware
+#+END_SRC
+
+*** Clean Up After Conditional
+
+#+BEGIN_SRC
+condition if
+  ...          ; condition was true (consumed by if)
+else
+  ...          ; condition was false
+then
+#+END_SRC
+
+** Important Notes
+
+- Reduces stack depth by 1
+- The value is completely lost; ensure you don't need it
+- Often paired with =dup= for testing values without consuming them
+- For discarding two values, use =2drop= (defined in high-level Fifth)
diff --git a/Documentation/opcodes_10_19.org b/Documentation/opcodes_10_19.org
new file mode 100644 (file)
index 0000000..336b62b
--- /dev/null
@@ -0,0 +1,504 @@
+#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
+#+TITLE: Fifth - virtual machine opcodes 10 -- 19
+#+AUTHOR: Svjatoslav Agejenko
+#+LANGUAGE: en
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+  .flex-center {
+    display: flex;            /* activate flexbox */
+    justify-content: center;  /* horizontally center anything inside   */
+  }
+
+  .flex-center video {
+    width: min(90%, 1000px); /* whichever is smaller wins */
+    height: auto;            /* preserve aspect ratio */
+  }
+
+  .responsive-img {
+    width: min(100%, 1000px);
+    height: auto;
+  }
+</style>
+#+end_export
+
+* Overview
+
+This document describes virtual machine opcodes 10 through 19. These
+opcodes provide conditional branching, subroutine return, byte-level
+memory access, stack-to-return-stack operations, stack rotation, and
+disk I/O.
+
+*Quick Reference:*
+
+| Opcode | Name   | Stack Effect   | Bytecode Size | Purpose                                         |
+|--------+--------+----------------+---------------+-------------------------------------------------|
+|     10 | if     | flag --        | 5 bytes       | Conditional jump (jump if zero)                 |
+|     11 | ret    | --             | 1 byte        | Return from subroutine                          |
+|     12 | c@     | addr -- byte   | 1 byte        | Read byte from memory                           |
+|     13 | c!     | byte addr --   | 1 byte        | Write byte to memory                            |
+|     14 | push   | n --           | 1 byte        | Move data to return stack                       |
+|     15 | pop    | -- n           | 1 byte        | Move data from return stack                     |
+|     16 | unused | --             | 1 byte        | Reserved for future use. Currently acts as nop. |
+|     17 | rot    | a b c -- b c a | 1 byte        | Rotate three stack elements                     |
+|     18 | disk@  | sector addr -- | 1 byte        | Read 1KB sector from disk                       |
+|     19 | disk!  | addr sector -- | 1 byte        | Write 1KB sector to disk                        |
+
+* 10: if (Conditional Jump)
+:PROPERTIES:
+:CUSTOM_ID: opcode-if
+:ID:       d6f834b6-9a37-4414-91b3-62b3e1d920c1
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value                                    |
+|------------+------------------------------------------|
+| Opcode     | 10 (0x0A)                                |
+| Name       | if                                       |
+| Stack      | ( flag -- )                              |
+| Bytecode   | =0A= followed by 4-byte target address   |
+
+*Description:*
+
+Pops the top value from the data stack. If the value is zero, jumps to
+the address embedded in the instruction stream. If the value is
+non-zero, skips the address and continues with the next instruction.
+
+This "jump if false" semantics is exactly what is needed to jump/skip
+over code because comparison condition was not met:
+
+: #1: <comparison logic, leaves comparison result on the top of data stack>
+: #2: <jmp instruction + pointer to #4 address>
+: #3:   <this code will be executed conditionally, if comparison was true>
+: #4: <any other code that follows after IF ... THEN ... block.>
+
+
+*Bytecode Format:*
+
+#+BEGIN_SRC
+0A aa aa aa aa
+│  └──────────┘ 32-bit target address (little-endian)
+└ opcode
+#+END_SRC
+
+*When to Use*
+
+- Implementing conditional branches in control structures
+- Building if-then-else constructs (the "else" branch)
+- Loop exit conditions
+
+*Important Notes:*
+
+- The jump is taken when flag is ZERO (false condition)
+- This is actually "jump if false" semantics
+- High-level Fifth words like =if= =then= =else= compile to this opcode
+- The address is a virtual address in the VM's address space
+
+* 11: ret (Return from Subroutine)
+:PROPERTIES:
+:CUSTOM_ID: opcode-ret
+:ID:       6e683977-a985-4bb8-9d2c-c860d30e1df6
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property | Value             |
+|----------+-------------------|
+| Opcode   | 11 (0x0B)         |
+| Name     | ret               |
+| Stack    | ( -- )            |
+| R. Stack | ( ret-addr -- )   |
+| Bytecode | Single byte: =0B= |
+
+*Description:*
+
+Returns from a subroutine by popping the return address from the
+return stack and jumping to it. This is the counterpart to the =call=
+opcode (5).
+
+
+*When to Use:*
+
+- Ending subroutine/word definitions
+- Early exit from subroutines
+
+*Example:*
+
+#+BEGIN_SRC
+; Subroutine at address 0x2000:
+03 2A 00 00 00          ; num 42 - push a value
+0B                      ; ret - return to caller
+#+END_SRC
+
+In Fifth source code:
+
+#+BEGIN_SRC fifth
+: myword ( -- n )
+  2A                    \ push 42
+;                       \ compiles to ret
+#+END_SRC
+
+** Important Notes
+
+- Each =ret= must have a matching =call= to maintain return stack balance
+- Unbalanced call/ret pairs will corrupt the return stack
+- The return stack is also used by =push= and =pop= opcodes
+- Return addresses are virtual addresses (without xms_addr offset)
+
+* 12: c@ (Fetch Byte from Memory)
+:PROPERTIES:
+:CUSTOM_ID: opcode-cfetch
+:ID:       a2ce44f7-b661-44e0-909b-644ff52aa38e
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 12 (0x0C)          |
+| Name       | c@ (c-fetch)       |
+| Stack      | ( addr -- byte )   |
+| Bytecode   | Single byte: =0C=  |
+
+*Description:*
+
+Reads a single byte from the specified memory address and pushes it
+onto the data stack. The byte value is zero-extended to 32 bits
+(padded with zeros in the upper 24 bits).
+
+*When to Use:*
+
+- Reading character data from strings
+- Parsing binary data structures
+- Reading individual pixels from image buffers
+
+
+*Example:*
+
+Read a byte from address 0x1000:
+
+#+BEGIN_SRC
+03 00 10 00 00      ; num 0x1000 - push address
+0C                  ; c@ - read byte
+; Stack now contains: byte-value (0-255, zero-extended)
+#+END_SRC
+
+
+*Important Notes:*
+
+- The byte is zero-extended: reading 0xFF gives 0x000000FF on stack
+- The address is a virtual address (xms_addr is added internally)
+
+* 13: c! (Store Byte to Memory)
+:PROPERTIES:
+:CUSTOM_ID: opcode-cstore
+:ID:       f129ef87-a31a-40fe-b8d3-984da2db90e2
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 13 (0x0D)          |
+| Name       | c! (c-store)       |
+| Stack      | ( byte addr -- )   |
+| Bytecode   | Single byte: =0D=  |
+
+*Description:*
+
+Stores a single byte to the specified memory address. The byte value
+is taken from the low 8 bits of the value on the stack. The upper 24
+bits are ignored.
+
+*When to Use:*
+
+- Writing character data to strings
+- Building binary data structures
+- Drawing individual pixels to image buffers
+
+*Example:*
+
+Store byte 0x42 at address 0x1000:
+
+#+BEGIN_SRC
+03 42 00 00 00      ; num 0x42 - byte value to store
+03 00 10 00 00      ; num 0x1000 - destination address
+0D                  ; c! - store byte
+; Memory at 0x1000 now contains 0x42
+#+END_SRC
+
+
+*Important Notes:*
+
+- Upper 24 bits are ignored (no error if value > 255)
+- The address is a virtual address
+
+* 14: push (Move Data to Return Stack)
+:PROPERTIES:
+:CUSTOM_ID: opcode-push
+:ID:       e4bcbaf1-7724-4051-b19c-1aa7cd06eae6
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 14 (0x0E)          |
+| Name       | push               |
+| Stack      | ( n -- )           |
+| R. Stack   | ( -- n )           |
+| Bytecode   | Single byte: =0E=  |
+
+*Description:*
+
+Moves the top value from the data stack to the return stack. This
+provides temporary storage that doesn't interfere with data stack
+operations.
+
+*When to Use:*
+
+- Temporarily saving values during complex stack manipulations
+
+*Example:*
+
+Save a value for later retrieval:
+
+#+BEGIN_SRC
+03 2A 00 00 00      ; num 42 - push value onto data stack
+0E                  ; push - move 42 to return stack
+; Data stack is now empty
+; Return stack now contains 42
+
+; ... do other work ...
+
+0F                  ; pop - retrieve 42 from return stack
+; Data stack now contains 42
+#+END_SRC
+
+
+*Important Notes:*
+
+- Must be balanced with =pop= to avoid return stack corruption
+- Do not mix carelessly with =call= /=ret= pairs
+- The return stack grows downward (like the data stack)
+- Popping too many times can corrupt return addresses
+
+* 15: pop (Move Data from Return Stack)
+:PROPERTIES:
+:CUSTOM_ID: opcode-pop
+:ID:       21871d09-4d58-440f-8c94-231105aa4e3f
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 15 (0x0F)          |
+| Name       | pop                |
+| Stack      | ( -- n )           |
+| R. Stack   | ( n -- )           |
+| Bytecode   | Single byte: =0F=  |
+
+*Description:*
+
+Moves the top value from the return stack to the data stack. This is
+the inverse of the =push= opcode.
+
+*When to Use:*
+
+- Retrieving temporarily saved values
+
+*Example:*
+
+Retrieve a saved value:
+
+#+BEGIN_SRC
+; Assuming return stack contains 42 (from previous 'push')
+0F                  ; pop - move 42 from return stack to data stack
+; Data stack now contains 42
+; Return stack top item removed
+#+END_SRC
+
+Important Notes:
+- Popping from an empty return stack causes undefined behavior
+- Always ensure there's a value on the return stack before calling =pop=
+- Balance every =push= with a corresponding =pop=
+
+** Related Opcode: i
+
+The =i= opcode (31) copies (rather than moves) the top of the return
+stack to the data stack, leaving the return stack unchanged.
+
+| Opcode | Action                 | R. Stack Effect |
+|--------+------------------------+-----------------|
+| i      | Copy top to data stack | <unchanged>     |
+| pop    | Move top to data stack | n --            |
+
+* 16: (Unused/Reserved)
+:PROPERTIES:
+:CUSTOM_ID: opcode-unused
+:END:
+
+Opcode 16 (0x10) is reserved for future use. Opcode currently behaves as *nop* instruction.
+
+* 17: rot (Rotate Three Stack Elements)
+:PROPERTIES:
+:CUSTOM_ID: opcode-rot
+:ID:       4cee73f7-c105-4b96-9380-ff89bd7fedad
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value                      |
+|------------+----------------------------|
+| Opcode     | 17 (0x11)                  |
+| Name       | rot                        |
+| Stack      | ( n1 n2 n3 -- n2 n3 n1 )   |
+| Bytecode   | Single byte: =11=          |
+
+*Description*
+
+Rotates the top three values on the data stack. The third item from
+the top moves to the top, while the top two items shift down.
+
+*Visual Representation:*
+#+BEGIN_SRC
+Before:  [ ... n1 n2 n3 ]   (n3 is on top)
+After:   [ ... n2 n3 n1 ]   (n1 is now on top)
+#+END_SRC
+
+Rotation direction: the deepest of the three (n1) rotates to the top.
+
+*When to Use:*
+- Accessing values buried deeper on the stack
+- Swapping values in multi-item calculations
+
+
+*Example:*
+
+#+BEGIN_SRC
+03 01 00 00 00      ; num 1 - push n1
+03 02 00 00 00      ; num 2 - push n2
+03 03 00 00 00      ; num 3 - push n3
+; Stack: [ 1 2 3 ] with 3 on top
+
+11                  ; rot
+; Stack: [ 2 3 1 ] with 1 on top
+#+END_SRC
+
+Important Notes:
+
+- Requires at least three items on the data stack
+- Rotating with fewer items causes undefined behavior
+- This is a rotation, not a swap - all three elements move
+
+* 18: disk@ (Read Disk Sector)
+:PROPERTIES:
+:CUSTOM_ID: opcode-disk-read
+:ID:       bed1aa27-66ac-4c73-bbb9-e49ff2aa67c5
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value                    |
+|------------+--------------------------|
+| Opcode     | 18 (0x12)                |
+| Name       | disk@ (disk-fetch)       |
+| Stack      | ( sector addr -- )       |
+| Bytecode   | Single byte: =12=        |
+
+*Description:*
+
+Reads one sector (1024 bytes) from the virtual disk into memory at the
+specified address.
+
+*Parameters:*
+
+- *sector* (top of stack): Sector number to read from (0-based)
+- *addr* (second): Destination memory address for the data
+
+*When to Use:*
+
+- Loading program code from disk
+- Reading data files
+- Accessing filesystem structures
+
+*Example:*
+
+Read sector 16 into memory at 0x2000:
+
+#+BEGIN_SRC
+03 10 00 00 00      ; num 16 - sector number
+03 00 20 00 00      ; num 0x2000 - destination address
+12                  ; disk@ - read sector
+; 1024 bytes from sector 16 now at address 0x2000
+#+END_SRC
+
+** Technical Details
+
+- One sector = 1024 bytes (1 KB)
+- Sector numbering starts at 0
+- Uses DOS file I/O to access the virtual disk image
+- The virtual disk is typically a file named =disk.img= or similar
+
+** Important Notes
+
+- The address is a virtual address in the VM's address space
+- Reading beyond the end of the disk file may return zeros or cause errors
+- The disk is accessed through DOS file handles, not BIOS interrupts
+
+* 19: disk! (Write Disk Sector)
+:PROPERTIES:
+:CUSTOM_ID: opcode-disk-write
+:ID:       02eda775-e483-4057-b809-de36d586579b
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value                    |
+|------------+--------------------------|
+| Opcode     | 19 (0x13)                |
+| Name       | disk! (disk-store)       |
+| Stack      | ( addr sector -- )       |
+| Bytecode   | Single byte: =13=        |
+
+*Description*
+
+Writes one sector (1024 bytes) from memory to the virtual disk at the
+specified sector number.
+
+*Parameters:*
+
+- *addr* (top of stack): Source memory address
+- *sector* (second): Sector number to write to (0-based)
+
+*When to Use:*
+
+- Saving program data to disk
+- Modifying filesystem structures
+- Persisting state across emulator sessions
+
+*Example:*
+
+Write memory at 0x2000 to sector 16:
+
+#+BEGIN_SRC
+03 00 20 00 00      ; num 0x2000 - source address
+03 10 00 00 00      ; num 16 - sector number
+13                  ; disk! - write sector
+; 1024 bytes from address 0x2000 written to sector 16
+#+END_SRC
+
+*Technical Details:*
+
+- One sector = 1024 bytes (1 KB)
+- Data is first copied to a temporary buffer in conventional memory
+  before being written to disk (required for XMS memory access)
+- Writing to sector 0 may corrupt the bootloader/kernel
+
+*Stack Order Note:*
+
+The stack order is =( addr sector -- )=, which is reversed from
+=disk@= =( sector addr -- )=. This is because the data source (addr)
+is "produced" first, then the destination (sector) is specified.
+
+*Important Notes*
+
+- The address is a virtual address
+- Writing to the disk image is immediate (no buffering)
+- Be careful not to overwrite critical sectors (kernel, filesystem)
diff --git a/Documentation/opcodes_20_29.org b/Documentation/opcodes_20_29.org
new file mode 100644 (file)
index 0000000..35adc9b
--- /dev/null
@@ -0,0 +1,953 @@
+#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
+#+TITLE: Fifth - virtual machine opcodes 20 -- 29
+#+AUTHOR: Svjatoslav Agejenko
+#+LANGUAGE: en
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+  .flex-center {
+    display: flex;            /* activate flexbox */
+    justify-content: center;  /* horizontally center anything inside   */
+  }
+
+  .flex-center video {
+    width: min(90%, 1000px); /* whichever is smaller wins */
+    height: auto;            /* preserve aspect ratio */
+  }
+
+  .responsive-img {
+    width: min(100%, 1000px);
+    height: auto;
+  }
+</style>
+#+end_export
+
+* Overview
+
+This document describes virtual machine opcodes 20 through 29. These are
+fundamental instructions for memory access, stack manipulation, arithmetic
+operations, and value comparison.
+
+** Quick Reference
+
+| Opcode | Name  | Stack Effect      | Bytecode Size | Purpose                          |
+|--------+-------+-------------------+---------------+----------------------------------|
+|     20 | @     | addr -- value     | 1 byte        | Fetch 32-bit value from memory   |
+|     21 | !     | value addr --     | 1 byte        | Store 32-bit value to memory     |
+|     22 | over  | n1 n2 -- n1 n2 n1 | 1 byte        | Duplicate second stack item      |
+|     23 | swap  | n1 n2 -- n2 n1    | 1 byte        | Exchange top two stack items     |
+|     24 | +     | n1 n2 -- n1+n2    | 1 byte        | Add two 32-bit values            |
+|     25 | -     | n1 n2 -- n1-n2    | 1 byte        | Subtract two 32-bit values       |
+|     26 | *     | n1 n2 -- n1*n2    | 1 byte        | Multiply two 32-bit values       |
+|     27 | /     | n1 n2 -- n1/n2    | 1 byte        | Divide two 32-bit values         |
+|     28 | >     | n1 n2 -- flag     | 1 byte        | Greater than comparison          |
+|     29 | <     | n1 n2 -- flag     | 1 byte        | Less than comparison             |
+
+* 20: @ (Fetch)
+:PROPERTIES:
+:CUSTOM_ID: opcode-fetch
+:ID:       0a54f24b-e62a-4244-85e1-855a0007c81e
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 20                 |
+| Name       | @                  |
+| Stack      | ( addr -- value )  |
+| Bytecode   | Single byte: =14=  |
+
+** Description
+
+Reads a 32-bit value from the specified memory address and replaces
+the address with the fetched value on the data stack. This is the
+primary operation for reading data from memory.
+
+** Memory Access
+
+The operation performs virtual address translation:
+
+1. Takes virtual address from top of data stack
+2. Converts to physical address by adding =xms_addr=
+3. Reads 32-bit value from physical memory
+4. Replaces address with value on stack
+
+** When to Use
+
+- Reading variables and data structures from memory
+- Accessing array elements
+- Loading values for computation
+- Implementing high-level words that need memory access
+- Reading hardware registers (when mapped to memory)
+
+** Example
+
+Read a value from address =0x1000=:
+
+#+BEGIN_SRC
+03 00 10 00 00  ; num 0x1000 - push address 0x1000
+14              ; @ - read 32-bit value from 0x1000
+                ; stack now contains the value from address 0x1000
+#+END_SRC
+
+In Fifth source code:
+
+#+BEGIN_SRC fifth
+0x1000 @        \ read 32-bit value from address 0x1000
+#+END_SRC
+
+** Important Notes
+
+- This is the 32-bit equivalent of =c@= (opcode 16)
+- Virtual address translation provides memory management
+- Reads full 32-bit words, not bytes
+- The address is consumed and replaced with the value
+- No bounds checking is performed
+
+** Common Patterns
+
+*** Read and Use
+
+#+BEGIN_SRC fifth
+addr @ .        \ read from address and display
+#+END_SRC
+
+*** Array Access
+
+#+BEGIN_SRC fifth
+base index 4 * + @  \ read array[index] (32-bit elements)
+#+END_SRC
+
+---------------------------------------------------------------------
+
+* 21: ! (Store)
+:PROPERTIES:
+:CUSTOM_ID: opcode-store
+:ID:       50e0c841-d678-41b4-be5a-1bab792f367d
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 21                 |
+| Name       | !                  |
+| Stack      | ( value addr -- )  |
+| Bytecode   | Single byte: =15=  |
+
+** Description
+
+Stores a 32-bit value to the specified memory address. Both the value
+and address are consumed from the data stack, leaving a clean stack.
+
+** Memory Access
+
+The operation performs virtual address translation:
+
+1. Takes address from top of stack
+2. Takes value to store from second on stack
+3. Converts virtual address to physical address
+4. Stores 32-bit value to physical memory
+5. Removes both arguments from stack
+
+** When to Use
+
+- Writing variables and data structures to memory
+- Storing array elements
+- Saving computation results
+- Implementing high-level words that modify memory
+- Writing to hardware registers (when mapped to memory)
+
+** Example
+
+Store value =0x12345678= to address =0x1000=:
+
+#+BEGIN_SRC
+03 78 56 34 12  ; num 0x12345678 - push value to store
+03 00 10 00 00  ; num 0x1000 - push destination address
+15              ; ! - store value to address
+                ; stack is now empty
+#+END_SRC
+
+In Fifth source code:
+
+#+BEGIN_SRC fifth
+0x12345678 0x1000 !  \ store 0x12345678 at address 0x1000
+#+END_SRC
+
+** Important Notes
+
+- This is the 32-bit equivalent of =c!= (opcode 17)
+- Virtual address translation provides memory protection
+- Order is value then addr (Forth standard: value to address)
+- Both arguments are consumed (stack cleaned up)
+- No bounds checking is performed
+- Overwrites existing data at the target address
+
+** Common Patterns
+
+*** Store Constant
+
+#+BEGIN_SRC fifth
+42 addr !       \ store constant 42 at addr
+#+END_SRC
+
+*** Array Assignment
+
+#+BEGIN_SRC fifth
+value base index 4 * + !  \ array[index] = value (32-bit elements)
+#+END_SRC
+
+*** Computed Store
+
+#+BEGIN_SRC fifth
+a b + addr !    \ store (a + b) at addr
+#+END_SRC
+
+---------------------------------------------------------------------
+
+* 22: over (Over)
+:PROPERTIES:
+:CUSTOM_ID: opcode-over
+:ID:       29828b20-b14d-41ff-9705-ca576c352fb4
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 22                 |
+| Name       | over               |
+| Stack      | ( n1 n2 -- n1 n2 n1 ) |
+| Bytecode   | Single byte: =16=  |
+
+** Description
+
+Duplicates the second item on the data stack, placing a copy on top.
+This allows access to the second item without disturbing the top item.
+
+** Stack Behavior
+
+The operation preserves the original order while adding a copy:
+
+#+BEGIN_SRC
+Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
+After:  [ n1 n2 n1 ]  (new n1 = TOS)
+#+END_SRC
+
+** When to Use
+
+- Preserving values while using the top item
+- Accessing the second item when you need to keep the top
+- Setting up multiple uses of the same value
+- Implementing arithmetic operations that need the original value
+- Creating stack patterns for complex operations
+
+** Example
+
+Duplicate the second item:
+
+#+BEGIN_SRC
+03 01 00 00 00  ; num 1    - stack: [ 1 ]
+03 02 00 00 00  ; num 2    - stack: [ 1 2 ]
+16              ; over     - stack: [ 1 2 1 ]
+#+END_SRC
+
+In Fifth source code:
+
+#+BEGIN_SRC fifth
+1 2 over        \ stack: 1 2 1
+#+END_SRC
+
+** Important Notes
+
+- Essential for preserving values while using the top item
+- More efficient than dup+swap+drop combination
+- Increases stack depth by 1
+- Often paired with arithmetic operations
+- Fundamental stack manipulation word
+
+** Common Patterns
+
+*** Compare Without Consuming
+
+#+BEGIN_SRC fifth
+a b over >      \ compare a with b, keeping both on stack
+#+END_SRC
+
+*** Use Value Twice
+
+#+BEGIN_SRC fifth
+a b over +      \ compute a + b, keeping a on stack
+#+END_SRC
+
+*** Save Address for Later Use
+
+#+BEGIN_SRC fifth
+addr over @     \ read from addr, keeping addr for later use
+#+END_SRC
+
+---------------------------------------------------------------------
+
+* 23: swap (Swap)
+:PROPERTIES:
+:CUSTOM_ID: opcode-swap
+:ID:       905894ae-d687-47cd-add0-f1904179a8a0
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 23                 |
+| Name       | swap               |
+| Stack      | ( n1 n2 -- n2 n1 ) |
+| Bytecode   | Single byte: =17=  |
+
+** Description
+
+Exchanges the top two values on the data stack. This is essential for
+reordering arguments when the natural stack order doesn't match the
+required order for operations.
+
+** Stack Behavior
+
+The operation reverses the order of the top two items:
+
+#+BEGIN_SRC
+Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
+After:  [ n2 n1 ]    (n1 = TOS, n2 = second)
+#+END_SRC
+
+** When to Use
+
+- Reordering arguments for arithmetic operations
+- Fixing stack order after computations
+- Implementing algorithms that need specific operand order
+- Exchanging values in sorting algorithms
+- Correcting stack order for function calls
+
+** Example
+
+Exchange the top two values:
+
+#+BEGIN_SRC
+03 01 00 00 00  ; num 1    - stack: [ 1 ]
+03 02 00 00 00  ; num 2    - stack: [ 1 2 ]
+17              ; swap     - stack: [ 2 1 ]
+#+END_SRC
+
+In Fifth source code:
+
+#+BEGIN_SRC fifth
+1 2 swap        \ stack: 2 1
+#+END_SRC
+
+** Important Notes
+
+- Fundamental stack manipulation operation
+- Used extensively for argument reordering
+- More efficient than multiple push/pop operations
+- Stack depth remains unchanged
+- Essential for correct operand order in arithmetic
+
+** Common Patterns
+
+*** Fix Subtraction Order
+
+#+BEGIN_SRC fifth
+min max swap -  \ compute max - min
+#+END_SRC
+
+*** Correct Division Order
+
+#+BEGIN_SRC fifth
+divisor dividend swap /  \ compute dividend / divisor
+#+END_SRC
+
+*** Exchange Variables
+
+#+BEGIN_SRC fifth
+addr1 @ addr2 @ swap  \ read two values and exchange them
+addr1 ! addr2 !       \ store them back in exchanged order
+#+END_SRC
+
+---------------------------------------------------------------------
+
+* 24: + (Add)
+:PROPERTIES:
+:CUSTOM_ID: opcode-add
+:ID:       bf4434bb-91a5-40c1-93de-90a0e05a50ec
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 24                 |
+| Name       | +                  |
+| Stack      | ( n1 n2 -- n1+n2 ) |
+| Bytecode   | Single byte: =18=  |
+
+** Description
+
+Adds the top two values on the data stack, replacing them with the sum.
+This is a fundamental arithmetic operation for mathematical computations.
+
+** Operation
+
+The operation performs unsigned 32-bit addition:
+
+#+BEGIN_SRC
+Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
+After:  [ sum ]      (sum = n1 + n2)
+#+END_SRC
+
+** When to Use
+
+- Basic arithmetic calculations
+- Computing sums and totals
+- Pointer arithmetic
+- Incrementing values by arbitrary amounts
+- Mathematical expressions and formulas
+
+** Example
+
+Add two numbers:
+
+#+BEGIN_SRC
+03 05 00 00 00  ; num 5    - stack: [ 5 ]
+03 03 00 00 00  ; num 3    - stack: [ 5 3 ]
+18              ; +        - stack: [ 8 ]
+#+END_SRC
+
+In Fifth source code:
+
+#+BEGIN_SRC fifth
+5 3 +           \ result: 8
+#+END_SRC
+
+** Important Notes
+
+- Performs unsigned 32-bit addition
+- Overflow wraps around modulo 2^32
+- Operates in place for efficiency (no extra stack slot needed)
+- Reduces stack depth by 1
+- Commutative operation (a + b = b + a)
+
+** Common Patterns
+
+*** Increment by Value
+
+#+BEGIN_SRC fifth
+value increment +  \ value = value + increment
+#+END_SRC
+
+*** Pointer Arithmetic
+
+#+BEGIN_SRC fifth
+ptr 4 +          \ advance pointer by 4 bytes
+#+END_SRC
+
+*** Sum Multiple Values
+
+#+BEGIN_SRC fifth
+a b + c + d +   \ compute a + b + c + d
+#+END_SRC
+
+** Edge Cases
+
+- =0xFFFFFFFF + 1 = 0= (wrap around)
+- =Any number + 0 = same number=
+- Large additions may overflow
+
+---------------------------------------------------------------------
+
+* 25: - (Subtract)
+:PROPERTIES:
+:CUSTOM_ID: opcode-sub
+:ID:       9afc77fc-ecee-4a69-b1d2-f511e64a0d72
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 25                 |
+| Name       | -                  |
+| Stack      | ( n1 n2 -- n1-n2 ) |
+| Bytecode   | Single byte: =19=  |
+
+** Description
+
+Subtracts the top value from the second value on the data stack. The
+result replaces both values. This operation is not commutative - order
+matters.
+
+** Operation
+
+The operation performs unsigned 32-bit subtraction:
+
+#+BEGIN_SRC
+Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
+After:  [ diff ]     (diff = n1 - n2)
+#+END_SRC
+
+** When to Use
+
+- Computing differences between values
+- Decrementing by arbitrary amounts
+- Distance calculations
+- Mathematical expressions requiring subtraction
+- Reverse arithmetic operations
+
+** Example
+
+Subtract two numbers:
+
+#+BEGIN_SRC
+03 0A 00 00 00  ; num 10   - stack: [ 10 ]
+03 03 00 00 00  ; num 3    - stack: [ 10 3 ]
+19              ; -        - stack: [ 7 ]
+#+END_SRC
+
+In Fifth source code:
+
+#+BEGIN_SRC fifth
+10 3 -          \ result: 7 (10 - 3)
+#+END_SRC
+
+** Important Notes
+
+- Performs unsigned 32-bit subtraction
+- Underflow wraps around modulo 2^32
+- Operates in place for efficiency
+- Reduces stack depth by 1
+- NOT commutative (a - b ≠ b - a)
+- Order: second item minus top item
+
+** Common Patterns
+
+*** Decrement by Value
+
+#+BEGIN_SRC fifth
+value decrement -  \ value = value - decrement
+#+END_SRC
+
+*** Distance Calculation
+
+#+BEGIN_SRC fifth
+end start -      \ compute distance from start to end
+#+END_SRC
+
+*** Reverse Subtraction
+
+#+BEGIN_SRC fifth
+a b swap -       \ compute b - a instead of a - b
+#+END_SRC
+
+** Edge Cases
+
+- =0 - 1 = 0xFFFFFFFF= (wrap around)
+- =Any number - 0 = same number=
+- =n - n = 0= for any n
+
+---------------------------------------------------------------------
+
+* 26: * (Multiply)
+:PROPERTIES:
+:CUSTOM_ID: opcode-mul
+:ID:       85833e5c-e3ae-41a7-ad3d-6e9f0ecc9cdb
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 26                 |
+| Name       | *                  |
+| Stack      | ( n1 n2 -- n1*n2 ) |
+| Bytecode   | Single byte: =1A=  |
+
+** Description
+
+Multiplies the top two values on the data stack using signed 32-bit
+multiplication. The result is the low 32 bits of the product.
+
+** Operation
+
+The operation performs signed 32-bit multiplication:
+
+#+BEGIN_SRC
+Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
+After:  [ product ]  (product = n1 * n2)
+#+END_SRC
+
+** When to Use
+
+- Multiplication operations
+- Area calculations
+- Scaling values
+- Mathematical formulas
+- Computing products and multiples
+
+** Example
+
+Multiply two numbers:
+
+#+BEGIN_SRC
+03 05 00 00 00  ; num 5    - stack: [ 5 ]
+03 03 00 00 00  ; num 3    - stack: [ 5 3 ]
+1A              ; *        - stack: [ 15 ]
+#+END_SRC
+
+In Fifth source code:
+
+#+BEGIN_SRC fifth
+5 3 *           \ result: 15
+#+END_SRC
+
+** Important Notes
+
+- Uses IMUL instruction (signed multiplication)
+- Result is low 32 bits only (high bits in edx are discarded)
+- Handles both positive and negative numbers correctly
+- Overflow behavior: result wraps around modulo 2^32
+- Reduces stack depth by 1
+- Commutative operation (a * b = b * a)
+
+** Common Patterns
+
+*** Area Calculation
+
+#+BEGIN_SRC fifth
+width height *   \ compute area of rectangle
+#+END_SRC
+
+*** Scaling
+
+#+BEGIN_SRC fifth
+value scale *    \ scale value by factor
+#+END_SRC
+
+*** Power of Two
+
+#+BEGIN_SRC fifth
+value 2 *        \ multiply by 2 (equivalent to shift left by 1)
+#+END_SRC
+
+** Edge Cases
+
+- =0 * anything = 0=
+- =1 * anything = anything=
+- =(-1) * (-1) = 1=
+- Large products may overflow (wrap around)
+
+---------------------------------------------------------------------
+
+* 27: / (Divide)
+:PROPERTIES:
+:CUSTOM_ID: opcode-div
+:ID:       e5ff13c7-a9e6-4035-8efd-220d05381bf1
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 27                 |
+| Name       | /                  |
+| Stack      | ( n1 n2 -- n1/n2 ) |
+| Bytecode   | Single byte: =1B=  |
+
+** Description
+
+Divides the second value by the top value using signed 32-bit division.
+Returns the quotient only (remainder is discarded).
+
+** Operation
+
+The operation performs signed 32-bit division:
+
+#+BEGIN_SRC
+Before: [ n1 n2 ]    (n2 = divisor = TOS, n1 = dividend = second)
+After:  [ quotient ] (quotient = n1 / n2)
+#+END_SRC
+
+** When to Use
+
+- Division operations
+- Averaging calculations
+- Ratio computations
+- Mathematical formulas requiring division
+- Splitting quantities into equal parts
+
+** Example
+
+Divide two numbers:
+
+#+BEGIN_SRC
+03 0F 00 00 00  ; num 15   - stack: [ 15 ]
+03 03 00 00 00  ; num 3    - stack: [ 15 3 ]
+1B              ; /        - stack: [ 5 ]
+#+END_SRC
+
+In Fifth source code:
+
+#+BEGIN_SRC fifth
+15 3 /          \ result: 5 (15 / 3)
+#+END_SRC
+
+** Important Notes
+
+- Uses IDIV instruction (signed division)
+- Returns quotient only (remainder discarded)
+- Handles both positive and negative numbers correctly
+- Division by zero causes CPU exception (not handled)
+- Reduces stack depth by 1
+- NOT commutative (a / b ≠ b / a)
+- Order: second item divided by top item
+
+** Common Patterns
+
+*** Average Calculation
+
+#+BEGIN_SRC fifth
+a b + 2 /       \ compute average of a and b
+#+END_SRC
+
+*** Split into Parts
+
+#+BEGIN_SRC fifth
+total parts /   \ divide total into equal parts
+#+END_SRC
+
+*** Correct Division Order
+
+#+BEGIN_SRC fifth
+dividend divisor swap /  \ compute dividend / divisor
+#+END_SRC
+
+** Edge Cases
+
+- Division by zero: CPU exception (crash)
+- =Anything / 1 = anything=
+- =0 / anything = 0=
+- Negative division follows standard signed rules
+
+** WARNING: Division by zero will crash the emulator!
+
+---------------------------------------------------------------------
+
+* 28: > (Greater Than)
+:PROPERTIES:
+:CUSTOM_ID: opcode-gt
+:ID:       abcc14d3-6cbf-46c3-8a93-ee7180f350d4
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 28                 |
+| Name       | >                  |
+| Stack      | ( n1 n2 -- flag )  |
+| Bytecode   | Single byte: =1C=  |
+
+** Description
+
+Compares the second value (a) with the top value (b). Returns -1 (true)
+if a > b, otherwise returns 0 (false). This is a fundamental comparison
+operation for conditional logic.
+
+** Operation
+
+The operation performs signed 32-bit comparison:
+
+#+BEGIN_SRC
+Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
+After:  [ flag ]     (flag = -1 if n1 > n2, 0 otherwise)
+#+END_SRC
+
+** Truth Value Convention
+
+- =-1 = true= (all bits set, non-zero)
+- =0 = false= (zero)
+
+** When to Use
+
+- Conditional branching and logic
+- Sorting algorithms
+- Range checking
+- Decision making in programs
+- Implementing high-level comparison words
+
+** Example
+
+Compare two numbers:
+
+#+BEGIN_SRC
+03 05 00 00 00  ; num 5    - stack: [ 5 ]
+03 03 00 00 00  ; num 3    - stack: [ 5 3 ]
+1C              ; >        - stack: [ 0 ] (false, 5 is not > 3)
+#+END_SRC
+
+In Fifth source code:
+
+#+BEGIN_SRC fifth
+3 5 >           \ result: 0 (false)
+5 3 >           \ result: -1 (true)
+#+END_SRC
+
+** Important Notes
+
+- Returns -1 for true (all bits set), 0 for false
+- Standard Forth truth value convention
+- Signed comparison (works for negative numbers)
+- Reduces stack depth by 1
+- NOT commutative (a > b ≠ b > a)
+
+** Common Patterns
+
+*** Conditional Execution
+
+#+BEGIN_SRC fifth
+a b > if
+  \ code for when a > b
+then
+#+END_SRC
+
+*** Range Check
+
+#+BEGIN_SRC fifth
+value max > abort" Value too large"
+#+END_SRC
+
+*** Sorting Logic
+
+#+BEGIN_SRC fifth
+a b > if swap then  \ ensure smaller value is on top
+#+END_SRC
+
+** Edge Cases
+
+- Equal values return 0 (false)
+- Negative numbers compared correctly
+- Works with full 32-bit signed range
+
+---------------------------------------------------------------------
+
+* 29: < (Less Than)
+:PROPERTIES:
+:CUSTOM_ID: opcode-lt
+:ID:       68362f38-c9e4-43f8-809c-8e15725a58c8
+:END:
+
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property   | Value              |
+|------------+--------------------|
+| Opcode     | 29                 |
+| Name       | <                  |
+| Stack      | ( n1 n2 -- flag )  |
+| Bytecode   | Single byte: =1D=  |
+
+** Description
+
+Compares the second value (a) with the top value (b). Returns -1 (true)
+if a < b, otherwise returns 0 (false). This is the complement of the
+greater than operation and essential for conditional logic.
+
+** Operation
+
+The operation performs signed 32-bit comparison:
+
+#+BEGIN_SRC
+Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
+After:  [ flag ]     (flag = -1 if n1 < n2, 0 otherwise)
+#+END_SRC
+
+** Truth Value Convention
+
+- =-1 = true= (all bits set, non-zero)
+- =0 = false= (zero)
+
+** When to Use
+
+- Conditional branching and logic
+- Sorting algorithms
+- Range checking
+- Decision making in programs
+- Implementing high-level comparison words
+- Complementary logic to greater than
+
+** Example
+
+Compare two numbers:
+
+#+BEGIN_SRC
+03 03 00 00 00  ; num 3    - stack: [ 3 ]
+03 05 00 00 00  ; num 5    - stack: [ 3 5 ]
+1D              ; <        - stack: [ -1 ] (true, 3 < 5)
+#+END_SRC
+
+In Fifth source code:
+
+#+BEGIN_SRC fifth
+3 5 <           \ result: -1 (true)
+5 3 <           \ result: 0 (false)
+#+END_SRC
+
+** Important Notes
+
+- Returns -1 for true (all bits set), 0 for false
+- Standard Forth truth value convention
+- Signed comparison (works for negative numbers)
+- Reduces stack depth by 1
+- NOT commutative (a < b ≠ b < a)
+- Complementary to > (greater than) operation
+
+** Common Patterns
+
+*** Conditional Execution
+
+#+BEGIN_SRC fifth
+a b < if
+  \ code for when a < b
+then
+#+END_SRC
+
+*** Range Check
+
+#+BEGIN_SRC fifth
+value min < abort" Value too small"
+#+END_SRC
+
+*** Sorting Logic
+
+#+BEGIN_SRC fifth
+a b < if swap then  \ ensure larger value is on top
+#+END_SRC
+
+*** Equality Check
+
+#+BEGIN_SRC fifth
+a b < if
+  \ a < b
+else
+  a b > if
+    \ a > b
+  else
+    \ a = b
+  then
+then
+#+END_SRC
+
+** Edge Cases
+
+- Equal values return 0 (false)
+- Negative numbers compared correctly
+- Works with full 32-bit signed range
+- Relationship to other comparisons: =a b <= is equivalent to= =b a > not=
+
+** Relationship to Other Comparisons
+
+The less than operation is complementary to greater than:
+
+- =a b < is equivalent to= =b a >=
+- =a b <= (less than or equal) can be implemented as=: =over over < > or=
+- =a b <> (not equal) can be implemented as=: =over over <> = drop=
\ No newline at end of file
diff --git a/Documentation/opcodes_30_39.org b/Documentation/opcodes_30_39.org
new file mode 100644 (file)
index 0000000..3d87fda
--- /dev/null
@@ -0,0 +1,240 @@
+#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
+#+TITLE: Fifth - virtual machine opcodes 30 -- 39
+#+AUTHOR: Svjatoslav Agejenko
+#+LANGUAGE: en
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+  .flex-center {
+    display: flex;            /* activate flexbox */
+    justify-content: center;  /* horizontally center anything inside   */
+  }
+
+  .flex-center video {
+    width: min(90%, 1000px); /* whichever is smaller wins */
+    height: auto;            /* preserve aspect ratio */
+  }
+
+  .responsive-img {
+    width: min(100%, 1000px);
+    height: auto;
+  }
+</style>
+#+end_export
+
+
+* 30: not
+:PROPERTIES:
+:CUSTOM_ID: opcode-not
+:ID:       21994321-a1c6-42f6-9682-d5a3fbabb88a
+:END:
+- *Stack Effect:* =n -- ~n=
+- *Description:* Performs a bitwise NOT operation on the top value of
+  the data stack.
+- *Notes:* Inverts all bits of the dword at the top of the stack.
+- *Example:*
+  #+begin_example
+  0x0000FFFF
+  not
+  #+end_example
+  After execution, stack contains 0xFFFF0000.
+
+* 31: i
+:PROPERTIES:
+:CUSTOM_ID: opcode-i
+:ID:       61fbdd36-4384-44a6-b162-b4e998c4c191
+:END:
+- *Stack Effect:* =-- r=
+- *Description:* Pushes the top value from the return stack onto the
+  data stack.
+- *Notes:* Commonly used to access loop counters or subroutine
+  parameters.
+- *Example:*
+  #+begin_example
+  42
+  push
+  i
+  #+end_example
+  After execution, data stack contains 42.
+
+* 32: cprt@
+:PROPERTIES:
+:CUSTOM_ID: opcode-cprt-read
+:ID:       78c1ac50-9c26-4132-8e02-8311331f2a1c
+:END:
+- *Stack Effect:* =port -- byte=
+- *Description:* Reads a byte from the specified hardware I/O port.
+- *Notes:* Uses IN instruction to read from the port. Replaces the port
+  address with the read byte.
+- *Example:*
+  #+begin_example
+  0x60  ; Keyboard port
+  cprt@
+  #+end_example
+
+* 33: cprt!
+:PROPERTIES:
+:CUSTOM_ID: opcode-cprt-write
+:ID:       cfa8550e-bf8b-4d44-a3d1-9ba8ad183147
+:END:
+- *Stack Effect:* =byte port --=
+- *Description:* Writes a byte to the specified hardware I/O port.
+- *Notes:* Uses OUT instruction to write to the port. Consumes both the
+  byte and port address.
+- *Example:*
+  #+begin_example
+  0x42  ; Byte to write
+  0x60  ; Keyboard port
+  cprt!
+  #+end_example
+
+* 34: i2
+:PROPERTIES:
+:CUSTOM_ID: opcode-i2
+:ID:       c3758859-c82e-40c1-9e92-87e5ef410cd2
+:END:
+- *Stack Effect:* =-- r2=
+- *Description:* Pushes the second value from the return stack onto the
+  data stack.
+- *Notes:* Useful for accessing deeper items in the return stack without
+  popping.
+- *Example:*
+  #+begin_example
+  1 2
+  push push
+  i2
+  #+end_example
+  After execution, data stack contains 1.
+
+* 35: i3
+:PROPERTIES:
+:CUSTOM_ID: opcode-i3
+:ID:       304cadf7-9725-4e2d-8634-2e67b5ad49f3
+:END:
+- *Stack Effect:* =-- r3=
+- *Description:* Pushes the third value from the return stack onto the
+  data stack.
+- *Notes:* Allows access to the third item in the return stack for
+  deeper subroutine contexts.
+- *Example:*
+  #+begin_example
+  1 2 3
+  push push push
+  i3
+  #+end_example
+  After execution, data stack contains 1.
+
+* 36: shl
+:PROPERTIES:
+:CUSTOM_ID: opcode-shl
+:ID:       978d1b75-3a1d-476f-8cdb-d3a6ee40b3f5
+:END:
+
+- *Stack Effect:* =value count -- result=
+- *Description:* Shifts =value= left by =count= bit positions. Each bit
+  position shifted left multiplies the value by 2.
+- *Bits Shifted Out:* Bits that are shifted beyond the most
+  significant bit (bit 31) are **discarded**.
+- *Count Masking:* Only the low byte of =count= is used. On x86
+  processors, the actual shift amount is further masked to 5 bits
+  (=count & 0x1F=), meaning the effective shift is always 0-31.
+
+
+*Corner Cases:*
+- =count = 0=: Value unchanged.
+- =count >= 32=: Due to 5-bit masking, the effective shift is
+  =count mod 32=. For example, shift by 32 results in no change,
+  shift by 33 shifts by 1.
+- =value = 0=: Result is always 0 regardless of count.
+
+*Examples:*
+
+#+begin_example
+1  \ Value to shift
+2  \ Shift amount (count)
+shl
+#+end_example
+Result: 4 (0b0001 << 2 = 0b0100).
+
+#+begin_example
+FF    \ Value: 255 (0x000000FF)
+4     \ Shift by 4
+shl
+#+end_example
+Result: FF0 (0x00000FF0 = 4080 decimal). The low 4 bits (F) were
+shifted up, and the upper bits remain zero.
+#+begin_example
+
+* 37: shr
+:PROPERTIES:
+:CUSTOM_ID: opcode-shr
+:ID:       9dbfcd07-6c34-41b7-b5dc-a33f0773e7cd
+:END:
+
+- *Stack Effect:* =value count -- result=
+- *Description:* Shifts =value= right by =count= bit positions. Each bit
+  position shifted right divides the value by 2 (integer division).
+- *Bits Shifted Out:* Bits that are shifted beyond the least significant
+  bit (bit 0) are **discarded**.
+- *Zero Fill:* This is a **logical shift right** (unsigned). Zeros are
+  shifted in from the left (MSB side). This differs from an arithmetic
+  shift right which would preserve the sign bit.
+- *Count Masking:* Only the low byte of =count= is used. On x86
+  processors, the actual shift amount is further masked to 5 bits
+  (=count & 0x1F=), meaning the effective shift is always 0-31.
+
+*Corner Cases:*
+- =count = 0=: Value unchanged.
+- =count >= 32=: Due to 5-bit masking, the effective shift is
+  =count mod 32=. For example, shift by 32 results in no change,
+  shift by 33 shifts by 1.
+- =value = 0=: Result is always 0 regardless of count.
+- Shifting by 31 always results in 0 (all bits shifted out).
+
+*Examples:*
+#+begin_example
+8  \ Value to shift
+2  \ Shift amount (count)
+shr
+#+end_example
+Result: 2 (0b1000 >> 2 = 0b0010).
+
+#+begin_example
+1      \ Value: only bit 0 set
+1      \ Shift by 1
+shr
+#+end_example
+Result: 0. The single bit was shifted out and discarded.
+
+* 38: or
+:PROPERTIES:
+:CUSTOM_ID: opcode-or
+:ID:       b38b971f-3a5f-4b16-9536-4193d2c5ae6b
+:END:
+- *Stack Effect:* =n1 n2 -- n1|n2=
+- *Description:* Performs a bitwise OR operation on the top two values.
+- *Notes:* The top value (n1) is ORed with the second value (n2).
+- *Example:*
+  #+begin_example
+  1 2
+  or
+  #+end_example
+  After execution, stack contains 3 (0b01 | 0b10).
+
+* 39: xor
+:PROPERTIES:
+:CUSTOM_ID: opcode-xor
+:ID:       e87a0d6d-89b0-4791-9500-654d60d99318
+:END:
+- *Stack Effect:* =n1 n2 -- n1^n2=
+- *Description:* Performs a bitwise XOR operation on the top two values.
+- *Notes:* The top value (n1) is XORed with the second value (n2).
+- *Example:*
+  #+begin_example
+  1 2
+  xor
+  #+end_example
+  After execution, stack contains 3 (0b01 ^ 0b10).
diff --git a/Documentation/opcodes_40_49.org b/Documentation/opcodes_40_49.org
new file mode 100644 (file)
index 0000000..1186994
--- /dev/null
@@ -0,0 +1,314 @@
+#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
+#+TITLE: Fifth - virtual machine opcodes 40 -- 49
+#+AUTHOR: Svjatoslav Agejenko
+#+LANGUAGE: en
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+  .flex-center {
+    display: flex;            /* activate flexbox */
+    justify-content: center;  /* horizontally center anything inside   */
+  }
+
+  .flex-center video {
+    width: min(90%, 1000px); /* whichever is smaller wins */
+    height: auto;            /* preserve aspect ratio */
+  }
+
+  .responsive-img {
+    width: min(100%, 1000px);
+    height: auto;
+  }
+</style>
+#+end_export
+
+
+* 40: vidmap
+:PROPERTIES:
+:CUSTOM_ID: opcode-vidmap
+:ID:       fe47ff6d-768f-4b05-9f8c-f52352c106f4
+:END:
+Stack Footprint
+: addr --
+
+Copies memory from the specified address to the video memory (VGA or
+VESA mode). Used for displaying images directly on the screen.
+
+Parameters:
+- *addr* (32-bit): Source memory address containing the image data to
+  copy to video memory.
+
+** Detailed Operation
+:PROPERTIES:
+:CUSTOM_ID: detailed-operation-4
+:END:
+1. *Video Memory Setup*:
+   - Set video memory segment to =0xA000= (VGA standard segment for
+     graphics mode).
+   - Initialize VESA-related variables (e.g., =gra= for page number).
+2. *VESA Page Mapping*:
+   - For each VESA page (up to 19 pages for 640x480x8 mode):
+     - Set VESA page using interrupt =0x10= with =AX = 0x4F05=.
+     - The page number is stored in =gra=.
+3. *Memory Copying*:
+   - For each page:
+     - Copy 4096 bytes (4KB) from source address to video memory.
+     - Use =STOSD= to write 32-bit words for efficiency.
+   - The source address is incremented by 4KB after each page.
+4. *Final Cleanup*:
+   - Restore original segments and clean up stack.
+
+** Example
+Copy a 640x480x8 image (307,200 bytes) from memory at =0x10000= to video
+memory:
+#+begin_example
+0x10000
+vidmap
+#+end_example
+
+** Notes
+
+- The operation assumes the video mode is set to VESA 640x480x8 (mode
+  =0x101=).
+- The exact number of pages copied depends on the video mode (19 pages
+  for 640x480x8).
+- Requires VESA BIOS support and proper initialization via
+  =set_vesa_mode=.
+
+* 41: mouse@
+:PROPERTIES:
+:CUSTOM_ID: opcode-mouse
+:ID:       b4bce653-d38f-45ed-82ec-13ca78c9860b
+:END:
+Stack Footprint:
+: -- x y buttons
+
+*Description:*
+
+Reads the current mouse position and button states from the mouse
+driver. Returns three values on the stack:
+- X-coordinate,
+- Y-coordinate,
+- button states.
+
+
+- *Returns*:
+  - *x* (32-bit): Current X-coordinate of the mouse cursor (0-based).
+  - *y* (32-bit): Current Y-coordinate of the mouse cursor (0-based).
+  - *buttons* (32-bit): Bitmask of button states:
+    - Bit 0: Left button (1 = pressed)
+    - Bit 1: Right button (1 = pressed)
+    - Bit 2: Middle button (1 = pressed)
+
+*Example:*
+
+#+begin_example
+mouse@
+#+end_example
+After execution, stack contains buttons (top), y, x (bottom).
+
+* 42: vidput - put image1 into image2, at location x, y
+:PROPERTIES:
+:CUSTOM_ID: opcode-vidput
+:ID:       238e8b03-57b6-424d-bfee-b6bb652cefbc
+:END:
+Stack Footprint:
+: addr1 addr2 x y --=
+
+Copies a portion of image1 to image2 at the specified (x, y)
+coordinates with clipping. Unlike =tvidput=, there is no transparency
+support - every pixel is copied regardless of value.
+
+*Parameters:*
+
+- *addr1* (32-bit): Address of the source image structure (width,
+  height, data address).
+- *addr2* (32-bit): Address of the destination image structure (width,
+  height, data address).
+- *x* (32-bit): X-coordinate in the destination image where the copy
+  starts.
+- *y* (32-bit): Y-coordinate in the destination image where the copy
+  starts.
+
+*Image Structure Format:*
+
+Identical to =tvidput=:
+- *Offset 0*: Image width (32-bit)
+- *Offset 4*: Image height (32-bit)
+- *Offset 8*: Base address of image data (32-bit pointer)
+
+*Example:*
+#+begin_example
+0x1000  ; Source image structure
+0x2000  ; Destination image structure
+50      ; x
+50      ; y
+vidput
+#+end_example
+
+* 43: cmove - copy memory array
+:PROPERTIES:
+:CUSTOM_ID: opcode-cmove
+:ID:       79e1916f-4103-42cc-ac10-bb1ee776ed50
+:END:
+
+- *Stack Effect:*
+: addr1 addr2 len --
+
+Copies =len= bytes from =addr1= to =addr2=. Handles overlapping memory
+regions correctly.
+
+- *Notes:* If =addr1 > addr2=, copies backwards to avoid data
+  corruption; otherwise copies forwards.
+- *Example:*
+  #+begin_example
+  100  ; Length
+  0x2000  ; Destination address
+  0x1000  ; Source address
+  cmove
+  #+end_example
+
+* 44: cfill
+:PROPERTIES:
+:CUSTOM_ID: opcode-cfill
+:ID:       fecb9438-d9d2-4224-a017-cc87dba9209e
+:END:
+- *Stack Effect:* =byte addr len --=
+- *Description:* Fills =len= bytes of memory starting at =addr= with the
+  specified byte value.
+- *Notes:* Simple byte-by-byte filling operation. Used for initializing
+  memory regions.
+- *Example:*
+  #+begin_example
+  0xFF  ; Fill byte
+  0x1000  ; Start address
+  100  ; Length
+  cfill
+  #+end_example
+
+* 45: tvidput - put image with transparency support
+:PROPERTIES:
+:CUSTOM_ID: opcode-tvidput
+:ID:       ab45247c-44c3-464d-9e2a-337f483b4616
+:END:
+Stack Footprint:
+: addr1 addr2 x y --
+
+Copies a portion of image1 to image2 at the specified (x, y)
+coordinates with transparency support. Pixels in image1 with value 255
+(0xFF) are treated as transparent and are not copied to the
+destination.
+
+*Parameters:*
+
+- *addr1* (32-bit): Address of the source image structure (contains
+  width, height, and data address).
+- *addr2* (32-bit): Address of the destination image structure (contains
+  width, height, and data address).
+- *x* (32-bit): X-coordinate in the destination image where the copy
+  starts.
+- *y* (32-bit): Y-coordinate in the destination image where the copy
+  starts.
+
+*Image Structure Format:*
+
+Each image structure is stored in memory as follows:
+- *Offset 0*: Image width (32-bit integer)
+- *Offset 4*: Image height (32-bit integer)
+- *Offset 8*: Base address of image data (32-bit pointer)
+
+*Example:*
+#+begin_example
+0x1000  ; Source image structure
+0x2000  ; Destination image structure
+50      ; x
+50      ; y
+tvidput
+#+end_example
+
+*Notes:*
+
+- Transparency is fixed at value 255 (0xFF).
+- The operation handles clipping automatically to ensure the copy stays
+  within destination bounds.
+- Source and destination image structures must be properly formatted.
+
+* 46: depth
+:PROPERTIES:
+:CUSTOM_ID: opcode-depth
+:ID:       77fa76d3-9cd0-49c1-882c-f30383347352
+:END:
+- *Stack Effect:* =-- depth=
+- *Description:* Pushes the current depth (number of items) on the data
+  stack onto the stack.
+- *Notes:* Calculated by comparing the data stack pointer to the base
+  address of the stack.
+- *Example:*
+  #+begin_example
+  1 2 3
+  depth
+  #+end_example
+  After execution, stack contains 3 (depth) followed by 1 2 3.
+
+* 47: charput - draw text character
+:PROPERTIES:
+:CUSTOM_ID: opcode-charput
+:ID:       4bb479cf-aae0-4128-9868-f016c286a162
+:END:
+
+Stack Footprint:
+=colorfg colorbg addrsrc addrdest x y --=
+
+
+Draws an 8x8 character from a source memory buffer to a destination
+image buffer at the specified (x, y) coordinates. Each byte in the
+source buffer represents one row of the character (8 bits per row),
+where each bit determines whether to use the foreground or background
+color for that pixel.
+
+*Parameters:*
+
+- *colorfg* (1 byte): Foreground color value (0-255). Typically a
+  grayscale value where 0 is black and 255 is white.
+- *colorbg* (1 byte): Background color value (0-255).
+- *addrsrc* (32-bit): Memory address pointing to 8 bytes of character
+  data. Each byte represents one row of the character (8 bits per row).
+- *addrdest* (32-bit): Base address of the destination image buffer in
+  memory.
+- *x* (32-bit): X-coordinate (0-based) where the character's left edge
+  starts.
+- *y* (32-bit): Y-coordinate (0-based) where the character's top edge
+  starts.
+
+*Example:*
+
+TODO: Create dedicated page that explains this instruction in
+depth. Link to this new page from current one.
+
+#+begin_example
+0xFF  ; White foreground
+0x00  ; Black background
+0x3000  ; Character data address
+0x5000  ; Video memory address
+20      ; y
+10      ; x
+charput
+#+end_example
+
+Character data for 'A' (ASCII 65):
+#+begin_example
+0x00, 0x18, 0x24, 0x24, 0x24, 0x3C, 0x24, 0x24
+#+end_example
+
+- Each byte represents a row:
+  - Row 0: =0x00= → all pixels black
+  - Row 1: =0x18= → bits 3-4 set (binary =00011000=)
+  - Row 2: =0x24= → bits 2 and 5 set (binary =00100100=)
+  - Row 3: =0x24= → same as row 2
+  - Row 4: =0x24= → same as row 2
+  - Row 5: =0x3C= → bits 2-5 set (binary =00111100=)
+  - Row 6: =0x24= → same as row 2
+  - Row 7: =0x24= → same as row 2
diff --git a/Documentation/screenshots/dictionary.png b/Documentation/screenshots/dictionary.png
new file mode 100644 (file)
index 0000000..73909b0
Binary files /dev/null and b/Documentation/screenshots/dictionary.png differ
diff --git a/Documentation/screenshots/start.png b/Documentation/screenshots/start.png
new file mode 100644 (file)
index 0000000..15b5c40
Binary files /dev/null and b/Documentation/screenshots/start.png differ
diff --git a/Documentation/screenshots/text editor.png b/Documentation/screenshots/text editor.png
new file mode 100644 (file)
index 0000000..153bf90
Binary files /dev/null and b/Documentation/screenshots/text editor.png differ
diff --git a/Documentation/virtual machine.org b/Documentation/virtual machine.org
new file mode 100644 (file)
index 0000000..4078fc4
--- /dev/null
@@ -0,0 +1,165 @@
+:PROPERTIES:
+:ID:       9b251eb9-aff6-4025-94bf-25e89e26d54a
+:END:
+#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
+#+TITLE: Fifth - virtual machine
+#+AUTHOR: Svjatoslav Agejenko
+#+LANGUAGE: en
+
+#+OPTIONS: H:20 num:20
+#+OPTIONS: author:nil
+
+#+begin_export html
+<style>
+  .flex-center {
+    display: flex;            /* activate flexbox */
+    justify-content: center;  /* horizontally center anything inside   */
+  }
+
+  .flex-center video {
+    width: min(90%, 1000px); /* whichever is smaller wins */
+    height: auto;            /* preserve aspect ratio */
+  }
+
+  .responsive-img {
+    width: min(100%, 1000px);
+    height: auto;
+  }
+</style>
+#+end_export
+
+
+* Overview
+
+Fifth is a hobby operating system built around a custom stack-based
+virtual CPU. The virtual CPU emulator runs as a COM executable
+(emulator.com) under MS-DOS.
+
+The virtual machine is designed to be simple yet powerful, featuring
+two stacks (data stack and return stack), approximately 50
+instructions (opcodes), and a theoretical 4GB flat address space. It
+serves as the foundation for the Fifth language — a Forth-inspired,
+interactive programming environment where users can define, extend,
+and modify system behavior at runtime.
+
+* x86 Unreal Mode Execution
+
+The emulator runs as a standard DOS COM executable and uses x86
+real-mode assembly with a technique called "unreal mode" to access
+extended memory beyond the 640KB conventional DOS limit. In unreal
+mode, the CPU operates in real-mode (compatible with DOS) but with
+segment registers configured to allow access to the full 32-bit
+address space (up to 4GB).
+
+Key aspects:
+- Starts in real mode for DOS compatibility.
+- Switches temporarily to x86 protected mode to initialize segment
+  registers for 4 GB RAM flat address space.
+- Returns to real mode while retaining 4 GB RAM access.
+- Uses XMS (Extended Memory Specification) for large memory allocation.
+
+** Memory Management and XMS
+
+The emulator uses DOS XMS (Extended Memory Specification) to allocate
+large blocks of extended memory:
+
+- **XMS Allocation**: Allocates the largest available block of extended
+  memory using HIMEM.SYS
+- **Memory Locking**: Locks the allocated block to prevent swapping
+- **Address Mapping**: Uses xms_addr variable to store the linear
+  address of allocated memory
+- **Virtual-to-Physical**: All virtual CPU addresses are offset by
+  xms_addr to convert to physical memory addresses
+
+* Two-Stack Architecture
+
+The virtual CPU uses two separate stacks:
+
+- **Data Stack**: Main working stack for operations.
+- **Return Stack (variable resp)**: Stores return addresses for
+  subroutine calls.
+
+* Graphics System
+
+The virtual machine integrates directly with VESA BIOS for graphics
+output. It uses VESA 640x480 8-bit color mode.
+
+Graphics operations are performed through dedicated VM instructions.
+
+* Boot Process
+
+1. DOS loads emulator.com as a COM executable
+2. system_init() allocates XMS memory and sets up A20 gate
+3. Sets VESA graphics mode (640x480, 8-bit color)
+4. Loads first kilobyte of kernel (core.raw) from disk into beginning
+   of virtual RAM.
+5. Jumps to kernel entry point
+6. Kernel loads remaining 3 kibibytes of kernel bytecode into RAM. So
+   initial bytecode part of the kernel must not exceed 4 kibibytes.
+7. Kernel loads high-level Fifth boot code into RAM.
+8. Kernel starts compiling additional modules to itself from
+   high-level bytecode to gain filesystem support, dynamic RAM support
+   and other essential functions.
+9. Additional modules (keyboard / mouse drivers) and interactive shell
+   are now loaded from filesystem files.
+10. Enters interactive REPL
+
+* Implemented instructions
+
+Virtual CPU opcodes (most of them are available as directly executable commands
+in FIFTH programming language):
+
+
+|  # | Name     | Stack effect          | Description                                              | Notes                                                               |
+|----+----------+-----------------------+----------------------------------------------------------+---------------------------------------------------------------------|
+|  0 | [[file:opcodes_00_09.org::#opcode-nop][nop]]      | --                    | No operation; execution continues to next instruction    | Used for padding or placeholder                                      |
+|  1 | [[file:opcodes_00_09.org::#opcode-halt][halt]]     | --                    | Stop execution and exit emulator                         | Cleanly terminates the Fifth environment                             |
+|  2 | [[file:opcodes_00_09.org::#opcode-kbd-read][kbd@]]     | -- scancode           | Read keyboard scancode; returns 0 if no key pending      | Make codes for press, break codes (value+128) for release            |
+|  3 | [[file:opcodes_00_09.org::#opcode-num][num]]      | -- n                  | Push 32-bit literal from instruction stream              | Followed by 4 bytes (little-endian)                                  |
+|  4 | [[file:opcodes_00_09.org::#opcode-jmp][jmp]]      | --                    | Unconditional jump to address from instruction stream    | Followed by 4-byte target address                                    |
+|  5 | [[file:opcodes_00_09.org::#opcode-call][call]]     | --                    | Call subroutine; push return address on return stack     | Use ret (opcode 11) to return; follow with 4-byte target address     |
+|  6 | [[file:opcodes_00_09.org::#opcode-1plus][1+]]       | n -- n+1              | Increment top of data stack by 1                         | Efficient single-byte operation for counters and pointers            |
+|  7 | [[file:opcodes_00_09.org::#opcode-1minus][1-]]       | n -- n-1              | Decrement top of data stack by 1                         | Efficient single-byte operation for countdown loops                  |
+|  8 | [[file:opcodes_00_09.org::#opcode-dup][dup]]      | n -- n n              | Duplicate top of data stack                              | Preserve values before consuming operations                          |
+|  9 | [[file:opcodes_00_09.org::#opcode-drop][drop]]     | n --                  | Remove and discard top of data stack                     | Clean up stack after operations                                      |
+| 10 | [[file:opcodes_10_19.org::#opcode-if][if]]       | n --                  | Jump to address if top of stack is zero                  |                                                                     |
+| 11 | [[file:opcodes_10_19.org::#opcode-ret][ret]]      |                       | Return from subroutine (pop return address)              |                                                                     |
+| 12 | [[file:opcodes_10_19.org::#opcode-cfetch][c@]]       | addr -- byte          | Read byte from memory at specified address               |                                                                     |
+| 13 | [[file:opcodes_10_19.org::#opcode-cstore][c!]]       | byte addr --          | Store byte to specified memory address                   |                                                                     |
+| 14 | [[file:opcodes_10_19.org::#opcode-push][push]]     | n --                  | Move top of data stack to return stack                   |                                                                     |
+| 15 | [[file:opcodes_10_19.org::#opcode-pop][pop]]      | -- n                  | Move top of return stack to data stack                   |                                                                     |
+| 16 | <unused> |                       |                                                          |                                                                     |
+| 17 | [[file:opcodes_10_19.org::#opcode-rot][rot]]      | n1 n2 n3 -- n2 n3 n1  | Rotate top three stack elements                          |                                                                     |
+| 18 | [[file:opcodes_10_19.org::#opcode-disk-read][disk@]]    | sector addr --        | Read 1KB from disk into RAM at specified address         |                                                                     |
+| 19 | [[file:opcodes_10_19.org::#opcode-disk-write][disk!]]    | addr sector --        | Write 1KB from RAM to disk at specified sector           |                                                                     |
+| 20 | [[file:opcodes_20_29.org::#opcode-fetch][@]]        | addr -- n             | Read 32-bit value from memory                            |                                                                     |
+| 21 | [[file:opcodes_20_29.org::#opcode-store][!]]        | n addr --             | Store 32-bit value to memory                             |                                                                     |
+| 22 | [[file:opcodes_20_29.org::#opcode-over][over]]     | n1 n2 -- n1 n2 n1     | Duplicate second item on data stack                      |                                                                     |
+| 23 | [[file:opcodes_20_29.org::#opcode-swap][swap]]     | n1 n2 -- n2 n1        | Swap top two items on data stack                         |                                                                     |
+| 24 | [[file:opcodes_20_29.org::#opcode-add][+]]        | n1 n2 -- n1+n2        | Add top two items on data stack                          |                                                                     |
+| 25 | [[file:opcodes_20_29.org::#opcode-sub][-]]        | n1 n2 -- n1-n2        | Subtract second item from top item on data stack         | TODO: verify argument order                                         |
+| 26 | [[file:opcodes_20_29.org::#opcode-mul][*]]        | n1 n2 -- n1*n2        | Multiply top two items on data stack                     |                                                                     |
+| 27 | [[file:opcodes_20_29.org::#opcode-div][/]]        | n1 n2 -- n2/n1        | Divide top item by second item on data stack             | TODO: verify argument order                                         |
+| 28 | [[file:opcodes_20_29.org::#opcode-gt][>]]        | n1 n2 -- result       | Compare n1 > n2 (returns true, false otherwise)          | TODO: document, what true and false means                           |
+| 29 | [[file:opcodes_20_29.org::#opcode-lt][<]]        | n1 n2 -- result       | Compare n1 < n2 (returns true, false otherwise)          | TODO: document, what true and false means                           |
+| 30 | [[file:opcodes_30_39.org::#opcode-not][not]]      | n -- ~n               | Bitwise NOT on top of data stack                         |                                                                     |
+| 31 | [[file:opcodes_30_39.org::#opcode-i][i]]        | -- n                  | Push top of return stack to data stack                   |                                                                     |
+| 32 | [[file:opcodes_30_39.org::#opcode-cprt-read][cprt@]]    | port -- byte          | Read byte from hardware I/O port                         |                                                                     |
+| 33 | [[file:opcodes_30_39.org::#opcode-cprt-write][cprt!]]    | byte port --          | Write byte to hardware I/O port                          |                                                                     |
+| 34 | [[file:opcodes_30_39.org::#opcode-i2][i2]]       | -- n                  | Push second item from return stack to data stack         |                                                                     |
+| 35 | [[file:opcodes_30_39.org::#opcode-i3][i3]]       | -- n                  | Push third item from return stack to data stack          |                                                                     |
+| 36 | [[file:opcodes_30_39.org::#opcode-shl][shl]]      | value count -- result | Left shift value by count bits; shifted-out bits discarded |
+| 37 | [[file:opcodes_30_39.org::#opcode-shr][shr]]      | value count -- result | Logical right shift; zeros shifted in, shifted-out bits discarded |
+| 38 | [[file:opcodes_30_39.org::#opcode-or][or]]       | n1 n2 -- result       | Bitwise OR of top two items on data stack                |                                                                     |
+| 39 | [[file:opcodes_30_39.org::#opcode-xor][xor]]      | n1 n2 -- result       | Bitwise XOR of top two items on data stack               |                                                                     |
+| 40 | [[file:opcodes_40_49.org::#opcode-vidmap][vidmap]]   | addr --               | Copy memory to video memory                              |                                                                     |
+| 41 | [[file:opcodes_40_49.org::#opcode-mouse][mouse@]]   | -- x y buttons        | Read mouse coordinates and button states                 |                                                                     |
+| 42 | [[file:opcodes_40_49.org::#opcode-vidput][vidput]]   | addr1 addr2 x y --    | Blit image1 to image2 at (x,y) without transparency      |                                                                     |
+| 43 | [[file:opcodes_40_49.org::#opcode-cmove][cmove]]    | addr1 addr2 len --    | Copy memory block from addr1 to addr2                    |                                                                     |
+| 44 | [[file:opcodes_40_49.org::#opcode-cfill][cfill]]    | byte addr len --      | Fill memory with specified byte value                    |                                                                     |
+| 45 | [[file:opcodes_40_49.org::#opcode-tvidput][tvidput]]  | addr1 addr2 x y --    | Blit image1 to image2 at (x,y) with transparency support |                                                                     |
+| 46 | [[file:opcodes_40_49.org::#opcode-depth][depth]]    | -- depth              | Push current data stack depth                            |                                                                     |
+| 47 | [[file:opcodes_40_49.org::#opcode-charput][charput]]  | fg bg src dest x y -- | Draw character from source buffer to destination buffer  |
+
+
+
index d7d5fd7..10b9574 100755 (executable)
@@ -2,66 +2,17 @@
 cd "${0%/*}"; if [ "$1" != "T" ]; then gnome-terminal -- "$0" T; exit; fi;
 cd ..
 
-# Function to export org to html using emacs in batch mode
-export_org_to_html() {
-    local org_file=$1
-    local dir=$(dirname "$org_file")
-    local base=$(basename "$org_file" .org)
-    (
-        cd "$dir" || return 1
-        local html_file="${base}.html"
-        if [ -f "$html_file" ]; then
-            rm -f "$html_file"
-        fi
-        echo "Exporting: $org_file → $dir/$html_file"
-        emacs --batch -l ~/.emacs --visit="${base}.org" --funcall=org-html-export-to-html --kill
-        if [ $? -eq 0 ]; then
-            echo "✓ Successfully exported $org_file"
-        else
-            echo "✗ Failed to export $org_file"
-            return 1
-        fi
-    )
-}
+# Export changed Documentation/*.org pages to html via the shared incremental
+# exporter (requires svjatoslav_commons checked out next to this repo).
+"../svjatoslav_commons/Tools/Org export incremental" \
+    --root Documentation --pattern '*.org' \
+    --state .org-export-state
 
-echo "🔍 Searching for .org files in doc/ ..."
-echo "======================================="
+# Upload assembled documentation to server
+SERVER_DIR="n0@www3.svjatoslav.eu:/mnt/big/projects/fifth/"
 
-mapfile -t ORG_FILES < <(find doc -type f -name "*.org" | sort)
-
-if [ ${#ORG_FILES[@]} -eq 0 ]; then
-    echo "❌ No .org files found!"
-    echo ""
-    echo "Press ENTER to close this window."
-    read
-    exit 1
-fi
-
-echo "Found ${#ORG_FILES[@]} .org file(s):"
-printf '%s\n' "${ORG_FILES[@]}"
-echo "======================================="
-
-SUCCESS_COUNT=0
-FAILED_COUNT=0
-
-for org_file in "${ORG_FILES[@]}"; do
-    export_org_to_html "$org_file"
-    if [ $? -eq 0 ]; then
-        ((SUCCESS_COUNT++))
-    else
-        ((FAILED_COUNT++))
-    fi
-done
-
-echo "======================================="
-echo "📊 SUMMARY:"
-echo "   ✓ Successful: $SUCCESS_COUNT"
-echo "   ✗ Failed:     $FAILED_COUNT"
-echo "   Total:        $((SUCCESS_COUNT + FAILED_COUNT))"
-echo ""
-
-echo "📤 Uploading to server..."
-rsync -avz --delete -e 'ssh -p 10006' doc/ n0@www3.svjatoslav.eu:/mnt/big/projects/fifth/
+echo "📤 Uploading to $SERVER_DIR ..."
+rsync -avz --delete -e 'ssh -p 10006' Documentation/ "$SERVER_DIR"
 
 if [ $? -eq 0 ]; then
     echo "✓ Upload completed successfully!"
diff --git a/doc/5TH_ET.txt b/doc/5TH_ET.txt
deleted file mode 100644 (file)
index 7fde517..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-.( loading editor ) update\r
-.( done        )\r
-.( ETh - for text editor help )\r
-\r
-var handletxt\r
-var handlebuf\r
-Dstralloc const        editfile\r
-var shiftx  var        shifty\r
-var curlocx var        curlocy\r
-Dstr \listF\TXT_ET" tmphelpfile\r
-\r
-: disppage ( --        )\r
-handletxt @\r
-dynp shifty @ 50 * +\r
-0 1 at!\r
-1270 type ;\r
-\r
-: fclose (  close opened file )\r
-handletxt @ dup        if dynde handletxt off else drop then ;\r
-\r
-: ETnewpage fclose 27100 dynal dup handletxt ! dynp\r
-FF swap        27100 cfill ;\r
-\r
-var tmp1\r
-: fopen        ( strhand -- )\r
-fclose\r
-dup editfile Dstr2Dstr fsDloadnew dup push dynp        ( addrinp       R: handinp )\r
-27100 dynal dup        handletxt ! dynp        ( addrinp addrout       R: handinp )\r
-FF over        27100 cfill\r
-tmp1 off\r
-i dyns do              ( addrinp addrout )\r
-over c@                        ( addrinp addrout c )\r
-dup FE = if\r
-       drop\r
-       50 tmp1 @ - + tmp1 off\r
-else\r
-       dup FD = if\r
-               drop tmp1 @ tab ( addrinp addrout numspaces )\r
-               tmp1 @ over + tmp1 ! + 0\r
-       else\r
-               over c! 1+ 0\r
-               tmp1 @ 1+ tmp1 !\r
-       then\r
-       drop\r
-then\r
-swap 1+        swap\r
-loop 2drop\r
-pop dynde ; rh tmp1\r
-\r
-: dispchar ( x y -- )\r
-2dup\r
-swap shiftx @ -\r
-swap shifty @ -        1+\r
-at!\r
-50 * + handletxt @ dynp        + c@ emit ;\r
-\r
-: dispcur curlocx @ curlocy @ dispchar ;\r
-\r
-: displine ( line )\r
-0 over shifty @        - 1+ at!\r
-50 * handletxt @ dynp +        shiftx @ + 50 type ;\r
-\r
-: dispstatbar\r
-colneg\r
-0 0 at!        50 do space loop\r
-0 0 at!        ." col:" curlocx @ .\r
-7 0 at!        ." line:" curlocy @ .\r
-11 0 at! ." ascii:" curlocy @ 50 * curlocx @ + handletxt @ dynp        + c@ .\r
-1B 0 at! ." file:" editfile Dstr.\r
-49 0 at! ." F1-help"\r
-colnorm        ;\r
-\r
-: charins ( char x y )\r
-50 * handletxt @ dynp +                ( char x addr )\r
-over push\r
-+ dup dup 1+ 4F        pop - cmove     ( char addr )\r
-c! ;\r
-\r
-: charcut ( x y        -- char )\r
-over push\r
-50 * handletxt @ dynp +        +\r
-dup c@ swap                    ( char addr )\r
-dup dup        1+ swap                 ( char addr addr+1 addr )\r
-4F pop - dup push cmove                ( char addr )\r
-pop + FF swap c! ;\r
-\r
-: lineins ( line )\r
-50 * dup push handletxt        @ dynp +                ( addr )\r
-dup dup        50 + handletxt @ dyns 50 - pop - cmove  ( addr )\r
-FF swap        50 cfill ;\r
-\r
-: linecut ( line )\r
-50 * dup push handletxt        @ dynp +                ( addr )\r
-dup 50 + swap handletxt        @ dyns 50 - pop - cmove ;\r
-\r
-: screenaim\r
-0 curlocy @ 1E - 794 bound shifty !\r
-disppage ;\r
-\r
-var tmp1\r
-: length       ( line -- length )\r
-50 * 4F        + handletxt @ dynp +    ( addr )\r
-51 do\r
-       i tmp1 !\r
-       dup c@ FF - if pop drop 0 push then\r
-       1-\r
-loop\r
-drop\r
-tmp1 @ ; rh tmp1\r
-\r
-var tmp2 var tmp3\r
-: fsavechar ( char ) tmp2 @ swap over c! 1+ tmp2 ! ;\r
-: fsave        ( -- )\r
-27200 dynal dup        dynp tmp2 !\r
-0\r
-7CF do\r
-       i length if drop pop 1+ 0 push then\r
-loop\r
-0 swap for             ( desthand )\r
-       tmp3 off\r
-       i 50 * handletxt @ dynp +\r
-       0 i length for  ( desthand srcaddr )\r
-               dup c@\r
-               i tab 8 = if tmp3 @ if FD fsavechar tmp3 off then then\r
-               dup FF = if\r
-                       drop tmp3 @ 1+ tmp3 !\r
-               else\r
-                       tmp3 @ do FF fsavechar loop tmp3 off\r
-                       fsavechar\r
-               then\r
-               1+\r
-       loop drop\r
-       FE fsavechar\r
-loop\r
-tmp2 @ over dynp - over        dynresize\r
-dup editfile fsDsave\r
-dynde ;        rh tmp2 rh tmp3\r
-\r
-str TXT_default" tmpdefault\r
-\r
-: ET\r
-handletxt @ if\r
-disppage\r
-until\r
-       colneg dispcur dispstatbar KBD_FW@ colnorm dispcur\r
-\r
-       dup 415 = if                                            ( DEL )\r
-               curlocx @ curlocy @ charcut drop\r
-               curlocy @ displine\r
-       then\r
-\r
-       dup FC = if                                             ( BACKSPACE )\r
-       curlocx @ if\r
-               curlocx @ 1- curlocy @ charcut drop\r
-               curlocy @ displine\r
-               drop 413\r
-       else\r
-               curlocy @ if\r
-                       curlocy @ 1- dup length dup curlocx !   ( y-1 strlen )\r
-                       swap 50 * handletxt @ dynp +    ( strlen y1addr )\r
-                       2dup + swap 50 +                ( strlen dest src )\r
-                       swap rot 50 swap - cmove\r
-                       curlocy @ linecut\r
-                       drop 410\r
-                       disppage\r
-               then\r
-       then\r
-       then\r
-\r
-       dup FD = if                                             ( TAB )\r
-               curlocx @ tab\r
-               dup do FF curlocx @ curlocy @ charins loop\r
-               curlocx @ + curlocx !\r
-               curlocy @ displine\r
-       then\r
-\r
-       dup FE = if                                             ( ENTER )\r
-               curlocy @ 7CF < if\r
-                       curlocy @ 1+ lineins\r
-                       curlocx @ 0\r
-                       50 curlocx @ - do\r
-                               over curlocy @ charcut\r
-                               over curlocy @ 1+ charins\r
-                               1+\r
-                       loop 2drop\r
-                       curlocx off\r
-                       drop 412\r
-                       disppage\r
-               then\r
-       then\r
-\r
-       dup 418 = if curlocy @ 3A - curlocy ! then              ( PG-UP )\r
-       dup 419 = if curlocy @ 3A + curlocy ! then              ( PG-DOWN )\r
-       dup 416 = if curlocx off then                           ( HOME )\r
-       dup 417 = if curlocy @ length curlocx ! then            ( END )\r
-       dup 401 = if tmphelpfile fsdisp disppage then           ( F1 )\r
-       dup 402 = if fsave then                                 ( F2 )\r
-       dup 403 = if fclose drop 1B then                        ( F3 )\r
-       dup 400 = if done 0 0 at! screen cls drop -1 then       ( ESC )\r
-\r
-       0 over F0 bound? if -1 else 0 then                      ( NORMAL KEY )\r
-       over FF = if drop -1 then\r
-       if\r
-               curlocx @ curlocy @ charins\r
-               curlocy @ displine\r
-               411\r
-       then\r
-\r
-       dup 411 = if curlocx @ 1+ curlocx ! then               ( RIGHT )\r
-       dup 413 = if curlocx @ 1- curlocx ! then               ( LEFT )\r
-       dup 412 = if curlocy @ 1+ curlocy ! then               ( DOWN )\r
-       dup 410 = if curlocy @ 1- curlocy ! then               ( UP )\r
-       drop\r
-\r
-       0 curlocx @ 4F bound curlocx !\r
-       0 curlocy @ 7CF bound curlocy !\r
-\r
-       curlocy @ shifty @ - 3B > if screenaim then\r
-\r
-       curlocy @ shifty @ - 3B - 0 = if\r
-               0 0 8 screen scrollf\r
-               shifty @ 1+ shifty !\r
-               curlocy @ displine\r
-       then\r
-\r
-       curlocy @ shifty @ - -1 < if screenaim then\r
-\r
-       curlocy @ shifty @ - 1+ 0 = if\r
-               0 0 -8 screen scrollf\r
-               shifty @ 1- shifty !\r
-               curlocy @ displine\r
-       then\r
-\r
-loop\r
-else\r
-       tmpdefault editfile str2Dstr\r
-       ETnewpage\r
-       ET\r
-then ;\r
-\r
-: ETl\r
-fopen\r
-curlocx        off\r
-curlocy        off\r
-shiftx off\r
-shifty off\r
-ET ;\r
-\r
-: ETs\r
-editfile Dstr2Dstr\r
-fsave ." saved " ;\r
-\r
-: ETh tmphelpfile fs. ;\r
-\r
-rh handletxt\r
-rh handlebuf\r
-rh editfile\r
-rh shiftx rh shifty\r
-rh curlocx rh curlocy\r
-rh tmphelpfile\r
-rh disppage\r
-rh fclose rh fopen\r
-rh dispchar rh dispcur\r
-rh displine rh dispstatbar\r
-rh charins rh charcut\r
-rh lineins rh linecut\r
-rh screenaim rh        length\r
-rh fsavechar rh        fsave\r
-rh ETnewpage rh        tmpdefault\r
diff --git a/doc/index.org b/doc/index.org
deleted file mode 100644 (file)
index fedd6a9..0000000
+++ /dev/null
@@ -1,359 +0,0 @@
-#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
-#+TITLE: Fifth - virtual machine, operating system, programming language
-#+LANGUAGE: en
-
-#+OPTIONS: H:20 num:20
-#+OPTIONS: author:nil
-
-#+begin_export html
-<style>
-  .flex-center {
-    display: flex;            /* activate flexbox */
-    justify-content: center;  /* horizontally center anything inside   */
-  }
-
-  .flex-center video {
-    width: min(90%, 1000px); /* whichever is smaller wins */
-    height: auto;            /* preserve aspect ratio */
-  }
-
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-</style>
-#+end_export
-
-
-* General
-- This program is free software: released under Creative Commons Zero
-  (CC0) license
-
-- Program author:
-  - Svjatoslav Agejenko
-  - Homepage: https://svjatoslav.eu
-  - Email: mailto://svjatoslav@svjatoslav.eu
-
-- [[https://www.svjatoslav.eu/projects/][Other software projects hosted at svjatoslav.eu]]
-
-** Source code
-- [[https://www2.svjatoslav.eu/gitweb/?p=fifth.git;a=snapshot;h=HEAD;sf=tgz][Download latest snapshot in TAR GZ format]]
-
-- [[https://www2.svjatoslav.eu/gitweb/?p=fifth.git;a=summary][Browse Git repository online]]
-
-- Clone Git repository using command:
-  : git clone https://www3.svjatoslav.eu/git/fifth.git
-
-* Introduction
-
-Fifth is self-hosting hobby computing environment that integrates a
-[[id:9b251eb9-aff6-4025-94bf-25e89e26d54a][custom virtual machine]], a [[id:da7fff9b-0b67-4843-828a-52a404d7f401][Forth-inspired programming language]], and
-operating system.
-
-At its core lies a stack-based virtual CPU with two stacks (data and
-return), approximately 50 instructions, and a 4GB flat address
-space. This virtual machine executes the Fifth language — a concise,
-interactive, and extensible environment where every operation is a
-command that can be defined, redefined, or extended by the user. The
-language uses a custom character encoding (FSCII) with unique
-representations for control characters (e.g., space as FF instead of
-20 in ASCII) and features an innovative hexadecimal number system
-visualized as squares split into four triangles, each representing a
-single bit—similar to Bibi-binary.
-
-It includes a disk-based filesystem, a built-in text editor, 2D
-graphics capabilities, mouse and keyboard drivers, and tools for file
-management and memory allocation.
-
-Released under the CC0 public domain license, Fifth is free for anyone
-to use, study, and modify. Whether you're a retro computing
-enthusiast, a systems programming student, or a curious developer.
-
-** Screenshots
-
-#+attr_html: :class responsive-img
-#+attr_latex: :width 1000px
-[[file:screenshots/start.png]]
-
-Startup screen diplaying Fifth logo and full file list.
-
-#+attr_html: :class responsive-img
-#+attr_latex: :width 1000px
-[[file:screenshots/dictionary.png]]
-
-Sample words defined. Most of the words are commands that can be
-executed interactively from the command line or from a file. When
-executed, they can be selectively compiled or interpreted.
-
-#+attr_html: :class responsive-img
-#+attr_latex: :width 1000px
-[[file:screenshots/text editor.png]]
-
-Built in text editor.
-
-* Installation
-Just unpack all files, witout altering original directory structure,
-somewhere in your hard disk. For example:
-
-: C:\MISC\FIFTH\
-
-To run fifth you need minimally just 2 files:
-- EMULATOR.COM :: Virtual CPU emulator
-- DISK.RAW :: Virtual disk file
-
-For more information, please refer to [[id:0759f3e0-28bb-4901-9e4f-09ef41732173][Fifth distribution directory
-tree description]].
-
-* Fifth distribution directory tree description
-:PROPERTIES:
-:CUSTOM_ID: ID-0759f3e0-28bb-4901-9e4f-09ef41732173
-:ID:       0759f3e0-28bb-4901-9e4f-09ef41732173
-:END:
-After downloading and unpacking the ZIP file you shoud get directory
-tree similar to this:
-
-#+BEGIN_VERSE
-*DOC*                   - Fifth documentation
-  *commands*            - documentation on Fifth built-in commands
-  *modules*             - documentation on additional commands, realized as loadable modules
-  *shots*               - Fifth screenshots
-
-*imageFile*             - files contained within 'disk.raw', just an extracted form.
-
-*source*                - source files
-  *emulator*            - emulator source
-  *util*                - utilites
-
-*disk.raw*                - Virtual disk file, has filesystem inside.
-*emulator.com*            - main executable.
-#+END_VERSE
-
-* Requirements
-** Software
-- MS-DOS 6.22 with HIMEM.SYS loaded.
-- Mouse driver (optional, if you have a mouse).
-- CPU is initialized into [[https://en.wikipedia.org/wiki/Unreal_mode][Unreal Mode]] during operation.
-- To recompile ASM sources, you can use FASM (Flat Assembler).
-- To run Quick Basic utilities, use Microsoft Quick Basic 4.5.
-- VESA support through BIOS or external driver (UNIVBE).
-
-** Hardware
-- A minimum of a i386 CPU.
-- 64 KB of free RAM below 640KB.
-- 2 MB of free [[https://en.wikipedia.org/wiki/Extended_memory][extended memory]].
-- A VESA-compatible video card.
-
-* Numbers representation within Fifth
-
-Because we are in full experimentation mode here (no regard for
-compatibility whatsoever), why not to try also alternative number
-representation ?
-
-Here alternative hexadecimal number representation format is devised:
-
-#+attr_html: :class responsive-img
-#+attr_latex: :width 1000px
-[[file:numbers.png][file:numbers.png]]
-
-Essentially square is split into 4 triangles. Each triangle represents
-one bit.
-
-Fifth uses this hexadecimal format as primary throughout entire
-system.
-
-See also: [[https://en.wikipedia.org/wiki/Bibi-binary][Bibi-binary]].
-
-* Disk file map and its data structures
-
-The `disk.raw` file is a raw disk image that contains both the boot
-code (loaded before filesystem initialization) and the filesystem
-structure. The disk layout is as follows:
-
-** Disk Allocation Table
-| Offset  | Length  | Description                                                          |
-|---------+---------+----------------------------------------------------------------------|
-| 0       | ~4 KiB  | Operating system kernel in virtual CPU byte-code                     |
-| 4 KiB   | ~32 KiB | Human readable, early system initialization code                     |
-| 37 KiB  | ~65 KiB | FAT (File Allocation Table)                                          |
-| 101 KiB | ~16 MiB | Filesystem data area (stores file contents and directory structures) |
-
-** FAT Entry Format
-
-The FAT tracks which disk sectors belong to each file.
-
-|     Code | Meaning                                      |
-|----------+----------------------------------------------|
-|       -2 | Last sector of a file chain                  |
-|       -1 | Unused (empty) sector                        |
-| 0 -- ... | Pointer to the next sector in the file chain |
-
-** File Directory Entry Format
-| Offset | Length | Description                                         |
-|--------+--------+-----------------------------------------------------|
-|      0 |      4 | File extension (4-byte FSCII string, e.g., "TXT ")  |
-|      4 |     16 | Filename (16-byte FSCII string, padded with spaces) |
-|     20 |      4 | First block address                                 |
-|     24 |      4 | File size in bytes                                  |
-|     28 |      4 | Last modification timestamp (seconds since epoch)   |
-
-The directory entries are stored within the filesystem data
-area. Directory is just a file that list other files.
-
-* Core architecture
-
-Fifth core is simply some amount of already compiled into machine code
-and linked together modules (entries in other words). In compilation
-process modules is compiled one by one and simply stored on top of
-already existing and growing core. Separately from core is kept
-dictionary, this is special list that contain names of compiled
-modules, variables etc. and they locations in core. Constants use
-dictionary space only. Random word can be removed from dictionary at
-any time. Currently dictionary can contain at most 1000 entries.
-
-** Dictionary entry format
-| offset | length | description           |
-|--------+--------+-----------------------|
-|      0 |      4 | 0 &lt; previous entry |
-|        |        | 0 = last              |
-|        |        | -1 = empty            |
-|--------+--------+-----------------------|
-|      4 |     15 | module name string    |
-|--------+--------+-----------------------|
-|     19 |      1 | entry type            |
-|--------+--------+-----------------------|
-|     20 |      4 | entry data            |
-
-Core headers as linked list of module names make up something like
-dictionary.  When some entry address is needed compiler can quickly
-run through headers backwards and find needed entry.
-
-** Possible module types
-
-| type | description    | "execute" action           |
-|------+----------------+----------------------------|
-|    0 | data           | compile "num" instruction  |
-|      |                | with address to module     |
-|------+----------------+----------------------------|
-|    1 | submodule      | compile "call" instruction |
-|      |                | with address to module     |
-|------+----------------+----------------------------|
-|    2 | imm. submodule | immediately call to module |
-
-** Memory map
-
-| location | size   | description                 |
-|----------+--------+-----------------------------|
-|        0 | ~4096  | core                        |
-|  1500000 | ~32000 | highlevel Fifth boot code   |
-|  200000h |        | core startup messages area  |
-|  5200000 |        | end of dynamic memory space |
-
-* Dynamically loadable modules
-** Keyboard driver
-#+BEGIN_VERSE
-
-KBD_@           ( -- code ) get scancodes for pressed keys from keyboard.
-KBD_down?       ( key -- result ) check is key with specified scancode
-                currently pressed down.
-KBD_SC2FSCII    ( code -- FSCII ) convert key scancode into FSCII code,
-                or in FSK (Fifth standard keycode).
-KBD_F@          ( -- FSCII ) read pressed key FSCII or FSK, returns -1 if no
-                keys are pressed.
-KBD_FW@         ( -- FSCII ) read pressed key FSCII or FSK, if no keys is
-                are pressed then waits until there is.
-
-                FSK
-                ---
-In HEX.
-
-FC      backspace
-FD      TAB
-FE      enter
-FF      space
-
-400     ESC
-401 ... F1 ...
-410     up
-411     right
-412     down
-413     left
-414     INS
-415     DEL
-416     home
-417     end
-418     PG/UP
-419     PG/DN
-#+END_VERSE
-** Mouse driver
-#+BEGIN_VERSE
-mousex  var     Mouse x coordinate.
-mousey  var     Mouse y coordinate.
-mousekeyl var   Mouse left key.
-mousekeym var   Mouse middle key.
-mousekeyr var   Mouse right key.
-mousec  var     Display current mouse coordinates in top left part of screen,
-                if true. (good for debugging)
-mousepointer var  Image buffer, holding current mouse pointer.
-mouseadd        ( ModuleAddr x1 x2 y1 y2 -- ) Add specified area on screen,
-                into mause click buffer. If any mouse button is clicked on
-                that area, module at "ModuleAddr" will be executed.
-mousebe var     Amount of buffer elements.
-mousedo         ( -- ) Updates mouse coordinates and keys. Parse mouse
-                click buffer, and draw mouse cursor to "screen".
-#+END_VERSE
-** 2D graphic library
-
-+ lineh ( color len x y imgbuf -- ) :: draws horisontal line from X,Y
-  coordinates to right, with specified length.
-
-+ linev ( color len x y imgbuf -- ) :: draws vertical line down, from
-  coordinates X,Y, with specified length.
-
-+ box ( color x2 x1 y2 y1 imgbuf -- ) :: draws rectangular box. x2
-  bust be >= x1, y2 must be >= y1.
-
-  #+begin_example
-    x1,y1-----------+
-      |             |
-      |             |
-      +-----------x2,y2
-  #+end_example
-
-+ flipv ( imgbuf -- ) :: flip image vertically.
-
-+ imgcoltrans ( ImgBuf Color ToColor -- ) :: Translate all pixels in
-  specified image with "Color" into "ToColor".
-
-+ imgfill ( color x y imgbuf -- ) :: Fill image region starting at
-  location X & Y with specified color.
-
-** Trigonometry functions
-
-
-*** sin ( a -- result )
-:PROPERTIES:
-:CUSTOM_ID: ID-9a66ca9c-eb5f-45aa-8116-71763081f2fb
-:ID:       9a66ca9c-eb5f-45aa-8116-71763081f2fb
-:END:
-
-Return sine of angle "a", where the:
-
-- Input is scaled such that: 360 degrees = 2000 units (i.e., 1 unit =
-  0.18 degrees).
-
-- The output is scaled to a 16-bit integer range of -10000 to 10000,
-  where ±10000 represents ±1.0 in floating-point terms.
-
-This fixed-point representation allows efficient computation using
-precomputed lookup tables, avoiding floating-point operations which
-are not supported by the virtual CPU's integer-only instruction
-set. The lookup table provides fast, sine values within the system's
-precision.
-
-*** cos ( a -- result )
-
-Return cosine of angle "a", using the same scaling and fixed-point
-representation as the [[id:9a66ca9c-eb5f-45aa-8116-71763081f2fb][sin]] function. Input angles are scaled (360° =
-2000 units), and outputs range from -10000 to 10000. Precomputed
-values in a lookup table ensure high performance for trigonometric
-calculations.
diff --git a/doc/language.org b/doc/language.org
deleted file mode 100644 (file)
index 39073ce..0000000
+++ /dev/null
@@ -1,860 +0,0 @@
-:PROPERTIES:
-:ID:       da7fff9b-0b67-4843-828a-52a404d7f401
-:END:
-#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
-#+TITLE: Fifth - language
-#+AUTHOR: Svjatoslav Agejenko
-#+LANGUAGE: en
-
-#+OPTIONS: H:20 num:20
-#+OPTIONS: author:nil
-
-#+begin_export html
-<style>
-  .flex-center {
-    display: flex;            /* activate flexbox */
-    justify-content: center;  /* horizontally center anything inside   */
-  }
-
-  .flex-center video {
-    width: min(90%, 1000px); /* whichever is smaller wins */
-    height: auto;            /* preserve aspect ratio */
-  }
-
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-</style>
-#+end_export
-
-
-- [[file:5TH_ET.txt][Example Fifth source file - text editor]]
-
-* Fifth source format
-
-Fifth uses a different character table and codes than ASCII (still
-almost similar). I call it FSCII (Fifth Standard Code for Information
-Interchange) for example space character is not 32 but 255 instead.  I
-plan to use mainly HEX numbers, and create new characters to represent
-numeric values. So typical nemric characters "0123..."  is treated
-like ordinary letters.
-
-** FSCII
-
-|    DEC | HEX   | function                               |
-|--------+-------+----------------------------------------|
-| 0 - 15 | 0 - F | HEX numbers                            |
-|    252 | FC    | backspace                              |
-|    253 | FD    | tabulator (TAB)                        |
-|    254 | FE    | carriage return (CR)                   |
-|    255 | FF    | space                                  |
-|   else |       | ordinary characters, same as in ASCII. |
-
-* Fifth commands
-** Compilation & miscellaneous
-*** init ( -- )
-
-- Description :: First module, control is passed to on startup. Contains
-  initialization routines. Also it is the last core module. All new
-  modules on top of it comes as result of executing external source
-  files.
-
-*** head <name> ( -- )
-
-- Description :: Compiles new dictionary entry without specifying new
-  module type.
-- Example ::
-  : head myentry
-
-*** : <name> ( -- )
-
-- Description :: Creates new code module.
-
-*** ; ( -- )
-
-- Description :: Ends module (immideate).
-- Example ::
-  : : hello ." hi there" ;
-
-*** const <name> ( n -- )
-
-- Description :: Defines new constant.
-- Example ::
-  : 2147483647 const max
-
-*** :i <name> ( -- )
-
-- Description :: Same as =:= but this module will be executed
-  immideately even in compile mode.
-- Example ::
-  : :i ( 41 scan ;
-
-*** create <name> ( -- )
-
-- Description :: Same as =head=, but specify module type as data.
-- Example ::
-  : create LotoResults 5 , 13 , 52 , 12 , 11 , 3 ,
-
-*** allot ( n -- )
-
-- Description :: Allocate *n* bytes in dictionary.
-- Example ::
-  : create MyArray 100 allot
-
-*** " <string>" ( -- )
-
-- Description :: Compile string and its size into core.
-- Example ::
-  : create Mystring " This is it's contects"
-
-*** str <name> <string>" ( -- )
-
-- Description :: Just shorter way for defining strings.
-- Example ::
-  : str Mystring This is it's contenc"
-
-*** var <name> ( -- )
-
-- Description :: Define new 32 bit variable.
-- Example ::
-  : var result
-
-*** ' <module> ( -- n )
-
-- Description :: Return memory address of given entry.
-- Example ::
-  : ' init
-
-*** forget <name> ( -- )
-
-- Description :: Erases from RAM given entry and all entries what was
-  defined after it.
-- Example ::
-  : forget myprog
-
-*** [ ( -- )
-
-- Description :: Set interpret mode (immideate).
-
-*** ] ( n -- )
-
-- Description :: Set compile mode and compile top stack element in as
-  literal. Together =[ .... ]= combination provides good way to
-  compute some values only once, at compile time, rather than every
-  time while program is running.
-- Example ::
-  : : calculate - [ 4 MyConst1 + MyConst2 * ] ;
-
-*** defer <name> ( -- )
-
-- Description :: Creates new module, with jump instruction. Later
-  address where to jump can be modified by =is= command. This
-  provides method of forward referencing. So you can use modules what
-  not yet exist.
-
-*** is ( address1 address2 -- )
-
-- Description :: *address1* - where to jump, *address2* - address of
-  module created by =defer= command.
-- Example ::
-  : defer dispver
-  : : run dispver ." running ..." ;
-  :        ... whatever ...
-  : : (dispver ." Version 9.99 " ;
-  : ' (dispver ' dispver is
-
-  Now if I type "run" on the screen appears:
-  : Version 9.99 running ...
-
-*** asc <char> ( -- )
-
-- Description :: Reads char ascii code and treats it as literal
-  (immideate).
-- Example ::
-  : : BreakLine 30 do asc - emit loop ;
-
-  same as:
-  : : BreakLine 30 do    45 emit loop ;
-
-*** dyninc ( handle -- )
-
-- Description :: Execute code in dynamic memory handle. Automatically
-  deallocates it when done.
-
-*** include ( filenumber -- )
-
-- Description :: Execute code in specified file.
-
-*** words ( -- )
-
-- Description :: Display existing blocks in core.
-
-*** bye ( -- )
-
-- Description :: Exit from Fifth.
-
-*** fkey ( -- c )
-
-- Description :: Read one byte from input stream.
-
-*** sadd ( c addr -- )
-
-- Description :: Add one byte *c* to string located at *addr* and
-  updates string length.
-
-*** scan ( c -- )
-
-- Description :: Read input stream and store it to =pad= until it
-  finds *c*. It ignores all *c* bytes until it finds any non *c*
-  byte. Is useful for breaking text lines into words.
-- Example ::
-  :              c  is:  "
-  :       input stream:  """"This is test !"aoeu idh
-  :              result:  This is test !
-
-*** skey ( -- c )
-
-- Description :: So called safe =fkey=. Reads data from input stream
-  but converts characters with ASCII codes: 9 13 10 to spaces.
-
-*** str=str? ( adr1 adr2 -- result )
-
-- Description :: Compares string at *adr1* with string at *adr2*,
-  returns true flag if they are equal or false if they are not.
-  true = -1, false = 0.
-
-*** find ( -- addr )
-
-- Description :: Searches whole dictionary for word in =pad=. If
-  found, returns its address, if not, returns 0.
-
-*** execute ( -- )
-
-- Description :: Execute word located in =pad=. Depending on =mode=.
-
-*** dta ( addr -- DataAddr )
-
-- Description :: Calculates address of dictionary entry data area,
-  from entry point.
-
-*** 2num ( -- num result )
-
-- Description :: Attempt to convert string located in =pad= into
-  numeric value. If succeed returns number and true as result. If
-  not, returns whatever and false as result.
-
-*** dadd ( addr length -- )
-
-- Description :: Add to dictionary data located at *addr*, with
-  specified length.
-
-*** lit ( n -- )
-
-- Description :: Act with number depending on =mode=. When
-  interpreting, leaves it in stack.
-
-*** incmod ( addr -- )
-
-- Description :: Add to dictionary data located at *addr*+1, length
-  is taken from *addr*.
-
-*** here ( -- n )
-
-- Description :: Return =h= contents.
-
-*** mode ( var, 8 bit )
-
-- Description :: Holds input stream parser operation mode. 0 =
-  interpreting, 1 = compiling.
-
-*** pad ( var, 128 bytes )
-
-- Description :: Holds temporary strings.
-
-*** h ( var, 32 bit )
-
-- Description :: Pointer to free byte in memory, always at the end of
-  the dictionary. Each time when something is stored by =c,= command,
-  pointer is increased.
-
-*** lp ( var, 32 bit )
-
-- Description :: Pointer to last dictionary word. Each time when new
-  word is compiled or erased by =forget=, this pointer is updated.
-
-*** modulechk ( Dstr<filename> -- )
-
-- Description :: Check if module is loaded, if not immideately load it.
-
-*** ne ( entrydata entrytype -- )
-
-- Description :: Compile new dictionary entry. Its name must be in
-  =pad=.
-
-** Conditionals & control flow
-*** if ( flag -- )
-
-- Description :: =if 1.. else 2.. then= or =if 1.. then=
-  construction. Conditional execution (immideate). Performs "1.." if
-  *flag* was true, elseway performs "2.." if exist. Execution
-  continues after word =then=.
-- Example ::
-  : 1 if ." nonzero" else ." zero" then
-
-*** >= ( n1 n2 -- result )
-
-- Description :: True if (n1 = n2) or (n1 > n2).
-- Example ::
-  : 5 3 >= if ." first number is greater or equal" then
-
-*** <= ( n1 n2 -- result )
-
-- Description :: True if (n1 = n2) or (n1 < n2).
-
-*** = ( n1 n2 -- result )
-
-- Description :: True if n1 = n2.
-
-*** do ( count -- )
-
-- Description :: =do .. loop= construction (immideate). Performs ".."
-  *count* times. In every step *count* is decreased until it is 0.
-- Example ::
-  : : test 5 do i .d loop ;
-  result: 4 3 2 1 0
-
-*** doexit ( -- )
-
-- Description :: Exit from =do .. loop=.
-
-*** for ( count top -- )
-
-- Description :: =for .. loop= construction (immideate). Performs ".."
-  (top - count) times. In every step *count* is increased until it
-  reaches *top*.
-- Example ::
-  : : test 4 10 for i .d loop ;
-  result: 4 5 6 7 8 9
-
-*** forexit ( -- )
-
-- Description :: Exit from =for .. loop=.
-
-*** until ( -- )
-
-- Description :: =until .. loop= construction (immideate). Performs
-  ".." until flag become true. False by default. Top of return stack
-  holds flag.
-
-*** done ( -- )
-
-- Description :: Exit from =until .. loop=.
-
-** Disk & file access
-*** diskload ( FromDisk ToMem amount -- )
-
-- Description :: Load specified amount of bytes from disk into memory.
-
-*** disksave ( FromMem ToDisk amount -- )
-
-- Description :: Save specified amount of bytes from memory into disk.
-
-*** format ( -- )
-
-- Description :: Erase all files.
-
-*** fsDfilesize@ ( handle -- size )
-
-- Description :: Return size of opened file.
-
-*** fsDcurloc@ ( handle -- location )
-
-- Description :: Return current location in file.
-
-*** fsDupdated@ ( handle -- updated? )
-
-- Description :: Return true if file was updated, ie. write operations
-  occurred.
-
-*** fssave ( FromMem DestFileHandle amount -- )
-
-- Description :: Save data to file.
-
-*** fsload ( SrcFileHandle ToMem amount -- )
-
-- Description :: Load data from file.
-
-*** fseof ( handle -- bytesLeft )
-
-- Description :: Return amount of bytes left till end of file. Useful
-  before read operation.
-
-*** fsls ( -- )
-
-- Description :: List all files and lists (directories, folders) in
-  current path.
-
-*** fslsr ( -- )
-
-- Description :: Same as =fsls= but recursively scans also sub lists.
-
-*** fscl ( DynStrHand -- )
-
-- Description :: Change list (path).
-
-*** fscreate ( DynStrHand -- DescPnt )
-
-- Description :: Create new file or list. Can create multiple lists at
-  once.
-- Example ::
-  When creating:
-  : "\listGAMES\listSTRATEGY\listSIMWORLD\5th-runme"
-  and only =\listGAMES\= already exist, then =listSTRATEGY= and
-  =listSIMWORLD= lists will be created, and empty file =5th-runme=
-  placed in there.
-
-*** fsDsave ( DynHand<data> DynStrHand<filename> -- )
-
-- Description :: Create new file and save all data from dynamic memory
-  block to it.
-
-*** fsDload ( DynStr<SrcFileName> DynHand<DataDest> -- )
-
-- Description :: Load whole file into dynamic memory block.
-
-*** fsDloadnew ( DynStr<SrcFileName> -- DynHand<DataDest> )
-
-- Description :: Load whole file into new dynamic memory block.
-
-** Dynamic memory
-*** dynal ( size -- handle )
-
-- Description :: Allocate dynamic memory block and return its handle.
-
-*** dynde ( handle -- )
-
-- Description :: Deallocate dynamic memory block.
-
-*** dynp ( handle -- addr )
-
-- Description :: Returns pointer to memory where dynamic block data
-  begins.
-
-*** dyns ( handle -- size )
-
-- Description :: Returns size of dynamic block.
-
-*** dynresize ( NewSize handle -- )
-
-- Description :: Nondestructively resize dynamic block.
-
-*** dync@ ( addr handle )
-
-- Description :: Read one byte from dynamic block.
-
-*** dync! ( byte addr dynhandle )
-
-- Description :: Write one byte to dynamic block.
-
-*** dyn@ ( addr handle )
-
-- Description :: Read 32 bit number from dynamic block. Address will
-  specify which number, not byte.
-
-*** dyn! ( 32BitNum addr dynhandle )
-
-- Description :: Write 32 bit number to dynamic block. Address will
-  specify which number, not byte.
-
-*** dyncon ( size "name" -- )
-
-- Description :: Allocate dynamic block with specified size, and
-  create constant holding its handle.
-- Example ::
-  : 100 dyncon MyNewBlock
-
-*** dyn. ( handle -- )
-
-- Description :: Write content of dynamic memory block to screen.
-
-** Graphics and text
-*** . ( n -- )
-
-- Description :: Print number on screen.
-
-*** d. ( n -- )
-
-- Description :: Print number on screen in decimal.
-
-*** ? ( addr -- )
-
-- Description :: Print 32 bit value located at *addr*.
-
-*** ." <string>" ( -- )
-
-- Description :: Print string into screen. Immideately compiles.
-- Example ::
-  : : greeting ." Hello, World" ;
-
-*** tab. ( -- )
-
-- Description :: Print tabulator.
-
-*** calccol ( b g r -- c )
-
-- Description :: Calculate color what best matches given Blue Green &
-  Red values. Values must be in range 0 - 255.
-
-*** imgalloc ( xsize ysize -- imgbuf )
-
-- Description :: Allocate image buffer for specified size.
-
-*** imgsize ( imgbuf -- )
-
-- Description :: Print on the screen X & Y size of image buffer.
-
-*** point ( x y imgbuf -- addr )
-
-- Description :: Returns memory address for specified pixel.
-
-*** pset ( color x y imgbuf -- )
-
-- Description :: Set graphic point.
-
-*** boxf ( x1 x2 y1 y2 imgbuf color -- )
-
-- Description :: Draw filled box.
-
-*** cls ( imgbuf -- )
-
-- Description :: Clear image buffer.
-
-*** setpal ( b g r color -- )
-
-- Description :: Set palette value for specified color. Values must be
-  in range 0 - 63.
-
-*** putchar ( char color x y imgbuf -- )
-
-- Description :: Put graphic character in imagebuffer to specified (x
-  & y) location.
-
-*** scroll ( x y imgbuf -- )
-
-- Description :: Scroll in imgbuf.
-
-*** scrollf ( color x y screen -- )
-
-- Description :: Scroll and fill empty space with given color.
-
-*** at! ( x y -- )
-
-- Description :: Set cursor location.
-
-*** curc! ( color -- )
-
-- Description :: Set text color.
-
-*** curb! ( color -- )
-
-- Description :: Set background color.
-
-*** colnorm ( -- )
-
-- Description :: Set text color to normal.
-
-*** colneg ( -- )
-
-- Description :: Set text color to negative (selected).
-
-*** dyntype ( dynhandle -- )
-
-- Description :: Display content of dynamic memory on screen.
-
-*** fsdisp ( file -- )
-
-- Description :: Clear screen, display file, and wait for key.
-
-*** type ( addr length -- )
-
-- Description :: Types on the screen string, from memory at *addr*
-  and specified length.
-
-*** write ( addr -- )
-
-- Description :: Types on the screen string, from memory at *addr*+1,
-  length is taken from *addr*.
-
-*** screen ( const, 32 bit )
-
-- Description :: Holds handle of screen buffer.
-
-*** copyscreen ( SrcImgHandle DestImgHandle -- )
-
-- Description :: Copy content of source image to destination image.
-  Source and destination images must have same size.
-
-** Math, memory & stack manipulation
-*** off ( n -- )
-
-- Description :: Writes 0 to given address, good for zeroing variable.
-- Example ::
-  : MyVariable off
-
-*** on ( n -- )
-
-- Description :: Writes -1 (true flag) to given address.
-- Example ::
-  : MyVariable on
-
-*** 2dup ( n1 n2 -- n1 n2 n1 n2 )
-*** 2drop ( n1 n2 -- )
-*** nip ( n1 n2 -- n2 )
-*** neg ( n1 -- -n1 )
-:PROPERTIES:
-:CUSTOM_ID: ID-a7cf0a47-40f1-49bc-afde-f6e86ac2c6d8
-:ID:       a7cf0a47-40f1-49bc-afde-f6e86ac2c6d8
-:END:
-+ See also: [[id:861f65e6-7ecb-43f0-9927-396855fb993f][abs ( n -- |n| )]]
-
-- Description :: Invert sign (negate) of a numerical value.
-
-*** bit@ ( n bit -- result )
-
-- Description :: Return specified bit from n.
-- Example ::
-  : 38 2 bit@
-    result will be 1
-
-*** to32bit  ( n1 n2 n3 n4 -- n32 )
-
-- Description :: Treat 4 last stack elements as bytes and unite them
-  into 32 bit double word. Most significant byte on top.
-- Example ::
-  : 12 76 23 11 to32bit
-  result: 186076172
-
-*** to8bit ( n32 -- n1 n2 n3 n4 )
-
-- Description :: Break 32 bit number into 4 bytes. Useful if you need
-  to send 32 bit numbers though 8 bit COM port.
-- Example ::
-  : 186076172 to8bit
-  result: 12 76 23 11
-
-*** mod ( n1 n2 -- reminder )
-
-- Description :: Divide *n1* by *n2* and returns reminder.
-- Example ::
-  : 12 5 mod
-  result: 2
-
-*** bound ( low n high -- n )
-
-- Description :: Check if *n* is in given bounds (upper and lower
-  bounds are both inclusive). If *n* if outside of bounds, increase or
-  decrease its value accordingly to stay within bounds.
-- Examples ::
-  : 5 80 15 bound
-  result: 15
-
-  : 5 10 15 bound
-  result: 10
-
-  : 5 -10 15 bound
-  result: 5
-
-*** bound? ( low n high -- result )
-
-- Description :: Returns true if *n* is in the given bounds. Upper and
-  lower bounds are both inclusive.
-
-*** tab ( col -- spaces )
-
-- Description :: Calculate amount of spaces to add to reach next
-  tabulation from given column.
-
-*** count ( addr -- addr+1 n )
-
-- Description :: Useful for returning bytes from constantly
-  incareasing address. Module =type= is nice example.
-
-*** c, ( n -- )
-
-- Description :: Store one byte at memory specified by =h=. And
-  incarease =h= by 1.
-
-*** , ( n -- )
-
-- Description :: Store 32 bit number at memory specified by =h=. And
-  incarease =h= by 4.
-
-*** cmove ( addr1 addr2 n -- )
-
-- Description :: Copy *n* amount of bytes from memory at *addr1* to
-  memory at *addr2*.
-
-*** rnd ( limit -- result )
-
-- Description :: Generates random number in range 0 to =limit= - 1.
-
-*** abs ( n -- |n| )
-:PROPERTIES:
-:CUSTOM_ID: ID-861f65e6-7ecb-43f0-9927-396855fb993f
-:ID:       861f65e6-7ecb-43f0-9927-396855fb993f
-:END:
-+ See also: [[id:a7cf0a47-40f1-49bc-afde-f6e86ac2c6d8][neg ( n1 -- -n1 )]]
-
-- Description :: Returns absolute value of *n*.
-
-** Dynamic & static strings
-
-Fifth supports both static and dynamic strings. Static strings must
-have predefined space reserved, and string mustn't exceed this
-length. They manipulation is faster. But they use more memory. Static
-string memory address is used to refer to the string.
-
-Dynamic strings can have at any time length form 0 to 0FFh, They take
-up only memory they currently need. They are held in dynamic memory
-blocks, so dynamic block handle is used to refer to this string.
-
-Both types of strings are stored in the way, where first (0th) byte
-holds current string length, following bytes are string itself.
-
-*** Dstral ( -- handle )
-
-- Description :: Allocate new dynamic string.
-
-*** Dstrlen ( handle -- length )
-
-- Description :: Return string length.
-
-*** c+Dstr ( chr handle -- )
-
-- Description :: Add one byte to end of the string.
-
-*** c+lDstr ( chr handle -- )
-
-- Description :: Add one byte to left side (beginning) of the string.
-
-*** Dstr. ( handle -- )
-
-- Description :: Write content of string into screen.
-
-*** Dstrsure ( size Dstr -- )
-
-- Description :: Makes sure that at least requested *size* (amount of
-  characters) is allocated for given dynamic string.
-
-*** Dstr2str ( handle address -- )
-
-- Description :: Copy dynamic string into static memory space.
-
-*** str2Dstr ( address handle -- )
-
-- Description :: Copy static string into dynamic string.
-
-*** Dstr+str ( Dstr addr -- )
-
-- Description :: Add content of dynamic string to static string.
-
-*** D" any string" ( -- Dstr )
-
-- Description :: Moves specified string into dynamic string called
-  =defDstr=.
-
-*** D> any_string ( -- Dstr )
-
-- Description :: Moves specified string into dynamic string called
-  =defDstr=. Space marks end of string!
-
-*** D>2 any_string ( -- Dstr )
-
-- Description :: Moves specified string into dynamic string called
-  =defDstr2=. Space marks end of string!
-
-*** Dstr+Dstr ( Dstr1 Dstr2 -- )
-
-- Description :: Adds *Dstr1* to *Dstr2* and places result into
-  *Dstr2*.
-
-*** Dstrclear ( Dstr -- )
-
-- Description :: Clears content of dynamic string.
-
-*** Dstr2Dstr ( Dstr1 Dstr2 -- )
-
-- Description :: Moves *Dstr1* to *Dstr2*.
-
-*** Dstr ( data" name -- )
-
-- Description :: Creates new dynamic string and moves specified data
-  into it. Then creates new constant with given *name* holding
-  created dynamic string handle.
-- Example ::
-  : Dstr Hello, my name is Sven!" message      \ creates it
-  : message Dstr.                              \ tests it
-
-*** Dstrlscan ( char Dstr -- loc )
-
-- Description :: Searches dynamic string for *char*, from left to
-  right, returns first found *char* location in string, or 0, if not
-  found.
-
-*** Dstrrscan ( char Dstr -- loc )
-
-- Description :: Searches dynamic string for *char*, from right to
-  left, returns first found *char* location in string, or 0, if not
-  found.
-
-*** Dstrlscane ( char Dstr -- loc )
-
-- Description :: Same as =Dstrlscan= but returns string length+1 as
-  location.
-
-*** Dstrleft ( amo Dstr -- )
-
-- Description :: Only specified amount of characters from left remains
-  in dynamic string. ie. cut right part out.
-
-*** Dstrright ( amo Dstr -- )
-
-- Description :: Only specified amount of characters from right
-  remains in dynamic string. ie. cut left part out.
-
-*** Dstrcutl ( amo Dstr -- )
-
-- Description :: Cut specified amount of characters from left of
-  dynamic string out.
-
-*** Dstrsp ( char Dstr1 Dstr2 -- )
-
-- Description :: Separate dynamic string in *Dstr1* into two parts,
-  using *char* as separator. First part will be stored in *Dstr2*,
-  second part in *Dstr1*.
-- Example ::
-  : asc \                               \ ..separator
-  : D> listF\listLIB\5TH_DRVMOUSE       \ ..separate from
-  : defDstr2                            \ ..place result in
-  : Dstrsp              \ separation command
-  : defDstr Dstr.       \ will be: listLIB\5TH_DRVMOUSE
-  : defDstr2 Dstr.      \ will be: listF
-
-*** Dv ( addr -- )
-
-- Description :: Allocates empty dynamic string, and places its
-  handle into given address.
-
-*** Df ( addr -- )
-
-- Description :: Reads dynamic string handle from given address and
-  deallocates (frees) it.
-- Example ::
-  : var mystring1
-  : : testmodule
-  : mystring1 Dv            \ allocates string
-  :
-  :         <whatever>
-  :
-  : mystring1 Df ;          \ deallocates it again when no longer needed.
diff --git a/doc/numbers.png b/doc/numbers.png
deleted file mode 100644 (file)
index 0ccd07b..0000000
Binary files a/doc/numbers.png and /dev/null differ
diff --git a/doc/opcodes_00_09.org b/doc/opcodes_00_09.org
deleted file mode 100644 (file)
index ddc530e..0000000
+++ /dev/null
@@ -1,628 +0,0 @@
-#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
-#+TITLE: Fifth - virtual machine opcodes 0 -- 9
-#+AUTHOR: Svjatoslav Agejenko
-#+LANGUAGE: en
-
-#+OPTIONS: H:20 num:20
-#+OPTIONS: author:nil
-
-#+begin_export html
-<style>
-  .flex-center {
-    display: flex;            /* activate flexbox */
-    justify-content: center;  /* horizontally center anything inside   */
-  }
-
-  .flex-center video {
-    width: min(90%, 1000px); /* whichever is smaller wins */
-    height: auto;            /* preserve aspect ratio */
-  }
-
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-</style>
-#+end_export
-
-* Overview
-
-This document describes virtual machine opcodes 0 through 9. These are
-the fundamental instructions for program flow control, stack
-manipulation, and basic I/O operations.
-
-*Quick Reference:*
-
-| Opcode | Name | Stack Effect     | Bytecode Size | Purpose                         |
-|--------+------+------------------+---------------+---------------------------------|
-|      0 | nop  | --               | 1 byte        | Do nothing (placeholder)        |
-|      1 | halt | --               | 1 byte        | Exit emulator                   |
-|      2 | kbd@ | -- scancode      | 1 byte        | Read keyboard input             |
-|      3 | num  | -- n             | 5 bytes       | Push literal 32-bit number      |
-|      4 | jmp  | --               | 5 bytes       | Unconditional jump              |
-|      5 | call | -- (R: -- ret)   | 5 bytes       | Call subroutine                 |
-|      6 | 1+   | n -- n+1         | 1 byte        | Increment by 1                  |
-|      7 | 1-   | n -- n-1         | 1 byte        | Decrement by 1                  |
-|      8 | dup  | n -- n n         | 1 byte        | Duplicate top of stack          |
-|      9 | drop | n --             | 1 byte        | Discard top of stack            |
-
-* 0: nop (No Operation)
-:PROPERTIES:
-:CUSTOM_ID: opcode-nop
-:ID:       4f0dee8a-647e-4d91-a252-aaf4782b5edc
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value             |
-|------------+-------------------|
-| Opcode     | 0                 |
-| Name       | nop               |
-| Stack      | ( -- )            |
-| Bytecode   | Single byte: =00= |
-
-*Description*
-
-Does nothing. Execution continues immediately to the next instruction.
-This opcode is handled as the entry point to the emulator's instruction
-fetch loop, meaning it effectively "falls through" to the next opcode.
-
-*When to Use:*
-
-- Padding bytecode for alignment purposes
-- Placeholder during development or debugging
-- Safe target for jump instructions when you need a "do nothing" branch
-- Filling unused entries in jump tables
-
-*Example:*
-
-#+BEGIN_SRC
-00              ; nop - do nothing
-03 05 00 00 00  ; num 5 - push 5 onto stack
-#+END_SRC
-
-No observable effect. The instruction pointer simply advances to the
-next opcode.
-
-* 1: halt (Stop Execution)
-:PROPERTIES:
-:CUSTOM_ID: opcode-halt
-:ID:       7c8841d3-2335-4ee9-b6b9-518d05354841
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value             |
-|------------+-------------------|
-| Opcode     | 1                 |
-| Name       | halt              |
-| Stack      | ( -- )            |
-| Bytecode   | Single byte: =01= |
-
-** Description
-
-Terminates the emulator process cleanly. This is the only proper way
-to exit the Fifth environment. When executed, the emulator:
-
-1. Restores text video mode (mode 3)
-2. Closes the virtual disk file handle
-3. Restores the original keyboard interrupt handler
-4. Returns control to DOS
-
-** When to Use
-
-- Terminating the program cleanly and exiting the Fifth environment
-- Implementing a "quit" or "bye" command in REPL
-- Shutting down after fatal errors
-
-** Example
-
-#+BEGIN_SRC
-01              ; halt - exit emulator immediately
-#+END_SRC
-
-In Fifth source code, this is typically invoked via the =bye= word,
-which compiles to the halt opcode.
-
-* 2: kbd@ (Keyboard Input)
-:PROPERTIES:
-:CUSTOM_ID: opcode-kbd-read
-:ID:       820b1b90-4f4c-4ab1-b49f-9b4a52ea2528
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value             |
-|------------+-------------------|
-| Opcode     | 2                 |
-| Name       | kbd@              |
-| Stack      | ( -- scancode )   |
-| Bytecode   | Single byte: =02= |
-
-** Description
-
-Reads a keyboard scancode from the internal ring buffer and pushes it
-onto the data stack. This is a non-blocking operation: if no key is
-pending, it pushes 0 immediately.
-
-** Scan Code Behavior
-
-The keyboard hardware generates scan codes for every key event:
-
-- *Make code*: Generated when a key is pressed (values 1-127)
-- *Break code*: Generated when a key is released (make code + 128)
-
-For example:
-- Pressing 'A' produces scan code =1E=
-- Releasing 'A' produces scan code =9E= (1E + 80 hex)
-
-** Common Scan Codes (US QWERTY)
-
-| Key         | Make Code | Break Code |
-|-------------+-----------+------------|
-| Escape      | 01        | 81         |
-| 1-9         | 02-0A     | 82-8A      |
-| 0           | 0B        | 8B         |
-| Enter       | 1C        | 9C         |
-| Space       | 39        | B9         |
-| Left Arrow  | 4B        | CB         |
-| Right Arrow | 4D        | CD         |
-| Up Arrow    | 48        | C8         |
-| Down Arrow  | 50        | D0         |
-| A           | 1E        | 9E         |
-| Z           | 2C        | AC         |
-
-** When to Use
-
-- Building interactive programs (games, text editors)
-- Reading raw keyboard input without translation to characters
-- Detecting key press/release events separately
-- Implementing custom keyboard drivers or input handlers
-
-** Example
-
-Basic key reading:
-
-#+BEGIN_SRC
-02              ; kbd@ - read scancode
-                ; data stack now contains: scancode (or 0 if no key)
-#+END_SRC
-
-** Return Values
-
-- Returns =0= if no key is available in the buffer
-- Returns scancode (1-255) when a key event is pending
-- Each call consumes one scancode from the buffer
-
-** Important Notes
-
-- This returns raw scan codes, not ASCII characters
-- Use a keyboard layout file (like =5TH_KBD_US=) to translate scan
-  codes to FSCII characters
-- The buffer holds 128 scan codes; older codes are overwritten if full
-
-* 3: num (Push Literal Number)
-:PROPERTIES:
-:CUSTOM_ID: opcode-num
-:ID:       8721dc8c-b237-4e9a-a509-0ded1c02329b
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value                                    |
-|------------+------------------------------------------|
-| Opcode     | 3                                        |
-| Name       | num                                      |
-| Stack      | ( -- n )                                 |
-| Bytecode   | =03= followed by 4 bytes (little-endian) |
-
-** Description
-
-Pushes a 32-bit literal value onto the data stack. The value is encoded
-directly in the instruction stream immediately after the opcode byte.
-After execution, the instruction pointer advances by 4 bytes.
-
-** Bytecode Format
-
-#+BEGIN_SRC
-03 xx xx xx xx
-│  └──────────┘ 32-bit value (little-endian)
-└ opcode
-#+END_SRC
-
-** When to Use
-
-- Loading constant values for calculations
-- Pushing memory addresses onto the stack
-- Setting up parameters for function calls
-- Initializing counters, pointers, and loop variables
-
-** Example
-
-Push the value =0x12345678=:
-
-#+BEGIN_SRC
-03              ; num opcode
-78 56 34 12     ; 32-bit value 0x12345678 (little-endian)
-                ; stack now contains: 0x12345678
-#+END_SRC
-
-In Fifth source code, simply write a number:
-
-#+BEGIN_SRC fifth
-12345678        ; Compiles to: 03 78 56 34 12
-FF              ; Compiles to: 03 FF 00 00 00
-1000            ; Compiles to: 03 00 10 00 00
-#+END_SRC
-
-** Important Notes
-
-- Numbers in Fifth source code are **hexadecimal by default**
-- Use =d.= to display numbers in decimal for debugging
-- All 32 bits are pushed; high bytes are zero-filled for small values
-- The value is stored in little-endian byte order in bytecode
-
-* 4: jmp (Unconditional Jump)
-:PROPERTIES:
-:CUSTOM_ID: opcode-jmp
-:ID:       a5c53b60-ffe9-4ba4-ab87-30c2ccc51a45
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value                                    |
-|------------+------------------------------------------|
-| Opcode     | 4                                        |
-| Name       | jmp                                      |
-| Stack      | ( -- )                                   |
-| Bytecode   | =04= followed by 4-byte target address   |
-
-** Description
-
-Transfers execution unconditionally to the specified address. The
-target address is embedded in the instruction stream immediately after
-the opcode. No return address is saved.
-
-** Bytecode Format
-
-#+BEGIN_SRC
-04 aa aa aa aa
-│  └──────────┘ 32-bit target address (little-endian)
-└ opcode
-#+END_SRC
-
-** When to Use
-
-- Creating infinite loops (combined with conditional exits)
-- Skipping over code blocks
-- Implementing forward jumps in control structures
-- Jump tables and dispatch mechanisms
-
-** Example
-
-Jump to address =0x1000=:
-
-#+BEGIN_SRC
-04              ; jmp opcode
-00 10 00 00     ; target address 0x1000 (little-endian)
-                ; execution continues at 0x1000
-#+END_SRC
-
-Create an infinite loop:
-
-#+BEGIN_SRC
-; At address 0x100:
-04 00 01 00 00  ; jmp 0x100 - infinite loop
-#+END_SRC
-
-Skip over code:
-
-#+BEGIN_SRC
-04 ...          ; jmp to skip_target
-...             ; code to skip
-; skip_target:
-#+END_SRC
-
-** Important Notes
-
-- The address is a **virtual address** in the VM's address space
-- The emulator adds =xms_addr= to convert to a physical memory address
-- No return address is saved; use =call= for subroutines
-
-* 5: call (Call Subroutine)
-:PROPERTIES:
-:CUSTOM_ID: opcode-call
-:ID:       66efbd35-c2b6-4657-ba0f-ff00a3a2c312
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property     | Value                                        |
-|--------------+----------------------------------------------|
-| Opcode       | 5                                            |
-| Name         | call                                         |
-| Stack        | ( -- )                                       |
-| Return Stack | ( -- ret-addr )                              |
-| Bytecode     | =05= followed by 4-byte target address       |
-
-** Description
-
-Calls a subroutine at the specified address. The return address (the
-address of the instruction immediately following this call) is saved
-on the return stack. Use =ret= (opcode 11) to return to the caller.
-
-** Bytecode Format
-
-#+BEGIN_SRC
-05 aa aa aa aa
-│  └──────────┘ 32-bit target address (little-endian)
-└ opcode
-#+END_SRC
-
-** When to Use
-
-- Calling reusable code blocks (functions, procedures)
-- Implementing Forth word definitions
-- Building modular programs with separate subroutines
-- Recursion (with proper stack management)
-
-** Example
-
-#+BEGIN_SRC
-; Main code at 0x100:
-05 00 20 00 00      ; call 0x2000
-03 01 00 00 00      ; num 1 (this is where we return to)
-
-; Subroutine at 0x2000:
-...                 ; subroutine code
-0B                  ; ret - return to caller
-#+END_SRC
-
-** Stack Effects
-
-| Stack        | Before | After     |
-|--------------+--------+-----------|
-| Data Stack   | ...    | ...       |
-| Return Stack | ...    | ret-addr  |
-
-The return address is the virtual address immediately after the 4-byte
-argument (i.e., the address of the next instruction).
-
-** Important Notes
-
-- The return stack is **separate** from the data stack
-- The return stack is also used by =push= and =pop= opcodes
-- Always balance =call= with =ret= to avoid return stack corruption
-- Nesting depth is limited by return stack size
-
-* 6: 1+ (Increment)
-:PROPERTIES:
-:CUSTOM_ID: opcode-1plus
-:ID:       76fe1c8f-756d-406e-9e8a-4ecc8f1d7369
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value              |
-|------------+--------------------|
-| Opcode     | 6                  |
-| Name       | 1+                 |
-| Stack      | ( n -- n+1 )       |
-| Bytecode   | Single byte: =06=  |
-
-** Description
-
-Adds 1 to the value on top of the data stack, modifying it in place.
-This is a highly efficient single-byte operation.
-
-** When to Use
-
-- Incrementing loop counters
-- Advancing pointers through arrays or buffers
-- Computing successor values
-- Any situation where you need to add exactly 1
-
-** Example
-
-#+BEGIN_SRC
-03 05 00 00 00  ; num 5    - stack: [ 5 ]
-06              ; 1+       - stack: [ 6 ]
-06              ; 1+       - stack: [ 7 ]
-#+END_SRC
-
-** Efficiency Comparison
-
-| Operation   | Bytecode                   | Size  |
-|-------------+---------------------------+-------|
-| 1+          | =06=                       | 1 byte|
-| 1 +         | =03 01 00 00 00= =18=      | 6 bytes|
-
-Use =1+= instead of =1 += for better code density.
-
-** Important Notes
-
-- Modifies the value in place (no additional stack space needed)
-- Works identically on signed and unsigned 32-bit values
-- For adding larger values, use =+= (opcode 24)
-
-* 7: 1- (Decrement)
-:PROPERTIES:
-:CUSTOM_ID: opcode-1minus
-:ID:       523f93a3-359e-4a6d-b296-df25008db403
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value              |
-|------------+--------------------|
-| Opcode     | 7                  |
-| Name       | 1-                 |
-| Stack      | ( n -- n-1 )       |
-| Bytecode   | Single byte: =07=  |
-
-** Description
-
-Subtracts 1 from the value on top of the data stack, modifying it in
-place. This is a highly efficient single-byte operation.
-
-** When to Use
-
-- Decrementing loop counters
-- Moving pointers backward through arrays or buffers
-- Computing predecessor values
-- Counting down to zero
-
-** Example
-
-#+BEGIN_SRC
-03 0A 00 00 00  ; num 10   - stack: [ 10 ]
-07              ; 1-       - stack: [ 9 ]
-07              ; 1-       - stack: [ 8 ]
-#+END_SRC
-
-** Common Pattern: Countdown Loop
-
-#+BEGIN_SRC
-: loop ( n -- )
-  begin
-    dup .        ; display counter
-    1- dup       ; decrement and copy for test
-  0= until       ; loop until zero
-  drop           ; clean up
-;
-
-A loop          ; prints A, 9, 8, ... 1
-#+END_SRC
-
-** Important Notes
-
-- Modifies the value in place (no additional stack space needed)
-- Works identically on signed and unsigned 32-bit values
-- For subtracting larger values, use =-= (opcode 25)
-
----------------------------------------------------------------------
-
-* 8: dup (Duplicate)
-:PROPERTIES:
-:CUSTOM_ID: opcode-dup
-:ID:       2a6a449a-fc76-421c-a81c-c2024a15fc78
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value              |
-|------------+--------------------|
-| Opcode     | 8                  |
-| Name       | dup                |
-| Stack      | ( n -- n n )       |
-| Bytecode   | Single byte: =08=  |
-
-** Description
-
-Duplicates the value on top of the data stack, pushing a copy. The
-original value remains, and an identical copy is placed on top.
-
-** When to Use
-
-- Preserving a value before consuming operations
-- Using the same value multiple times in a calculation
-- Displaying values without losing them
-- Setting up parameters for operations that consume values
-
-** Example
-
-#+BEGIN_SRC
-03 2A 00 00 00  ; num 42   - stack: [ 42 ]
-08              ; dup      - stack: [ 42 42 ]
-#+END_SRC
-
-** Common Patterns
-
-*** Read and Keep Address
-
-#+BEGIN_SRC
-addr dup @      ; stack: [ addr value ]
-                ; read from address while keeping the address
-#+END_SRC
-
-*** Display and Keep
-
-#+BEGIN_SRC
-value dup .     ; display value while keeping it on stack
-#+END_SRC
-
-*** Test Without Consuming
-
-#+BEGIN_SRC
-value dup 0=    ; test if zero, keep original value
-if
-  ...           ; handle zero case (value still on stack)
-then
-drop            ; now consume it
-#+END_SRC
-
-** Important Notes
-
-- Increases stack depth by 1
-- Often paired with =drop= to test values without consuming them
-- For duplicating the second stack item, use =over= (opcode 22)
-
----------------------------------------------------------------------
-
-* 9: drop (Discard)
-:PROPERTIES:
-:CUSTOM_ID: opcode-drop
-:ID:       4600dbeb-1833-4e7d-af7e-f6cc6c98d022
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value              |
-|------------+--------------------|
-| Opcode     | 9                  |
-| Name       | drop               |
-| Stack      | ( n -- )           |
-| Bytecode   | Single byte: =09=  |
-
-** Description
-
-Removes and discards the value from the top of the data stack. The
-value is completely lost.
-
-** When to Use
-
-- Cleaning up the stack after calculations
-- Discarding values that are no longer needed
-- Consuming function results you don't need
-- Balancing stack operations
-
-** Example
-
-#+BEGIN_SRC
-03 2A 00 00 00  ; num 42   - stack: [ 42 ]
-03 64 00 00 00  ; num 100  - stack: [ 42 100 ]
-09              ; drop     - stack: [ 42 ]
-09              ; drop     - stack: [ ]
-#+END_SRC
-
-** Common Patterns
-
-*** Discard Unused Return Values
-
-#+BEGIN_SRC
-some-operation drop    ; call operation, ignore result
-#+END_SRC
-
-*** Execute for Side Effect Only
-
-#+BEGIN_SRC
-addr @ drop    ; read from memory, discard value
-               ; useful for prefetching or triggering hardware
-#+END_SRC
-
-*** Clean Up After Conditional
-
-#+BEGIN_SRC
-condition if
-  ...          ; condition was true (consumed by if)
-else
-  ...          ; condition was false
-then
-#+END_SRC
-
-** Important Notes
-
-- Reduces stack depth by 1
-- The value is completely lost; ensure you don't need it
-- Often paired with =dup= for testing values without consuming them
-- For discarding two values, use =2drop= (defined in high-level Fifth)
diff --git a/doc/opcodes_10_19.org b/doc/opcodes_10_19.org
deleted file mode 100644 (file)
index 336b62b..0000000
+++ /dev/null
@@ -1,504 +0,0 @@
-#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
-#+TITLE: Fifth - virtual machine opcodes 10 -- 19
-#+AUTHOR: Svjatoslav Agejenko
-#+LANGUAGE: en
-
-#+OPTIONS: H:20 num:20
-#+OPTIONS: author:nil
-
-#+begin_export html
-<style>
-  .flex-center {
-    display: flex;            /* activate flexbox */
-    justify-content: center;  /* horizontally center anything inside   */
-  }
-
-  .flex-center video {
-    width: min(90%, 1000px); /* whichever is smaller wins */
-    height: auto;            /* preserve aspect ratio */
-  }
-
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-</style>
-#+end_export
-
-* Overview
-
-This document describes virtual machine opcodes 10 through 19. These
-opcodes provide conditional branching, subroutine return, byte-level
-memory access, stack-to-return-stack operations, stack rotation, and
-disk I/O.
-
-*Quick Reference:*
-
-| Opcode | Name   | Stack Effect   | Bytecode Size | Purpose                                         |
-|--------+--------+----------------+---------------+-------------------------------------------------|
-|     10 | if     | flag --        | 5 bytes       | Conditional jump (jump if zero)                 |
-|     11 | ret    | --             | 1 byte        | Return from subroutine                          |
-|     12 | c@     | addr -- byte   | 1 byte        | Read byte from memory                           |
-|     13 | c!     | byte addr --   | 1 byte        | Write byte to memory                            |
-|     14 | push   | n --           | 1 byte        | Move data to return stack                       |
-|     15 | pop    | -- n           | 1 byte        | Move data from return stack                     |
-|     16 | unused | --             | 1 byte        | Reserved for future use. Currently acts as nop. |
-|     17 | rot    | a b c -- b c a | 1 byte        | Rotate three stack elements                     |
-|     18 | disk@  | sector addr -- | 1 byte        | Read 1KB sector from disk                       |
-|     19 | disk!  | addr sector -- | 1 byte        | Write 1KB sector to disk                        |
-
-* 10: if (Conditional Jump)
-:PROPERTIES:
-:CUSTOM_ID: opcode-if
-:ID:       d6f834b6-9a37-4414-91b3-62b3e1d920c1
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value                                    |
-|------------+------------------------------------------|
-| Opcode     | 10 (0x0A)                                |
-| Name       | if                                       |
-| Stack      | ( flag -- )                              |
-| Bytecode   | =0A= followed by 4-byte target address   |
-
-*Description:*
-
-Pops the top value from the data stack. If the value is zero, jumps to
-the address embedded in the instruction stream. If the value is
-non-zero, skips the address and continues with the next instruction.
-
-This "jump if false" semantics is exactly what is needed to jump/skip
-over code because comparison condition was not met:
-
-: #1: <comparison logic, leaves comparison result on the top of data stack>
-: #2: <jmp instruction + pointer to #4 address>
-: #3:   <this code will be executed conditionally, if comparison was true>
-: #4: <any other code that follows after IF ... THEN ... block.>
-
-
-*Bytecode Format:*
-
-#+BEGIN_SRC
-0A aa aa aa aa
-│  └──────────┘ 32-bit target address (little-endian)
-└ opcode
-#+END_SRC
-
-*When to Use*
-
-- Implementing conditional branches in control structures
-- Building if-then-else constructs (the "else" branch)
-- Loop exit conditions
-
-*Important Notes:*
-
-- The jump is taken when flag is ZERO (false condition)
-- This is actually "jump if false" semantics
-- High-level Fifth words like =if= =then= =else= compile to this opcode
-- The address is a virtual address in the VM's address space
-
-* 11: ret (Return from Subroutine)
-:PROPERTIES:
-:CUSTOM_ID: opcode-ret
-:ID:       6e683977-a985-4bb8-9d2c-c860d30e1df6
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property | Value             |
-|----------+-------------------|
-| Opcode   | 11 (0x0B)         |
-| Name     | ret               |
-| Stack    | ( -- )            |
-| R. Stack | ( ret-addr -- )   |
-| Bytecode | Single byte: =0B= |
-
-*Description:*
-
-Returns from a subroutine by popping the return address from the
-return stack and jumping to it. This is the counterpart to the =call=
-opcode (5).
-
-
-*When to Use:*
-
-- Ending subroutine/word definitions
-- Early exit from subroutines
-
-*Example:*
-
-#+BEGIN_SRC
-; Subroutine at address 0x2000:
-03 2A 00 00 00          ; num 42 - push a value
-0B                      ; ret - return to caller
-#+END_SRC
-
-In Fifth source code:
-
-#+BEGIN_SRC fifth
-: myword ( -- n )
-  2A                    \ push 42
-;                       \ compiles to ret
-#+END_SRC
-
-** Important Notes
-
-- Each =ret= must have a matching =call= to maintain return stack balance
-- Unbalanced call/ret pairs will corrupt the return stack
-- The return stack is also used by =push= and =pop= opcodes
-- Return addresses are virtual addresses (without xms_addr offset)
-
-* 12: c@ (Fetch Byte from Memory)
-:PROPERTIES:
-:CUSTOM_ID: opcode-cfetch
-:ID:       a2ce44f7-b661-44e0-909b-644ff52aa38e
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value              |
-|------------+--------------------|
-| Opcode     | 12 (0x0C)          |
-| Name       | c@ (c-fetch)       |
-| Stack      | ( addr -- byte )   |
-| Bytecode   | Single byte: =0C=  |
-
-*Description:*
-
-Reads a single byte from the specified memory address and pushes it
-onto the data stack. The byte value is zero-extended to 32 bits
-(padded with zeros in the upper 24 bits).
-
-*When to Use:*
-
-- Reading character data from strings
-- Parsing binary data structures
-- Reading individual pixels from image buffers
-
-
-*Example:*
-
-Read a byte from address 0x1000:
-
-#+BEGIN_SRC
-03 00 10 00 00      ; num 0x1000 - push address
-0C                  ; c@ - read byte
-; Stack now contains: byte-value (0-255, zero-extended)
-#+END_SRC
-
-
-*Important Notes:*
-
-- The byte is zero-extended: reading 0xFF gives 0x000000FF on stack
-- The address is a virtual address (xms_addr is added internally)
-
-* 13: c! (Store Byte to Memory)
-:PROPERTIES:
-:CUSTOM_ID: opcode-cstore
-:ID:       f129ef87-a31a-40fe-b8d3-984da2db90e2
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value              |
-|------------+--------------------|
-| Opcode     | 13 (0x0D)          |
-| Name       | c! (c-store)       |
-| Stack      | ( byte addr -- )   |
-| Bytecode   | Single byte: =0D=  |
-
-*Description:*
-
-Stores a single byte to the specified memory address. The byte value
-is taken from the low 8 bits of the value on the stack. The upper 24
-bits are ignored.
-
-*When to Use:*
-
-- Writing character data to strings
-- Building binary data structures
-- Drawing individual pixels to image buffers
-
-*Example:*
-
-Store byte 0x42 at address 0x1000:
-
-#+BEGIN_SRC
-03 42 00 00 00      ; num 0x42 - byte value to store
-03 00 10 00 00      ; num 0x1000 - destination address
-0D                  ; c! - store byte
-; Memory at 0x1000 now contains 0x42
-#+END_SRC
-
-
-*Important Notes:*
-
-- Upper 24 bits are ignored (no error if value > 255)
-- The address is a virtual address
-
-* 14: push (Move Data to Return Stack)
-:PROPERTIES:
-:CUSTOM_ID: opcode-push
-:ID:       e4bcbaf1-7724-4051-b19c-1aa7cd06eae6
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value              |
-|------------+--------------------|
-| Opcode     | 14 (0x0E)          |
-| Name       | push               |
-| Stack      | ( n -- )           |
-| R. Stack   | ( -- n )           |
-| Bytecode   | Single byte: =0E=  |
-
-*Description:*
-
-Moves the top value from the data stack to the return stack. This
-provides temporary storage that doesn't interfere with data stack
-operations.
-
-*When to Use:*
-
-- Temporarily saving values during complex stack manipulations
-
-*Example:*
-
-Save a value for later retrieval:
-
-#+BEGIN_SRC
-03 2A 00 00 00      ; num 42 - push value onto data stack
-0E                  ; push - move 42 to return stack
-; Data stack is now empty
-; Return stack now contains 42
-
-; ... do other work ...
-
-0F                  ; pop - retrieve 42 from return stack
-; Data stack now contains 42
-#+END_SRC
-
-
-*Important Notes:*
-
-- Must be balanced with =pop= to avoid return stack corruption
-- Do not mix carelessly with =call= /=ret= pairs
-- The return stack grows downward (like the data stack)
-- Popping too many times can corrupt return addresses
-
-* 15: pop (Move Data from Return Stack)
-:PROPERTIES:
-:CUSTOM_ID: opcode-pop
-:ID:       21871d09-4d58-440f-8c94-231105aa4e3f
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value              |
-|------------+--------------------|
-| Opcode     | 15 (0x0F)          |
-| Name       | pop                |
-| Stack      | ( -- n )           |
-| R. Stack   | ( n -- )           |
-| Bytecode   | Single byte: =0F=  |
-
-*Description:*
-
-Moves the top value from the return stack to the data stack. This is
-the inverse of the =push= opcode.
-
-*When to Use:*
-
-- Retrieving temporarily saved values
-
-*Example:*
-
-Retrieve a saved value:
-
-#+BEGIN_SRC
-; Assuming return stack contains 42 (from previous 'push')
-0F                  ; pop - move 42 from return stack to data stack
-; Data stack now contains 42
-; Return stack top item removed
-#+END_SRC
-
-Important Notes:
-- Popping from an empty return stack causes undefined behavior
-- Always ensure there's a value on the return stack before calling =pop=
-- Balance every =push= with a corresponding =pop=
-
-** Related Opcode: i
-
-The =i= opcode (31) copies (rather than moves) the top of the return
-stack to the data stack, leaving the return stack unchanged.
-
-| Opcode | Action                 | R. Stack Effect |
-|--------+------------------------+-----------------|
-| i      | Copy top to data stack | <unchanged>     |
-| pop    | Move top to data stack | n --            |
-
-* 16: (Unused/Reserved)
-:PROPERTIES:
-:CUSTOM_ID: opcode-unused
-:END:
-
-Opcode 16 (0x10) is reserved for future use. Opcode currently behaves as *nop* instruction.
-
-* 17: rot (Rotate Three Stack Elements)
-:PROPERTIES:
-:CUSTOM_ID: opcode-rot
-:ID:       4cee73f7-c105-4b96-9380-ff89bd7fedad
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value                      |
-|------------+----------------------------|
-| Opcode     | 17 (0x11)                  |
-| Name       | rot                        |
-| Stack      | ( n1 n2 n3 -- n2 n3 n1 )   |
-| Bytecode   | Single byte: =11=          |
-
-*Description*
-
-Rotates the top three values on the data stack. The third item from
-the top moves to the top, while the top two items shift down.
-
-*Visual Representation:*
-#+BEGIN_SRC
-Before:  [ ... n1 n2 n3 ]   (n3 is on top)
-After:   [ ... n2 n3 n1 ]   (n1 is now on top)
-#+END_SRC
-
-Rotation direction: the deepest of the three (n1) rotates to the top.
-
-*When to Use:*
-- Accessing values buried deeper on the stack
-- Swapping values in multi-item calculations
-
-
-*Example:*
-
-#+BEGIN_SRC
-03 01 00 00 00      ; num 1 - push n1
-03 02 00 00 00      ; num 2 - push n2
-03 03 00 00 00      ; num 3 - push n3
-; Stack: [ 1 2 3 ] with 3 on top
-
-11                  ; rot
-; Stack: [ 2 3 1 ] with 1 on top
-#+END_SRC
-
-Important Notes:
-
-- Requires at least three items on the data stack
-- Rotating with fewer items causes undefined behavior
-- This is a rotation, not a swap - all three elements move
-
-* 18: disk@ (Read Disk Sector)
-:PROPERTIES:
-:CUSTOM_ID: opcode-disk-read
-:ID:       bed1aa27-66ac-4c73-bbb9-e49ff2aa67c5
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value                    |
-|------------+--------------------------|
-| Opcode     | 18 (0x12)                |
-| Name       | disk@ (disk-fetch)       |
-| Stack      | ( sector addr -- )       |
-| Bytecode   | Single byte: =12=        |
-
-*Description:*
-
-Reads one sector (1024 bytes) from the virtual disk into memory at the
-specified address.
-
-*Parameters:*
-
-- *sector* (top of stack): Sector number to read from (0-based)
-- *addr* (second): Destination memory address for the data
-
-*When to Use:*
-
-- Loading program code from disk
-- Reading data files
-- Accessing filesystem structures
-
-*Example:*
-
-Read sector 16 into memory at 0x2000:
-
-#+BEGIN_SRC
-03 10 00 00 00      ; num 16 - sector number
-03 00 20 00 00      ; num 0x2000 - destination address
-12                  ; disk@ - read sector
-; 1024 bytes from sector 16 now at address 0x2000
-#+END_SRC
-
-** Technical Details
-
-- One sector = 1024 bytes (1 KB)
-- Sector numbering starts at 0
-- Uses DOS file I/O to access the virtual disk image
-- The virtual disk is typically a file named =disk.img= or similar
-
-** Important Notes
-
-- The address is a virtual address in the VM's address space
-- Reading beyond the end of the disk file may return zeros or cause errors
-- The disk is accessed through DOS file handles, not BIOS interrupts
-
-* 19: disk! (Write Disk Sector)
-:PROPERTIES:
-:CUSTOM_ID: opcode-disk-write
-:ID:       02eda775-e483-4057-b809-de36d586579b
-:END:
-
-#+ATTR_HTML: :border 2 :rules all :frame border
-| Property   | Value                    |
-|------------+--------------------------|
-| Opcode     | 19 (0x13)                |
-| Name       | disk! (disk-store)       |
-| Stack      | ( addr sector -- )       |
-| Bytecode   | Single byte: =13=        |
-
-*Description*
-
-Writes one sector (1024 bytes) from memory to the virtual disk at the
-specified sector number.
-
-*Parameters:*
-
-- *addr* (top of stack): Source memory address
-- *sector* (second): Sector number to write to (0-based)
-
-*When to Use:*
-
-- Saving program data to disk
-- Modifying filesystem structures
-- Persisting state across emulator sessions
-
-*Example:*
-
-Write memory at 0x2000 to sector 16:
-
-#+BEGIN_SRC
-03 00 20 00 00      ; num 0x2000 - source address
-03 10 00 00 00      ; num 16 - sector number
-13                  ; disk! - write sector
-; 1024 bytes from address 0x2000 written to sector 16
-#+END_SRC
-
-*Technical Details:*
-
-- One sector = 1024 bytes (1 KB)
-- Data is first copied to a temporary buffer in conventional memory
-  before being written to disk (required for XMS memory access)
-- Writing to sector 0 may corrupt the bootloader/kernel
-
-*Stack Order Note:*
-
-The stack order is =( addr sector -- )=, which is reversed from
-=disk@= =( sector addr -- )=. This is because the data source (addr)
-is "produced" first, then the destination (sector) is specified.
-
-*Important Notes*
-
-- The address is a virtual address
-- Writing to the disk image is immediate (no buffering)
-- Be careful not to overwrite critical sectors (kernel, filesystem)
diff --git a/doc/opcodes_20_29.org b/doc/opcodes_20_29.org
deleted file mode 100644 (file)
index 14905b8..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
-#+TITLE: Fifth - virtual machine opcodes 20 -- 29
-#+AUTHOR: Svjatoslav Agejenko
-#+LANGUAGE: en
-
-#+OPTIONS: H:20 num:20
-#+OPTIONS: author:nil
-
-#+begin_export html
-<style>
-  .flex-center {
-    display: flex;            /* activate flexbox */
-    justify-content: center;  /* horizontally center anything inside   */
-  }
-
-  .flex-center video {
-    width: min(90%, 1000px); /* whichever is smaller wins */
-    height: auto;            /* preserve aspect ratio */
-  }
-
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-</style>
-#+end_export
-
-
-* 20: @
-:PROPERTIES:
-:CUSTOM_ID: opcode-fetch
-:ID:       0a54f24b-e62a-4244-85e1-855a0007c81e
-:END:
-- *Stack Effect:* =addr -- value=
-- *Description:* Reads a 32-bit value from the specified memory address.
-  Replaces the address on the stack with the value.
-- *Notes:* The address is adjusted by =xms_addr= before reading. This is
-  the 32-bit equivalent of =c@=.
-- *Example:*
-  #+begin_example
-  0x1000  ; Read 32-bit value from address 0x1000
-  @
-  #+end_example
-
-* 21: !
-:PROPERTIES:
-:CUSTOM_ID: opcode-store
-:ID:       50e0c841-d678-41b4-be5a-1bab792f367d
-:END:
-- *Stack Effect:* =value addr --=
-- *Description:* Stores a 32-bit value to the specified memory address.
-- *Notes:* Takes two values: the value to store and the address. The
-  address is adjusted by =xms_addr= before writing.
-- *Example:*
-  #+begin_example
-  0x12345678  ; Value to store
-  0x1000      ; Address to store to
-  !
-  #+end_example
-
-* 22: over
-:PROPERTIES:
-:CUSTOM_ID: opcode-over
-:ID:       29828b20-b14d-41ff-9705-ca576c352fb4
-:END:
-- *Stack Effect:* =n1 n2 -- n1 n2 n1=
-- *Description:* Duplicates the second item on the data stack, placing
-  it on top.
-- *Notes:* Commonly used to access the second item without popping the
-  top item.
-- *Example:*
-  #+begin_example
-  1 2
-  over
-  #+end_example
-  After execution, stack contains 1 2 1.
-
-* 23: swap
-:PROPERTIES:
-:CUSTOM_ID: opcode-swap
-:ID:       905894ae-d687-47cd-add0-f1904179a8a0
-:END:
-- *Stack Effect:* =n1 n2 -- n2 n1=
-- *Description:* Swaps the top two values on the data stack.
-- *Notes:* Essential for reordering stack items during complex
-  operations.
-- *Example:*
-  #+begin_example
-  1 2
-  swap
-  #+end_example
-  After execution, stack contains 2 1.
-
-* 24: +
-:PROPERTIES:
-:CUSTOM_ID: opcode-add
-:ID:       bf4434bb-91a5-40c1-93de-90a0e05a50ec
-:END:
-- *Stack Effect:* =n1 n2 -- n1+n2=
-- *Description:* Adds the top two values on the data stack. The result
-  replaces both values.
-- *Notes:* Performs unsigned 32-bit addition. The top value (n1) is
-  added to the second value (n2).
-- *Example:*
-  #+begin_example
-  1 2
-  +
-  #+end_example
-  After execution, stack contains 3.
-
-* 25: -
-:PROPERTIES:
-:CUSTOM_ID: opcode-sub
-:ID:       9afc77fc-ecee-4a69-b1d2-f511e64a0d72
-:END:
-- *Stack Effect:* =n1 n2 -- n2-n1=
-- *Description:* Subtracts the top value from the second value on the
-  data stack. The result replaces both values.
-- *Notes:* Performs unsigned 32-bit subtraction. The second value (n2)
-  minus the top value (n1).
-- *Example:*
-  #+begin_example
-  1 2
-  -
-  #+end_example
-  After execution, stack contains 1 (2 - 1).
-
-* 26: *
-:PROPERTIES:
-:CUSTOM_ID: opcode-mul
-:ID:       85833e5c-e3ae-41a7-ad3d-6e9f0ecc9cdb
-:END:
-- *Stack Effect:* =n1 n2 -- n1*n2=
-- *Description:* Multiplies the top two values on the data stack. The
-  result replaces both values.
-- *Notes:* Uses 32-bit signed multiplication (IMUL). The top value (n1)
-  is multiplied by the second value (n2).
-- *Example:*
-  #+begin_example
-  2 3
-  *
-  #+end_example
-  After execution, stack contains 6.
-
-* 27: /
-:PROPERTIES:
-:CUSTOM_ID: opcode-div
-:ID:       e5ff13c7-a9e6-4035-8efd-220d05381bf1
-:END:
-- *Stack Effect:* =n1 n2 -- n2/n1=
-- *Description:* Divides the second value by the top value on the data
-  stack. The quotient replaces both values.
-- *Notes:* Uses signed integer division (IDIV). The second value (n2) is
-  divided by the top value (n1).
-- *Example:*
-  #+begin_example
-  2 6
-  /
-  #+end_example
-  After execution, stack contains 3 (6 / 2).
-
-* 28: >
-:PROPERTIES:
-:CUSTOM_ID: opcode-gt
-:ID:       abcc14d3-6cbf-46c3-8a93-ee7180f350d4
-:END:
-- *Stack Effect:* =n1 n2 -- result=
-- *Description:* Compares the second value (n1) with the top value (n2).
-  Returns -1 (true) if n1 > n2, otherwise 0.
-- *Notes:* The comparison is between the second item (n1) and top item
-  (n2) on the stack.
-- *Example:*
-  #+begin_example
-  2 3
-  >
-  #+end_example
-  After execution, stack contains 0 (since 2 < 3).
-
-* 29: <
-:PROPERTIES:
-:CUSTOM_ID: opcode-lt
-:ID:       68362f38-c9e4-43f8-809c-8e15725a58c8
-:END:
-- *Stack Effect:* =n1 n2 -- result=
-- *Description:* Compares the second value (n1) with the top value (n2).
-  Returns -1 (true) if n1 < n2, otherwise 0.
-- *Notes:* The comparison is between the second item (n1) and top item
-  (n2) on the stack.
-- *Example:*
-  #+begin_example
-  2 3
-  <
-  #+end_example
-  After execution, stack contains -1 (since 2 < 3).
diff --git a/doc/opcodes_30_39.org b/doc/opcodes_30_39.org
deleted file mode 100644 (file)
index 3d87fda..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
-#+TITLE: Fifth - virtual machine opcodes 30 -- 39
-#+AUTHOR: Svjatoslav Agejenko
-#+LANGUAGE: en
-
-#+OPTIONS: H:20 num:20
-#+OPTIONS: author:nil
-
-#+begin_export html
-<style>
-  .flex-center {
-    display: flex;            /* activate flexbox */
-    justify-content: center;  /* horizontally center anything inside   */
-  }
-
-  .flex-center video {
-    width: min(90%, 1000px); /* whichever is smaller wins */
-    height: auto;            /* preserve aspect ratio */
-  }
-
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-</style>
-#+end_export
-
-
-* 30: not
-:PROPERTIES:
-:CUSTOM_ID: opcode-not
-:ID:       21994321-a1c6-42f6-9682-d5a3fbabb88a
-:END:
-- *Stack Effect:* =n -- ~n=
-- *Description:* Performs a bitwise NOT operation on the top value of
-  the data stack.
-- *Notes:* Inverts all bits of the dword at the top of the stack.
-- *Example:*
-  #+begin_example
-  0x0000FFFF
-  not
-  #+end_example
-  After execution, stack contains 0xFFFF0000.
-
-* 31: i
-:PROPERTIES:
-:CUSTOM_ID: opcode-i
-:ID:       61fbdd36-4384-44a6-b162-b4e998c4c191
-:END:
-- *Stack Effect:* =-- r=
-- *Description:* Pushes the top value from the return stack onto the
-  data stack.
-- *Notes:* Commonly used to access loop counters or subroutine
-  parameters.
-- *Example:*
-  #+begin_example
-  42
-  push
-  i
-  #+end_example
-  After execution, data stack contains 42.
-
-* 32: cprt@
-:PROPERTIES:
-:CUSTOM_ID: opcode-cprt-read
-:ID:       78c1ac50-9c26-4132-8e02-8311331f2a1c
-:END:
-- *Stack Effect:* =port -- byte=
-- *Description:* Reads a byte from the specified hardware I/O port.
-- *Notes:* Uses IN instruction to read from the port. Replaces the port
-  address with the read byte.
-- *Example:*
-  #+begin_example
-  0x60  ; Keyboard port
-  cprt@
-  #+end_example
-
-* 33: cprt!
-:PROPERTIES:
-:CUSTOM_ID: opcode-cprt-write
-:ID:       cfa8550e-bf8b-4d44-a3d1-9ba8ad183147
-:END:
-- *Stack Effect:* =byte port --=
-- *Description:* Writes a byte to the specified hardware I/O port.
-- *Notes:* Uses OUT instruction to write to the port. Consumes both the
-  byte and port address.
-- *Example:*
-  #+begin_example
-  0x42  ; Byte to write
-  0x60  ; Keyboard port
-  cprt!
-  #+end_example
-
-* 34: i2
-:PROPERTIES:
-:CUSTOM_ID: opcode-i2
-:ID:       c3758859-c82e-40c1-9e92-87e5ef410cd2
-:END:
-- *Stack Effect:* =-- r2=
-- *Description:* Pushes the second value from the return stack onto the
-  data stack.
-- *Notes:* Useful for accessing deeper items in the return stack without
-  popping.
-- *Example:*
-  #+begin_example
-  1 2
-  push push
-  i2
-  #+end_example
-  After execution, data stack contains 1.
-
-* 35: i3
-:PROPERTIES:
-:CUSTOM_ID: opcode-i3
-:ID:       304cadf7-9725-4e2d-8634-2e67b5ad49f3
-:END:
-- *Stack Effect:* =-- r3=
-- *Description:* Pushes the third value from the return stack onto the
-  data stack.
-- *Notes:* Allows access to the third item in the return stack for
-  deeper subroutine contexts.
-- *Example:*
-  #+begin_example
-  1 2 3
-  push push push
-  i3
-  #+end_example
-  After execution, data stack contains 1.
-
-* 36: shl
-:PROPERTIES:
-:CUSTOM_ID: opcode-shl
-:ID:       978d1b75-3a1d-476f-8cdb-d3a6ee40b3f5
-:END:
-
-- *Stack Effect:* =value count -- result=
-- *Description:* Shifts =value= left by =count= bit positions. Each bit
-  position shifted left multiplies the value by 2.
-- *Bits Shifted Out:* Bits that are shifted beyond the most
-  significant bit (bit 31) are **discarded**.
-- *Count Masking:* Only the low byte of =count= is used. On x86
-  processors, the actual shift amount is further masked to 5 bits
-  (=count & 0x1F=), meaning the effective shift is always 0-31.
-
-
-*Corner Cases:*
-- =count = 0=: Value unchanged.
-- =count >= 32=: Due to 5-bit masking, the effective shift is
-  =count mod 32=. For example, shift by 32 results in no change,
-  shift by 33 shifts by 1.
-- =value = 0=: Result is always 0 regardless of count.
-
-*Examples:*
-
-#+begin_example
-1  \ Value to shift
-2  \ Shift amount (count)
-shl
-#+end_example
-Result: 4 (0b0001 << 2 = 0b0100).
-
-#+begin_example
-FF    \ Value: 255 (0x000000FF)
-4     \ Shift by 4
-shl
-#+end_example
-Result: FF0 (0x00000FF0 = 4080 decimal). The low 4 bits (F) were
-shifted up, and the upper bits remain zero.
-#+begin_example
-
-* 37: shr
-:PROPERTIES:
-:CUSTOM_ID: opcode-shr
-:ID:       9dbfcd07-6c34-41b7-b5dc-a33f0773e7cd
-:END:
-
-- *Stack Effect:* =value count -- result=
-- *Description:* Shifts =value= right by =count= bit positions. Each bit
-  position shifted right divides the value by 2 (integer division).
-- *Bits Shifted Out:* Bits that are shifted beyond the least significant
-  bit (bit 0) are **discarded**.
-- *Zero Fill:* This is a **logical shift right** (unsigned). Zeros are
-  shifted in from the left (MSB side). This differs from an arithmetic
-  shift right which would preserve the sign bit.
-- *Count Masking:* Only the low byte of =count= is used. On x86
-  processors, the actual shift amount is further masked to 5 bits
-  (=count & 0x1F=), meaning the effective shift is always 0-31.
-
-*Corner Cases:*
-- =count = 0=: Value unchanged.
-- =count >= 32=: Due to 5-bit masking, the effective shift is
-  =count mod 32=. For example, shift by 32 results in no change,
-  shift by 33 shifts by 1.
-- =value = 0=: Result is always 0 regardless of count.
-- Shifting by 31 always results in 0 (all bits shifted out).
-
-*Examples:*
-#+begin_example
-8  \ Value to shift
-2  \ Shift amount (count)
-shr
-#+end_example
-Result: 2 (0b1000 >> 2 = 0b0010).
-
-#+begin_example
-1      \ Value: only bit 0 set
-1      \ Shift by 1
-shr
-#+end_example
-Result: 0. The single bit was shifted out and discarded.
-
-* 38: or
-:PROPERTIES:
-:CUSTOM_ID: opcode-or
-:ID:       b38b971f-3a5f-4b16-9536-4193d2c5ae6b
-:END:
-- *Stack Effect:* =n1 n2 -- n1|n2=
-- *Description:* Performs a bitwise OR operation on the top two values.
-- *Notes:* The top value (n1) is ORed with the second value (n2).
-- *Example:*
-  #+begin_example
-  1 2
-  or
-  #+end_example
-  After execution, stack contains 3 (0b01 | 0b10).
-
-* 39: xor
-:PROPERTIES:
-:CUSTOM_ID: opcode-xor
-:ID:       e87a0d6d-89b0-4791-9500-654d60d99318
-:END:
-- *Stack Effect:* =n1 n2 -- n1^n2=
-- *Description:* Performs a bitwise XOR operation on the top two values.
-- *Notes:* The top value (n1) is XORed with the second value (n2).
-- *Example:*
-  #+begin_example
-  1 2
-  xor
-  #+end_example
-  After execution, stack contains 3 (0b01 ^ 0b10).
diff --git a/doc/opcodes_40_49.org b/doc/opcodes_40_49.org
deleted file mode 100644 (file)
index 1186994..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
-#+TITLE: Fifth - virtual machine opcodes 40 -- 49
-#+AUTHOR: Svjatoslav Agejenko
-#+LANGUAGE: en
-
-#+OPTIONS: H:20 num:20
-#+OPTIONS: author:nil
-
-#+begin_export html
-<style>
-  .flex-center {
-    display: flex;            /* activate flexbox */
-    justify-content: center;  /* horizontally center anything inside   */
-  }
-
-  .flex-center video {
-    width: min(90%, 1000px); /* whichever is smaller wins */
-    height: auto;            /* preserve aspect ratio */
-  }
-
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-</style>
-#+end_export
-
-
-* 40: vidmap
-:PROPERTIES:
-:CUSTOM_ID: opcode-vidmap
-:ID:       fe47ff6d-768f-4b05-9f8c-f52352c106f4
-:END:
-Stack Footprint
-: addr --
-
-Copies memory from the specified address to the video memory (VGA or
-VESA mode). Used for displaying images directly on the screen.
-
-Parameters:
-- *addr* (32-bit): Source memory address containing the image data to
-  copy to video memory.
-
-** Detailed Operation
-:PROPERTIES:
-:CUSTOM_ID: detailed-operation-4
-:END:
-1. *Video Memory Setup*:
-   - Set video memory segment to =0xA000= (VGA standard segment for
-     graphics mode).
-   - Initialize VESA-related variables (e.g., =gra= for page number).
-2. *VESA Page Mapping*:
-   - For each VESA page (up to 19 pages for 640x480x8 mode):
-     - Set VESA page using interrupt =0x10= with =AX = 0x4F05=.
-     - The page number is stored in =gra=.
-3. *Memory Copying*:
-   - For each page:
-     - Copy 4096 bytes (4KB) from source address to video memory.
-     - Use =STOSD= to write 32-bit words for efficiency.
-   - The source address is incremented by 4KB after each page.
-4. *Final Cleanup*:
-   - Restore original segments and clean up stack.
-
-** Example
-Copy a 640x480x8 image (307,200 bytes) from memory at =0x10000= to video
-memory:
-#+begin_example
-0x10000
-vidmap
-#+end_example
-
-** Notes
-
-- The operation assumes the video mode is set to VESA 640x480x8 (mode
-  =0x101=).
-- The exact number of pages copied depends on the video mode (19 pages
-  for 640x480x8).
-- Requires VESA BIOS support and proper initialization via
-  =set_vesa_mode=.
-
-* 41: mouse@
-:PROPERTIES:
-:CUSTOM_ID: opcode-mouse
-:ID:       b4bce653-d38f-45ed-82ec-13ca78c9860b
-:END:
-Stack Footprint:
-: -- x y buttons
-
-*Description:*
-
-Reads the current mouse position and button states from the mouse
-driver. Returns three values on the stack:
-- X-coordinate,
-- Y-coordinate,
-- button states.
-
-
-- *Returns*:
-  - *x* (32-bit): Current X-coordinate of the mouse cursor (0-based).
-  - *y* (32-bit): Current Y-coordinate of the mouse cursor (0-based).
-  - *buttons* (32-bit): Bitmask of button states:
-    - Bit 0: Left button (1 = pressed)
-    - Bit 1: Right button (1 = pressed)
-    - Bit 2: Middle button (1 = pressed)
-
-*Example:*
-
-#+begin_example
-mouse@
-#+end_example
-After execution, stack contains buttons (top), y, x (bottom).
-
-* 42: vidput - put image1 into image2, at location x, y
-:PROPERTIES:
-:CUSTOM_ID: opcode-vidput
-:ID:       238e8b03-57b6-424d-bfee-b6bb652cefbc
-:END:
-Stack Footprint:
-: addr1 addr2 x y --=
-
-Copies a portion of image1 to image2 at the specified (x, y)
-coordinates with clipping. Unlike =tvidput=, there is no transparency
-support - every pixel is copied regardless of value.
-
-*Parameters:*
-
-- *addr1* (32-bit): Address of the source image structure (width,
-  height, data address).
-- *addr2* (32-bit): Address of the destination image structure (width,
-  height, data address).
-- *x* (32-bit): X-coordinate in the destination image where the copy
-  starts.
-- *y* (32-bit): Y-coordinate in the destination image where the copy
-  starts.
-
-*Image Structure Format:*
-
-Identical to =tvidput=:
-- *Offset 0*: Image width (32-bit)
-- *Offset 4*: Image height (32-bit)
-- *Offset 8*: Base address of image data (32-bit pointer)
-
-*Example:*
-#+begin_example
-0x1000  ; Source image structure
-0x2000  ; Destination image structure
-50      ; x
-50      ; y
-vidput
-#+end_example
-
-* 43: cmove - copy memory array
-:PROPERTIES:
-:CUSTOM_ID: opcode-cmove
-:ID:       79e1916f-4103-42cc-ac10-bb1ee776ed50
-:END:
-
-- *Stack Effect:*
-: addr1 addr2 len --
-
-Copies =len= bytes from =addr1= to =addr2=. Handles overlapping memory
-regions correctly.
-
-- *Notes:* If =addr1 > addr2=, copies backwards to avoid data
-  corruption; otherwise copies forwards.
-- *Example:*
-  #+begin_example
-  100  ; Length
-  0x2000  ; Destination address
-  0x1000  ; Source address
-  cmove
-  #+end_example
-
-* 44: cfill
-:PROPERTIES:
-:CUSTOM_ID: opcode-cfill
-:ID:       fecb9438-d9d2-4224-a017-cc87dba9209e
-:END:
-- *Stack Effect:* =byte addr len --=
-- *Description:* Fills =len= bytes of memory starting at =addr= with the
-  specified byte value.
-- *Notes:* Simple byte-by-byte filling operation. Used for initializing
-  memory regions.
-- *Example:*
-  #+begin_example
-  0xFF  ; Fill byte
-  0x1000  ; Start address
-  100  ; Length
-  cfill
-  #+end_example
-
-* 45: tvidput - put image with transparency support
-:PROPERTIES:
-:CUSTOM_ID: opcode-tvidput
-:ID:       ab45247c-44c3-464d-9e2a-337f483b4616
-:END:
-Stack Footprint:
-: addr1 addr2 x y --
-
-Copies a portion of image1 to image2 at the specified (x, y)
-coordinates with transparency support. Pixels in image1 with value 255
-(0xFF) are treated as transparent and are not copied to the
-destination.
-
-*Parameters:*
-
-- *addr1* (32-bit): Address of the source image structure (contains
-  width, height, and data address).
-- *addr2* (32-bit): Address of the destination image structure (contains
-  width, height, and data address).
-- *x* (32-bit): X-coordinate in the destination image where the copy
-  starts.
-- *y* (32-bit): Y-coordinate in the destination image where the copy
-  starts.
-
-*Image Structure Format:*
-
-Each image structure is stored in memory as follows:
-- *Offset 0*: Image width (32-bit integer)
-- *Offset 4*: Image height (32-bit integer)
-- *Offset 8*: Base address of image data (32-bit pointer)
-
-*Example:*
-#+begin_example
-0x1000  ; Source image structure
-0x2000  ; Destination image structure
-50      ; x
-50      ; y
-tvidput
-#+end_example
-
-*Notes:*
-
-- Transparency is fixed at value 255 (0xFF).
-- The operation handles clipping automatically to ensure the copy stays
-  within destination bounds.
-- Source and destination image structures must be properly formatted.
-
-* 46: depth
-:PROPERTIES:
-:CUSTOM_ID: opcode-depth
-:ID:       77fa76d3-9cd0-49c1-882c-f30383347352
-:END:
-- *Stack Effect:* =-- depth=
-- *Description:* Pushes the current depth (number of items) on the data
-  stack onto the stack.
-- *Notes:* Calculated by comparing the data stack pointer to the base
-  address of the stack.
-- *Example:*
-  #+begin_example
-  1 2 3
-  depth
-  #+end_example
-  After execution, stack contains 3 (depth) followed by 1 2 3.
-
-* 47: charput - draw text character
-:PROPERTIES:
-:CUSTOM_ID: opcode-charput
-:ID:       4bb479cf-aae0-4128-9868-f016c286a162
-:END:
-
-Stack Footprint:
-=colorfg colorbg addrsrc addrdest x y --=
-
-
-Draws an 8x8 character from a source memory buffer to a destination
-image buffer at the specified (x, y) coordinates. Each byte in the
-source buffer represents one row of the character (8 bits per row),
-where each bit determines whether to use the foreground or background
-color for that pixel.
-
-*Parameters:*
-
-- *colorfg* (1 byte): Foreground color value (0-255). Typically a
-  grayscale value where 0 is black and 255 is white.
-- *colorbg* (1 byte): Background color value (0-255).
-- *addrsrc* (32-bit): Memory address pointing to 8 bytes of character
-  data. Each byte represents one row of the character (8 bits per row).
-- *addrdest* (32-bit): Base address of the destination image buffer in
-  memory.
-- *x* (32-bit): X-coordinate (0-based) where the character's left edge
-  starts.
-- *y* (32-bit): Y-coordinate (0-based) where the character's top edge
-  starts.
-
-*Example:*
-
-TODO: Create dedicated page that explains this instruction in
-depth. Link to this new page from current one.
-
-#+begin_example
-0xFF  ; White foreground
-0x00  ; Black background
-0x3000  ; Character data address
-0x5000  ; Video memory address
-20      ; y
-10      ; x
-charput
-#+end_example
-
-Character data for 'A' (ASCII 65):
-#+begin_example
-0x00, 0x18, 0x24, 0x24, 0x24, 0x3C, 0x24, 0x24
-#+end_example
-
-- Each byte represents a row:
-  - Row 0: =0x00= → all pixels black
-  - Row 1: =0x18= → bits 3-4 set (binary =00011000=)
-  - Row 2: =0x24= → bits 2 and 5 set (binary =00100100=)
-  - Row 3: =0x24= → same as row 2
-  - Row 4: =0x24= → same as row 2
-  - Row 5: =0x3C= → bits 2-5 set (binary =00111100=)
-  - Row 6: =0x24= → same as row 2
-  - Row 7: =0x24= → same as row 2
diff --git a/doc/screenshots/dictionary.png b/doc/screenshots/dictionary.png
deleted file mode 100644 (file)
index 73909b0..0000000
Binary files a/doc/screenshots/dictionary.png and /dev/null differ
diff --git a/doc/screenshots/start.png b/doc/screenshots/start.png
deleted file mode 100644 (file)
index 15b5c40..0000000
Binary files a/doc/screenshots/start.png and /dev/null differ
diff --git a/doc/screenshots/text editor.png b/doc/screenshots/text editor.png
deleted file mode 100644 (file)
index 153bf90..0000000
Binary files a/doc/screenshots/text editor.png and /dev/null differ
diff --git a/doc/virtual machine.org b/doc/virtual machine.org
deleted file mode 100644 (file)
index 4078fc4..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-:PROPERTIES:
-:ID:       9b251eb9-aff6-4025-94bf-25e89e26d54a
-:END:
-#+SETUPFILE: ~/.emacs.d/org-styles/html/darksun.theme
-#+TITLE: Fifth - virtual machine
-#+AUTHOR: Svjatoslav Agejenko
-#+LANGUAGE: en
-
-#+OPTIONS: H:20 num:20
-#+OPTIONS: author:nil
-
-#+begin_export html
-<style>
-  .flex-center {
-    display: flex;            /* activate flexbox */
-    justify-content: center;  /* horizontally center anything inside   */
-  }
-
-  .flex-center video {
-    width: min(90%, 1000px); /* whichever is smaller wins */
-    height: auto;            /* preserve aspect ratio */
-  }
-
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-</style>
-#+end_export
-
-
-* Overview
-
-Fifth is a hobby operating system built around a custom stack-based
-virtual CPU. The virtual CPU emulator runs as a COM executable
-(emulator.com) under MS-DOS.
-
-The virtual machine is designed to be simple yet powerful, featuring
-two stacks (data stack and return stack), approximately 50
-instructions (opcodes), and a theoretical 4GB flat address space. It
-serves as the foundation for the Fifth language — a Forth-inspired,
-interactive programming environment where users can define, extend,
-and modify system behavior at runtime.
-
-* x86 Unreal Mode Execution
-
-The emulator runs as a standard DOS COM executable and uses x86
-real-mode assembly with a technique called "unreal mode" to access
-extended memory beyond the 640KB conventional DOS limit. In unreal
-mode, the CPU operates in real-mode (compatible with DOS) but with
-segment registers configured to allow access to the full 32-bit
-address space (up to 4GB).
-
-Key aspects:
-- Starts in real mode for DOS compatibility.
-- Switches temporarily to x86 protected mode to initialize segment
-  registers for 4 GB RAM flat address space.
-- Returns to real mode while retaining 4 GB RAM access.
-- Uses XMS (Extended Memory Specification) for large memory allocation.
-
-** Memory Management and XMS
-
-The emulator uses DOS XMS (Extended Memory Specification) to allocate
-large blocks of extended memory:
-
-- **XMS Allocation**: Allocates the largest available block of extended
-  memory using HIMEM.SYS
-- **Memory Locking**: Locks the allocated block to prevent swapping
-- **Address Mapping**: Uses xms_addr variable to store the linear
-  address of allocated memory
-- **Virtual-to-Physical**: All virtual CPU addresses are offset by
-  xms_addr to convert to physical memory addresses
-
-* Two-Stack Architecture
-
-The virtual CPU uses two separate stacks:
-
-- **Data Stack**: Main working stack for operations.
-- **Return Stack (variable resp)**: Stores return addresses for
-  subroutine calls.
-
-* Graphics System
-
-The virtual machine integrates directly with VESA BIOS for graphics
-output. It uses VESA 640x480 8-bit color mode.
-
-Graphics operations are performed through dedicated VM instructions.
-
-* Boot Process
-
-1. DOS loads emulator.com as a COM executable
-2. system_init() allocates XMS memory and sets up A20 gate
-3. Sets VESA graphics mode (640x480, 8-bit color)
-4. Loads first kilobyte of kernel (core.raw) from disk into beginning
-   of virtual RAM.
-5. Jumps to kernel entry point
-6. Kernel loads remaining 3 kibibytes of kernel bytecode into RAM. So
-   initial bytecode part of the kernel must not exceed 4 kibibytes.
-7. Kernel loads high-level Fifth boot code into RAM.
-8. Kernel starts compiling additional modules to itself from
-   high-level bytecode to gain filesystem support, dynamic RAM support
-   and other essential functions.
-9. Additional modules (keyboard / mouse drivers) and interactive shell
-   are now loaded from filesystem files.
-10. Enters interactive REPL
-
-* Implemented instructions
-
-Virtual CPU opcodes (most of them are available as directly executable commands
-in FIFTH programming language):
-
-
-|  # | Name     | Stack effect          | Description                                              | Notes                                                               |
-|----+----------+-----------------------+----------------------------------------------------------+---------------------------------------------------------------------|
-|  0 | [[file:opcodes_00_09.org::#opcode-nop][nop]]      | --                    | No operation; execution continues to next instruction    | Used for padding or placeholder                                      |
-|  1 | [[file:opcodes_00_09.org::#opcode-halt][halt]]     | --                    | Stop execution and exit emulator                         | Cleanly terminates the Fifth environment                             |
-|  2 | [[file:opcodes_00_09.org::#opcode-kbd-read][kbd@]]     | -- scancode           | Read keyboard scancode; returns 0 if no key pending      | Make codes for press, break codes (value+128) for release            |
-|  3 | [[file:opcodes_00_09.org::#opcode-num][num]]      | -- n                  | Push 32-bit literal from instruction stream              | Followed by 4 bytes (little-endian)                                  |
-|  4 | [[file:opcodes_00_09.org::#opcode-jmp][jmp]]      | --                    | Unconditional jump to address from instruction stream    | Followed by 4-byte target address                                    |
-|  5 | [[file:opcodes_00_09.org::#opcode-call][call]]     | --                    | Call subroutine; push return address on return stack     | Use ret (opcode 11) to return; follow with 4-byte target address     |
-|  6 | [[file:opcodes_00_09.org::#opcode-1plus][1+]]       | n -- n+1              | Increment top of data stack by 1                         | Efficient single-byte operation for counters and pointers            |
-|  7 | [[file:opcodes_00_09.org::#opcode-1minus][1-]]       | n -- n-1              | Decrement top of data stack by 1                         | Efficient single-byte operation for countdown loops                  |
-|  8 | [[file:opcodes_00_09.org::#opcode-dup][dup]]      | n -- n n              | Duplicate top of data stack                              | Preserve values before consuming operations                          |
-|  9 | [[file:opcodes_00_09.org::#opcode-drop][drop]]     | n --                  | Remove and discard top of data stack                     | Clean up stack after operations                                      |
-| 10 | [[file:opcodes_10_19.org::#opcode-if][if]]       | n --                  | Jump to address if top of stack is zero                  |                                                                     |
-| 11 | [[file:opcodes_10_19.org::#opcode-ret][ret]]      |                       | Return from subroutine (pop return address)              |                                                                     |
-| 12 | [[file:opcodes_10_19.org::#opcode-cfetch][c@]]       | addr -- byte          | Read byte from memory at specified address               |                                                                     |
-| 13 | [[file:opcodes_10_19.org::#opcode-cstore][c!]]       | byte addr --          | Store byte to specified memory address                   |                                                                     |
-| 14 | [[file:opcodes_10_19.org::#opcode-push][push]]     | n --                  | Move top of data stack to return stack                   |                                                                     |
-| 15 | [[file:opcodes_10_19.org::#opcode-pop][pop]]      | -- n                  | Move top of return stack to data stack                   |                                                                     |
-| 16 | <unused> |                       |                                                          |                                                                     |
-| 17 | [[file:opcodes_10_19.org::#opcode-rot][rot]]      | n1 n2 n3 -- n2 n3 n1  | Rotate top three stack elements                          |                                                                     |
-| 18 | [[file:opcodes_10_19.org::#opcode-disk-read][disk@]]    | sector addr --        | Read 1KB from disk into RAM at specified address         |                                                                     |
-| 19 | [[file:opcodes_10_19.org::#opcode-disk-write][disk!]]    | addr sector --        | Write 1KB from RAM to disk at specified sector           |                                                                     |
-| 20 | [[file:opcodes_20_29.org::#opcode-fetch][@]]        | addr -- n             | Read 32-bit value from memory                            |                                                                     |
-| 21 | [[file:opcodes_20_29.org::#opcode-store][!]]        | n addr --             | Store 32-bit value to memory                             |                                                                     |
-| 22 | [[file:opcodes_20_29.org::#opcode-over][over]]     | n1 n2 -- n1 n2 n1     | Duplicate second item on data stack                      |                                                                     |
-| 23 | [[file:opcodes_20_29.org::#opcode-swap][swap]]     | n1 n2 -- n2 n1        | Swap top two items on data stack                         |                                                                     |
-| 24 | [[file:opcodes_20_29.org::#opcode-add][+]]        | n1 n2 -- n1+n2        | Add top two items on data stack                          |                                                                     |
-| 25 | [[file:opcodes_20_29.org::#opcode-sub][-]]        | n1 n2 -- n1-n2        | Subtract second item from top item on data stack         | TODO: verify argument order                                         |
-| 26 | [[file:opcodes_20_29.org::#opcode-mul][*]]        | n1 n2 -- n1*n2        | Multiply top two items on data stack                     |                                                                     |
-| 27 | [[file:opcodes_20_29.org::#opcode-div][/]]        | n1 n2 -- n2/n1        | Divide top item by second item on data stack             | TODO: verify argument order                                         |
-| 28 | [[file:opcodes_20_29.org::#opcode-gt][>]]        | n1 n2 -- result       | Compare n1 > n2 (returns true, false otherwise)          | TODO: document, what true and false means                           |
-| 29 | [[file:opcodes_20_29.org::#opcode-lt][<]]        | n1 n2 -- result       | Compare n1 < n2 (returns true, false otherwise)          | TODO: document, what true and false means                           |
-| 30 | [[file:opcodes_30_39.org::#opcode-not][not]]      | n -- ~n               | Bitwise NOT on top of data stack                         |                                                                     |
-| 31 | [[file:opcodes_30_39.org::#opcode-i][i]]        | -- n                  | Push top of return stack to data stack                   |                                                                     |
-| 32 | [[file:opcodes_30_39.org::#opcode-cprt-read][cprt@]]    | port -- byte          | Read byte from hardware I/O port                         |                                                                     |
-| 33 | [[file:opcodes_30_39.org::#opcode-cprt-write][cprt!]]    | byte port --          | Write byte to hardware I/O port                          |                                                                     |
-| 34 | [[file:opcodes_30_39.org::#opcode-i2][i2]]       | -- n                  | Push second item from return stack to data stack         |                                                                     |
-| 35 | [[file:opcodes_30_39.org::#opcode-i3][i3]]       | -- n                  | Push third item from return stack to data stack          |                                                                     |
-| 36 | [[file:opcodes_30_39.org::#opcode-shl][shl]]      | value count -- result | Left shift value by count bits; shifted-out bits discarded |
-| 37 | [[file:opcodes_30_39.org::#opcode-shr][shr]]      | value count -- result | Logical right shift; zeros shifted in, shifted-out bits discarded |
-| 38 | [[file:opcodes_30_39.org::#opcode-or][or]]       | n1 n2 -- result       | Bitwise OR of top two items on data stack                |                                                                     |
-| 39 | [[file:opcodes_30_39.org::#opcode-xor][xor]]      | n1 n2 -- result       | Bitwise XOR of top two items on data stack               |                                                                     |
-| 40 | [[file:opcodes_40_49.org::#opcode-vidmap][vidmap]]   | addr --               | Copy memory to video memory                              |                                                                     |
-| 41 | [[file:opcodes_40_49.org::#opcode-mouse][mouse@]]   | -- x y buttons        | Read mouse coordinates and button states                 |                                                                     |
-| 42 | [[file:opcodes_40_49.org::#opcode-vidput][vidput]]   | addr1 addr2 x y --    | Blit image1 to image2 at (x,y) without transparency      |                                                                     |
-| 43 | [[file:opcodes_40_49.org::#opcode-cmove][cmove]]    | addr1 addr2 len --    | Copy memory block from addr1 to addr2                    |                                                                     |
-| 44 | [[file:opcodes_40_49.org::#opcode-cfill][cfill]]    | byte addr len --      | Fill memory with specified byte value                    |                                                                     |
-| 45 | [[file:opcodes_40_49.org::#opcode-tvidput][tvidput]]  | addr1 addr2 x y --    | Blit image1 to image2 at (x,y) with transparency support |                                                                     |
-| 46 | [[file:opcodes_40_49.org::#opcode-depth][depth]]    | -- depth              | Push current data stack depth                            |                                                                     |
-| 47 | [[file:opcodes_40_49.org::#opcode-charput][charput]]  | fg bg src dest x y -- | Draw character from source buffer to destination buffer  |
-
-
-
index 03aba5b..b92a840 100644 (file)
@@ -1,13 +1,61 @@
-; Opcodes 20-29: @, !, over, swap, plus, minus, mul, div, great, less
+; Opcodes 20-29: Memory access, stack operations, arithmetic, and comparison
+;
+; This file implements opcodes 20-29 of the Fifth virtual machine:
+; 20: @    - Fetch 32-bit value from memory
+; 21: !    - Store 32-bit value to memory  
+; 22: over - Duplicate second stack item
+; 23: swap - Exchange top two stack items
+; 24: +    - Add two 32-bit values
+; 25: -    - Subtract two 32-bit values
+; 26: *    - Multiply two 32-bit values (signed)
+; 27: /    - Divide two 32-bit values (signed)
+; 28: >    - Greater than comparison
+; 29: <    - Less than comparison
 
-op_20_x@:                       ; Fetch 32-bit: ( addr -- n )
+op_20_x@:                       ; Fetch 32-bit: ( addr -- value )
+; Reads a 32-bit value from the specified memory address and replaces
+; the address with the fetched value on the data stack.
+;
+; Stack behavior:
+;   Before: [ addr ]
+;   After:  [ value ]
+;
+; Memory access:
+;   - Takes virtual address from top of data stack
+;   - Converts to physical address by adding xms_addr
+;   - Reads 32-bit value from physical memory
+;   - Replaces address with value on stack
+;
+; Notes:
+;   - This is the 32-bit equivalent of c@ (opcode 16)
+;   - Virtual address translation allows memory management
+;   - Reads full 32-bit words, not bytes
        mov     eax, [es:edi]           ; eax = virtual address from top of data stack
        add     eax, [xms_addr]         ; convert virtual address to physical address
        mov     eax, [es:eax]           ; read 32-bit value from memory
        mov     [es:edi], eax           ; replace address on stack with the fetched value
        jmp     emu                     ; return to emulation loop
 
-op_21_x!:                       ; Store 32-bit: ( n addr -- )
+op_21_x!:                       ; Store 32-bit: ( value addr -- )
+; Stores a 32-bit value to the specified memory address. Both the value
+; and address are consumed from the data stack.
+;
+; Stack behavior:
+;   Before: [ value addr ]
+;   After:  [ ]
+;
+; Memory access:
+;   - Takes address from top of stack (TOS)
+;   - Takes value to store from second on stack
+;   - Converts virtual address to physical address
+;   - Stores 32-bit value to physical memory
+;   - Removes both arguments from stack
+;
+; Notes:
+;   - This is the 32-bit equivalent of c! (opcode 17)
+;   - Virtual address translation provides memory protection
+;   - Order is value then addr (Forth standard: value to address)
+;   - Both arguments are consumed (stack cleaned up)
        mov         eax, [es:edi]       ; eax = virtual address (top of stack)
        add         eax, [xms_addr]     ; convert virtual address to physical address
        mov         ecx, [es:edi+4]     ; ecx = value to store (second on stack)
@@ -16,18 +64,85 @@ op_21_x!:                       ; Store 32-bit: ( n addr -- )
        jmp         emu                 ; return to emulation loop
 
 op_22_xover:                    ; Over: ( a b -- a b a )
+; Duplicates the second item on the data stack, placing a copy on top.
+; This allows access to the second item without disturbing the top item.
+;
+; Stack behavior:
+;   Before: [ a b ]      (b = TOS, a = second)
+;   After:  [ a b a ]    (new a = TOS)
+;
+; Operation:
+;   - Reads second item (a) from stack
+;   - Grows stack by one element (decrement stack pointer)
+;   - Writes copy of a to new top of stack
+;
+; Notes:
+;   - Essential for preserving values while using the top item
+;   - Often used with arithmetic operations that consume arguments
+;   - More efficient than dup+swap+drop combination
+;   - Increases stack depth by 1
+;
+; Common usage:
+;   a b over -> a b a (can now use b while preserving a)
        mov         ebx, [es:edi+4]     ; ebx = a (second element on stack)
        sub         edi, 4              ; make room on data stack for one element
        mov         [es:edi], ebx       ; push copy of a onto top of stack
        jmp         emu                 ; return to emulation loop
 
 op_23_xswap:                    ; Swap: ( a b -- b a )
+; Exchanges the top two values on the data stack. This is essential for
+; reordering arguments when the natural stack order doesn't match the
+; required order for operations.
+;
+; Stack behavior:
+;   Before: [ a b ]      (b = TOS, a = second)
+;   After:  [ b a ]      (a = TOS, b = second)
+;
+; Operation:
+;   - Reads top item (b) into register
+;   - Uses xchg to atomically exchange with second item (a)
+;   - Writes result back to stack
+;
+; Notes:
+;   - Fundamental stack manipulation operation
+;   - Used extensively for argument reordering
+;   - More efficient than multiple push/pop operations
+;   - Stack depth remains unchanged
+;
+; Common usage:
+;   a b swap -> b a (arguments now in correct order)
+;   Often used before arithmetic operations to fix operand order
        mov         ebx, [es:edi]       ; ebx = b (top of stack)
        xchg    ebx, [es:edi+4]     ; exchange ebx with a (second on stack); ebx=a, [edi+4]=b
        mov         [es:edi], ebx       ; top of stack = a
        jmp         emu                 ; return to emulation loop
 
 op_24_xplus:                    ; Add: ( n1 n2 -- n1+n2 )
+; Adds the top two values on the data stack, replacing them with the sum.
+; This is a fundamental arithmetic operation for mathematical computations.
+;
+; Stack behavior:
+;   Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
+;   After:  [ sum ]      (sum = n1 + n2)
+;
+; Operation:
+;   - Reads top item (n2) into register
+;   - Pops n2 off stack (n1 becomes new TOS)
+;   - Adds n2 to n1 in place (n1 = n1 + n2)
+;
+; Notes:
+;   - Performs unsigned 32-bit addition
+;   - Overflow wraps around modulo 2^32
+;   - Operates in place for efficiency (no extra stack slot needed)
+;   - Reduces stack depth by 1
+;
+; Common usage:
+;   5 3 + -> 8
+;   addr 4 + -> addr+4 (pointer arithmetic)
+;
+; Edge cases:
+;   - 0xFFFFFFFF + 1 = 0 (wrap around)
+;   - Any number + 0 = same number
        mov         ebx, [es:edi]       ; ebx = n2 (the addend — top of stack)
        add         edi, 4              ; pop n2 off the stack; n1 is now the new top
        add         [es:edi], ebx       ; [es:edi] = n1 + n2 (add n2 to n1 in place)
@@ -59,6 +174,35 @@ op_25_xminus:                   ; Subtract: ( n1 n2 -- n1-n2 )
        jmp         emu                 ; return to emulation loop
 
 op_26_xmul:                     ; Multiply (signed): ( n1 n2 -- n1*n2 )
+; Multiplies the top two values on the data stack using signed 32-bit
+; multiplication. The result is the low 32 bits of the product.
+;
+; Stack behavior:
+;   Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
+;   After:  [ product ]  (product = n1 * n2)
+;
+; Operation:
+;   - Reads top item (n2) into eax
+;   - Pops n2 off stack (n1 becomes new TOS)
+;   - Clears edx (required for signed multiply)
+;   - Performs signed multiply: edx:eax = eax * n1
+;   - Stores low 32 bits (eax) as result
+;
+; Notes:
+;   - Uses IMUL instruction (signed multiplication)
+;   - Result is low 32 bits only (high bits in edx are discarded)
+;   - Handles both positive and negative numbers correctly
+;   - Overflow behavior: result wraps around modulo 2^32
+;   - Reduces stack depth by 1
+;
+; Common usage:
+;   5 3 * -> 15
+;   -2 4 * -> -8
+;
+; Edge cases:
+;   - 0 * anything = 0
+;   - Large products may overflow (wrap around)
+;   - Division by zero not possible here
        mov         eax, [es:edi]       ; eax = n2 (top of stack)
        add         edi, 4              ; pop n2 off the stack; n1 is now the new top
        sub         edx, edx            ; clear edx before signed multiply
@@ -67,6 +211,37 @@ op_26_xmul:                     ; Multiply (signed): ( n1 n2 -- n1*n2 )
        jmp         emu                 ; return to emulation loop
 
 op_27_xdiv:                     ; Divide (signed): ( n1 n2 -- n1/n2 )
+; Divides the second value by the top value using signed 32-bit division.
+; Returns the quotient only (remainder is discarded).
+;
+; Stack behavior:
+;   Before: [ n1 n2 ]    (n2 = divisor = TOS, n1 = dividend = second)
+;   After:  [ quotient ] (quotient = n1 / n2)
+;
+; Operation:
+;   - Pops divisor (n2) off stack (dividend n1 becomes TOS)
+;   - Reads dividend (n1) into eax
+;   - Sign-extends eax into edx:eax (required for signed division)
+;   - Performs signed division: eax = edx:eax / divisor
+;   - Stores quotient (eax) as result
+;
+; Notes:
+;   - Uses IDIV instruction (signed division)
+;   - Returns quotient only (remainder discarded)
+;   - Handles both positive and negative numbers correctly
+;   - Division by zero causes CPU exception (not handled)
+;   - Reduces stack depth by 1
+;
+; Common usage:
+;   15 3 / -> 5
+;   -8 4 / -> -2
+;
+; Edge cases:
+;   - Division by zero: CPU exception (crash)
+;   - Negative division: follows standard signed division rules
+;   - Remainder is discarded (use mod operation if needed)
+;
+; WARNING: Division by zero will crash the emulator!
        add         edi, 4              ; pop n2; n1 is now the new top (but we read n2 from edi-4)
        mov         eax, [es:edi]       ; eax = n1 (the dividend)
        cdq                         ; sign-extend eax into edx:eax for signed division
@@ -75,6 +250,39 @@ op_27_xdiv:                     ; Divide (signed): ( n1 n2 -- n1/n2 )
        jmp         emu                 ; return to emulation loop
 
 op_28_xgreat:                   ; Greater Than: ( a b -- flag )
+; Compares the second value (a) with the top value (b). Returns -1 (true)
+; if a > b, otherwise returns 0 (false). This is a fundamental comparison
+; operation for conditional logic.
+;
+; Stack behavior:
+;   Before: [ a b ]      (b = TOS, a = second)
+;   After:  [ flag ]     (flag = -1 if a > b, 0 otherwise)
+;
+; Operation:
+;   - Reads top item (b) into eax
+;   - Pops b off stack (a becomes new TOS)
+;   - Sets edx = 0 (false flag)
+;   - Compares a with b
+;   - If a > b, sets edx = -1 (true flag)
+;   - Stores result flag on stack
+;
+; Notes:
+;   - Returns -1 for true (all bits set), 0 for false
+;   - Standard Forth truth value convention
+;   - Signed comparison (works for negative numbers)
+;   - Reduces stack depth by 1
+;
+; Truth value convention:
+;   - -1 = true (all bits set, non-zero)
+;   -  0 = false (zero)
+;
+; Common usage:
+;   5 3 > -> 0 (false, 5 is not greater than 3)
+;   3 5 > -> -1 (true, 3 is greater than 5)
+;
+; Edge cases:
+;   - Equal values return 0 (false)
+;   - Negative numbers compared correctly
        mov         eax, [es:edi]       ; eax = b (top of stack)
        add         edi, 4              ; pop b off the stack; a is now the new top
        mov         edx, 0              ; edx = 0 (default: false)
@@ -85,6 +293,44 @@ l3: mov         [es:edi], edx       ; store flag as new top of stack
        jmp         emu                 ; return to emulation loop
 
 op_29_xless:                    ; Less Than: ( a b -- flag )
+; Compares the second value (a) with the top value (b). Returns -1 (true)
+; if a < b, otherwise returns 0 (false). This is the complement of the
+; greater than operation and essential for conditional logic.
+;
+; Stack behavior:
+;   Before: [ a b ]      (b = TOS, a = second)
+;   After:  [ flag ]     (flag = -1 if a < b, 0 otherwise)
+;
+; Operation:
+;   - Reads top item (b) into eax
+;   - Pops b off stack (a becomes new TOS)
+;   - Sets edx = 0 (false flag)
+;   - Compares a with b
+;   - If a < b, sets edx = -1 (true flag)
+;   - Stores result flag on stack
+;
+; Notes:
+;   - Returns -1 for true (all bits set), 0 for false
+;   - Standard Forth truth value convention
+;   - Signed comparison (works for negative numbers)
+;   - Reduces stack depth by 1
+;   - Complementary to > (greater than) operation
+;
+; Truth value convention:
+;   - -1 = true (all bits set, non-zero)
+;   -  0 = false (zero)
+;
+; Common usage:
+;   3 5 < -> -1 (true, 3 is less than 5)
+;   5 3 < -> 0 (false, 5 is not less than 3)
+;
+; Edge cases:
+;   - Equal values return 0 (false)
+;   - Negative numbers compared correctly
+;
+; Relationship to other comparisons:
+;   a b <  is equivalent to  b a >
+;   a b <> (not equal) can be implemented as: over over <> = drop
        mov         eax, [es:edi]       ; eax = b (top of stack)
        add         edi, 4              ; pop b off the stack; a is now the new top
        mov         edx, 0              ; edx = 0 (default: false)