</style>
#+end_export
+* Overview
-* 0: nop
+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: ID-4f0dee8a-647e-4d91-a252-aaf4782b5edc
:ID: 4f0dee8a-647e-4d91-a252-aaf4782b5edc
:END:
-- *Stack Effect:* =--=
-- *Description:* No operation. The VM simply proceeds to the next
- instruction without modifying any state. This is a placeholder
- instruction that has no effect on registers or stacks.
-- *Implementation:* The opcode unconditionally triggers next instruction fetch within emulator,
- effectively executing nothing.
-- *Usage Pattern:* Typically used for padding, aligning code segments,
- or as a placeholder during code development.
+#+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
+---------------------------------------------------------------------
+
+* 1: halt (Stop Execution)
:PROPERTIES:
:CUSTOM_ID: ID-7c8841d3-2335-4ee9-b6b9-518d05354841
:ID: 7c8841d3-2335-4ee9-b6b9-518d05354841
:END:
-- *Stack Effect:* =--=
-- *Description:* Terminates the emulator process cleanly. The halt
- procedure performs the following sequence:
- 1. Restores text mode video mode (3)
- 2. Unmounts the virtual disk file
- 3. Calls =KB_restore= to restore the original keyboard interrupt handler
- 4. Exits to DOS with exit code 0
-- *Notes:* This is the ONLY way to cleanly exit the emulator.
+#+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@
+---------------------------------------------------------------------
+
+* 2: kbd@ (Keyboard Input)
:PROPERTIES:
:CUSTOM_ID: ID-820b1b90-4f4c-4ab1-b49f-9b4a52ea2528
:ID: 820b1b90-4f4c-4ab1-b49f-9b4a52ea2528
:END:
-- *Stack Effect:* =-- scancode=
-- *Description:* Reads the next keyboard scan code from the keyboard
- ring buffer and pushes it onto the data stack. If the buffer is empty,
- pushes 0. This operation is non-blocking and does not wait for user
- input.
+#+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
-- *Timing Behavior:*
- - Multiple =kbd@= calls in quick succession will return sequential
- keys
- - No blocking or timeout occurs if the buffer is empty
- - Each key read consumes the key from the buffer permanently
+---------------------------------------------------------------------
-* 3: num
+* 3: num (Push Literal Number)
:PROPERTIES:
:CUSTOM_ID: ID-8721dc8c-b237-4e9a-a509-0ded1c02329b
:ID: 8721dc8c-b237-4e9a-a509-0ded1c02329b
:END:
-- *Stack Effect:* =-- n=
-- *Description:* Pushes a 32-bit immediate integer value onto the
- data stack. The value is encoded directly in the instruction stream
- following this opcode. After pushing, the instruction pointer
- is advanced by 4 bytes to point to the next opcode.
+#+ATTR_HTML: :border 2 :rules all :frame border
+| Property | Value |
+|------------+------------------------------------------|
+| Opcode | 3 |
+| Name | num |
+| Stack | ( -- n ) |
+| Bytecode | =03= followed by 4 bytes (little-endian) |
-- *Example:*
- #+begin_example
- 42 ; Push 42 onto stack
- num
- #+end_example
+** Description
-* 4: jmp
+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: ID-a5c53b60-ffe9-4ba4-ab87-30c2ccc51a45
:ID: a5c53b60-ffe9-4ba4-ab87-30c2ccc51a45
:END:
-- *Stack Effect:* =--=
-- *Description:* Unconditionally jumps to the absolute address specified
- by the next 32-bit value in the instruction stream.
-- *Notes:* The target address is added to =xms_addr= to convert from
- virtual to physical memory address before jumping.
-- *Example:*
- #+begin_example
- 0x1000 ; Jump target address
- jmp
- #+end_example
-
-* 5: call
+
+#+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: ID-66efbd35-c2b6-4657-ba0f-ff00a3a2c312
:ID: 66efbd35-c2b6-4657-ba0f-ff00a3a2c312
:END:
-- *Stack Effect:* =--=
-- *Description:* Calls a subroutine at the specified address. Saves the
- return address (current instruction pointer + 4) onto the return stack
- before jumping.
-- *Notes:* The return address is pushed to the return stack before the
- jump occurs.
-- *Example:*
- #+begin_example
- 0x2000 ; Subroutine address
- call
- #+end_example
-
-* 6: 1+
+
+#+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: ID-76fe1c8f-756d-406e-9e8a-4ecc8f1d7369
:ID: 76fe1c8f-756d-406e-9e8a-4ecc8f1d7369
:END:
-- *Stack Effect:* =n -- n+1=
-- *Description:* Increments the top value on the data stack by 1.
-- *Notes:* Directly increments the dword at the data stack pointer.
-- *Example:*
- #+begin_example
- 5
- 1+
- #+end_example
- After execution, stack contains 6.
-
-* 7: 1-
+
+#+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: ID-523f93a3-359e-4a6d-b296-df25008db403
:ID: 523f93a3-359e-4a6d-b296-df25008db403
:END:
-- *Stack Effect:* =n -- n-1=
-- *Description:* Decrements the top value on the data stack by exactly
- one. The operation modifies the value IN PLACE at the data stack
- pointer.
-=1-= is commonly used for:
-- Iteration counters (decrementing and testing)
-- Reference counting (decrementing and checking for zero)
+#+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
-* 8: dup
+- 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: ID-2a6a449a-fc76-421c-a81c-c2024a15fc78
:ID: 2a6a449a-fc76-421c-a81c-c2024a15fc78
:END:
-- *Stack Effect:* =n -- n n=
-- *Description:* Duplicates the top value on the data stack.
-- *Notes:* Creates a copy of the top item and pushes it onto the stack.
-- *Example:*
- #+begin_example
- 42
- dup
- #+end_example
- After execution, stack contains 42 42.
-
-* 9: drop
+
+#+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: ID-4600dbeb-1833-4e7d-af7e-f6cc6c98d022
:ID: 4600dbeb-1833-4e7d-af7e-f6cc6c98d022
:END:
-- *Stack Effect:* =n --=
-- *Description:* Removes the top value from the data stack.
-- *Notes:* Simply increments the data stack pointer by 4 bytes.
-- *Example:*
- #+begin_example
- 42
- drop
- #+end_example
- After execution, stack is empty.
+
+#+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)