From 32c4cc3e5078d359a0dc50846d57d25589efae6a Mon Sep 17 00:00:00 2001 From: Svjatoslav Agejenko Date: Sat, 10 Oct 2026 21:44:53 +0300 Subject: [PATCH] docs: rename doc/ to Documentation/, add incremental org export - 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. --- .gitignore | 3 + AGENTS.md | 12 +- {doc => Documentation}/5TH_ET.txt | 0 {doc => Documentation}/index.org | 0 {doc => Documentation}/language.org | 0 {doc => Documentation}/numbers.png | Bin {doc => Documentation}/opcodes_00_09.org | 0 {doc => Documentation}/opcodes_10_19.org | 0 Documentation/opcodes_20_29.org | 953 ++++++++++++++++++ {doc => Documentation}/opcodes_30_39.org | 0 {doc => Documentation}/opcodes_40_49.org | 0 .../screenshots/dictionary.png | Bin {doc => Documentation}/screenshots/start.png | Bin .../screenshots/text editor.png | Bin {doc => Documentation}/virtual machine.org | 0 Tools/Update web site | 67 +- doc/opcodes_20_29.org | 194 ---- emulator/opcodes_20_29.asm | 252 ++++- 18 files changed, 1220 insertions(+), 261 deletions(-) rename {doc => Documentation}/5TH_ET.txt (100%) rename {doc => Documentation}/index.org (100%) rename {doc => Documentation}/language.org (100%) rename {doc => Documentation}/numbers.png (100%) rename {doc => Documentation}/opcodes_00_09.org (100%) rename {doc => Documentation}/opcodes_10_19.org (100%) create mode 100644 Documentation/opcodes_20_29.org rename {doc => Documentation}/opcodes_30_39.org (100%) rename {doc => Documentation}/opcodes_40_49.org (100%) rename {doc => Documentation}/screenshots/dictionary.png (100%) rename {doc => Documentation}/screenshots/start.png (100%) rename {doc => Documentation}/screenshots/text editor.png (100%) rename {doc => Documentation}/virtual machine.org (100%) delete mode 100644 doc/opcodes_20_29.org diff --git a/.gitignore b/.gitignore index 90a65f0..3646344 100755 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ bin/ .aider* *.html + +# Incremental org export cache (Tools/Update web site) +.org-export-state diff --git a/AGENTS.md b/AGENTS.md index 35e5a23..e0496ef 100644 --- 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/doc/5TH_ET.txt b/Documentation/5TH_ET.txt similarity index 100% rename from doc/5TH_ET.txt rename to Documentation/5TH_ET.txt diff --git a/doc/index.org b/Documentation/index.org similarity index 100% rename from doc/index.org rename to Documentation/index.org diff --git a/doc/language.org b/Documentation/language.org similarity index 100% rename from doc/language.org rename to Documentation/language.org diff --git a/doc/numbers.png b/Documentation/numbers.png similarity index 100% rename from doc/numbers.png rename to Documentation/numbers.png diff --git a/doc/opcodes_00_09.org b/Documentation/opcodes_00_09.org similarity index 100% rename from doc/opcodes_00_09.org rename to Documentation/opcodes_00_09.org diff --git a/doc/opcodes_10_19.org b/Documentation/opcodes_10_19.org similarity index 100% rename from doc/opcodes_10_19.org rename to Documentation/opcodes_10_19.org diff --git a/Documentation/opcodes_20_29.org b/Documentation/opcodes_20_29.org new file mode 100644 index 0000000..35adc9b --- /dev/null +++ b/Documentation/opcodes_20_29.org @@ -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 + +#+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/doc/opcodes_30_39.org b/Documentation/opcodes_30_39.org similarity index 100% rename from doc/opcodes_30_39.org rename to Documentation/opcodes_30_39.org diff --git a/doc/opcodes_40_49.org b/Documentation/opcodes_40_49.org similarity index 100% rename from doc/opcodes_40_49.org rename to Documentation/opcodes_40_49.org diff --git a/doc/screenshots/dictionary.png b/Documentation/screenshots/dictionary.png similarity index 100% rename from doc/screenshots/dictionary.png rename to Documentation/screenshots/dictionary.png diff --git a/doc/screenshots/start.png b/Documentation/screenshots/start.png similarity index 100% rename from doc/screenshots/start.png rename to Documentation/screenshots/start.png diff --git a/doc/screenshots/text editor.png b/Documentation/screenshots/text editor.png similarity index 100% rename from doc/screenshots/text editor.png rename to Documentation/screenshots/text editor.png diff --git a/doc/virtual machine.org b/Documentation/virtual machine.org similarity index 100% rename from doc/virtual machine.org rename to Documentation/virtual machine.org diff --git a/Tools/Update web site b/Tools/Update web site index d7d5fd7..10b9574 100755 --- a/Tools/Update web site +++ b/Tools/Update web site @@ -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/opcodes_20_29.org b/doc/opcodes_20_29.org deleted file mode 100644 index 14905b8..0000000 --- a/doc/opcodes_20_29.org +++ /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 - -#+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/emulator/opcodes_20_29.asm b/emulator/opcodes_20_29.asm index 03aba5b..b92a840 100644 --- a/emulator/opcodes_20_29.asm +++ b/emulator/opcodes_20_29.asm @@ -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) -- 2.20.1