Fifth - virtual machine opcodes 20 – 29

Table of Contents

1. Overview

This document describes virtual machine opcodes 20 through 29. These are fundamental instructions for memory access, stack manipulation, arithmetic operations, and value comparison.

1.1. 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

2. 20: @ (Fetch)

Property Value
Opcode 20
Name @
Stack ( addr – value )
Bytecode Single byte: 14

2.1. 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.

2.2. 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

2.3. 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)

2.4. Example

Read a value from address 0x1000:

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

In Fifth source code:

0x1000 @        \ read 32-bit value from address 0x1000

2.5. 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

2.6. Common Patterns

2.6.1. Read and Use

addr @ .        \ read from address and display

2.6.2. Array Access

base index 4 * + @  \ read array[index] (32-bit elements)

3. 21: ! (Store)

Property Value
Opcode 21
Name !
Stack ( value addr – )
Bytecode Single byte: 15

3.1. 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.

3.2. 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

3.3. 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)

3.4. Example

Store value 0x12345678 to address 0x1000:

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

In Fifth source code:

0x12345678 0x1000 !  \ store 0x12345678 at address 0x1000

3.5. 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

3.6. Common Patterns

3.6.1. Store Constant

42 addr !       \ store constant 42 at addr

3.6.2. Array Assignment

value base index 4 * + !  \ array[index] = value (32-bit elements)

3.6.3. Computed Store

a b + addr !    \ store (a + b) at addr

4. 22: over (Over)

Property Value
Opcode 22
Name over
Stack ( n1 n2 – n1 n2 n1 )
Bytecode Single byte: 16

4.1. 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.

4.2. Stack Behavior

The operation preserves the original order while adding a copy:

Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
After:  [ n1 n2 n1 ]  (new n1 = TOS)

4.3. 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

4.4. Example

Duplicate the second item:

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 ]

In Fifth source code:

1 2 over        \ stack: 1 2 1

4.5. 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

4.6. Common Patterns

4.6.1. Compare Without Consuming

a b over >      \ compare a with b, keeping both on stack

4.6.2. Use Value Twice

a b over +      \ compute a + b, keeping a on stack

4.6.3. Save Address for Later Use

addr over @     \ read from addr, keeping addr for later use

5. 23: swap (Swap)

Property Value
Opcode 23
Name swap
Stack ( n1 n2 – n2 n1 )
Bytecode Single byte: 17

5.1. 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.

5.2. Stack Behavior

The operation reverses the order of the top two items:

Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
After:  [ n2 n1 ]    (n1 = TOS, n2 = second)

5.3. 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

5.4. Example

Exchange the top two values:

03 01 00 00 00  ; num 1    - stack: [ 1 ]
03 02 00 00 00  ; num 2    - stack: [ 1 2 ]
17              ; swap     - stack: [ 2 1 ]

In Fifth source code:

1 2 swap        \ stack: 2 1

5.5. 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

5.6. Common Patterns

5.6.1. Fix Subtraction Order

min max swap -  \ compute max - min

5.6.2. Correct Division Order

divisor dividend swap /  \ compute dividend / divisor

5.6.3. Exchange Variables

addr1 @ addr2 @ swap  \ read two values and exchange them
addr1 ! addr2 !       \ store them back in exchanged order

6. 24: + (Add)

Property Value
Opcode 24
Name +
Stack ( n1 n2 – n1+n2 )
Bytecode Single byte: 18

6.1. Description

Adds the top two values on the data stack, replacing them with the sum. This is a fundamental arithmetic operation for mathematical computations.

6.2. Operation

The operation performs unsigned 32-bit addition:

Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
After:  [ sum ]      (sum = n1 + n2)

6.3. When to Use

  • Basic arithmetic calculations
  • Computing sums and totals
  • Pointer arithmetic
  • Incrementing values by arbitrary amounts
  • Mathematical expressions and formulas

6.4. Example

Add two numbers:

03 05 00 00 00  ; num 5    - stack: [ 5 ]
03 03 00 00 00  ; num 3    - stack: [ 5 3 ]
18              ; +        - stack: [ 8 ]

In Fifth source code:

5 3 +           \ result: 8

6.5. 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)

6.6. Common Patterns

6.6.1. Increment by Value

value increment +  \ value = value + increment

6.6.2. Pointer Arithmetic

ptr 4 +          \ advance pointer by 4 bytes

6.6.3. Sum Multiple Values

a b + c + d +   \ compute a + b + c + d

6.7. Edge Cases

  • 0xFFFFFFFF + 1 = 0 (wrap around)
  • Any number + 0 = same number
  • Large additions may overflow

7. 25: - (Subtract)

Property Value
Opcode 25
Name -
Stack ( n1 n2 – n1-n2 )
Bytecode Single byte: 19

7.1. 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.

7.2. Operation

The operation performs unsigned 32-bit subtraction:

Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
After:  [ diff ]     (diff = n1 - n2)

7.3. When to Use

  • Computing differences between values
  • Decrementing by arbitrary amounts
  • Distance calculations
  • Mathematical expressions requiring subtraction
  • Reverse arithmetic operations

7.4. Example

Subtract two numbers:

03 0A 00 00 00  ; num 10   - stack: [ 10 ]
03 03 00 00 00  ; num 3    - stack: [ 10 3 ]
19              ; -        - stack: [ 7 ]

In Fifth source code:

10 3 -          \ result: 7 (10 - 3)

7.5. 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

7.6. Common Patterns

7.6.1. Decrement by Value

value decrement -  \ value = value - decrement

7.6.2. Distance Calculation

end start -      \ compute distance from start to end

7.6.3. Reverse Subtraction

a b swap -       \ compute b - a instead of a - b

7.7. Edge Cases

  • 0 - 1 = 0xFFFFFFFF (wrap around)
  • Any number - 0 = same number
  • n - n = 0 for any n

8. 26: * (Multiply)

Property Value
Opcode 26
Name *
Stack ( n1 n2 – n1*n2 )
Bytecode Single byte: 1A

8.1. 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.

8.2. Operation

The operation performs signed 32-bit multiplication:

Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
After:  [ product ]  (product = n1 * n2)

8.3. When to Use

  • Multiplication operations
  • Area calculations
  • Scaling values
  • Mathematical formulas
  • Computing products and multiples

8.4. Example

Multiply two numbers:

03 05 00 00 00  ; num 5    - stack: [ 5 ]
03 03 00 00 00  ; num 3    - stack: [ 5 3 ]
1A              ; *        - stack: [ 15 ]

In Fifth source code:

5 3 *           \ result: 15

8.5. 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)

8.6. Common Patterns

8.6.1. Area Calculation

width height *   \ compute area of rectangle

8.6.2. Scaling

value scale *    \ scale value by factor

8.6.3. Power of Two

value 2 *        \ multiply by 2 (equivalent to shift left by 1)

8.7. Edge Cases

  • 0 * anything = 0
  • 1 * anything = anything
  • (-1) * (-1) = 1
  • Large products may overflow (wrap around)

9. 27: / (Divide)

Property Value
Opcode 27
Name /
Stack ( n1 n2 – n1/n2 )
Bytecode Single byte: 1B

9.1. Description

Divides the second value by the top value using signed 32-bit division. Returns the quotient only (remainder is discarded).

9.2. Operation

The operation performs signed 32-bit division:

Before: [ n1 n2 ]    (n2 = divisor = TOS, n1 = dividend = second)
After:  [ quotient ] (quotient = n1 / n2)

9.3. When to Use

  • Division operations
  • Averaging calculations
  • Ratio computations
  • Mathematical formulas requiring division
  • Splitting quantities into equal parts

9.4. Example

Divide two numbers:

03 0F 00 00 00  ; num 15   - stack: [ 15 ]
03 03 00 00 00  ; num 3    - stack: [ 15 3 ]
1B              ; /        - stack: [ 5 ]

In Fifth source code:

15 3 /          \ result: 5 (15 / 3)

9.5. 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

9.6. Common Patterns

9.6.1. Average Calculation

a b + 2 /       \ compute average of a and b

9.6.2. Split into Parts

total parts /   \ divide total into equal parts

9.6.3. Correct Division Order

dividend divisor swap /  \ compute dividend / divisor

9.7. Edge Cases

  • Division by zero: CPU exception (crash)
  • Anything / 1 = anything
  • 0 / anything = 0
  • Negative division follows standard signed rules

9.8. WARNING: Division by zero will crash the emulator!


10. 28: > (Greater Than)

Property Value
Opcode 28
Name >
Stack ( n1 n2 – flag )
Bytecode Single byte: 1C

10.1. 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.

10.2. Operation

The operation performs signed 32-bit comparison:

Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
After:  [ flag ]     (flag = -1 if n1 > n2, 0 otherwise)

10.3. Truth Value Convention

  • -1 = true (all bits set, non-zero)
  • 0 = false (zero)

10.4. When to Use

  • Conditional branching and logic
  • Sorting algorithms
  • Range checking
  • Decision making in programs
  • Implementing high-level comparison words

10.5. Example

Compare two numbers:

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)

In Fifth source code:

3 5 >           \ result: 0 (false)
5 3 >           \ result: -1 (true)

10.6. 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)

10.7. Common Patterns

10.7.1. Conditional Execution

a b > if
  \ code for when a > b
then

10.7.2. Range Check

value max > abort" Value too large"

10.7.3. Sorting Logic

a b > if swap then  \ ensure smaller value is on top

10.8. Edge Cases

  • Equal values return 0 (false)
  • Negative numbers compared correctly
  • Works with full 32-bit signed range

11. 29: < (Less Than)

Property Value
Opcode 29
Name <
Stack ( n1 n2 – flag )
Bytecode Single byte: 1D

11.1. 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.

11.2. Operation

The operation performs signed 32-bit comparison:

Before: [ n1 n2 ]    (n2 = TOS, n1 = second)
After:  [ flag ]     (flag = -1 if n1 < n2, 0 otherwise)

11.3. Truth Value Convention

  • -1 = true (all bits set, non-zero)
  • 0 = false (zero)

11.4. 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

11.5. Example

Compare two numbers:

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)

In Fifth source code:

3 5 <           \ result: -1 (true)
5 3 <           \ result: 0 (false)

11.6. 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

11.7. Common Patterns

11.7.1. Conditional Execution

a b < if
  \ code for when a < b
then

11.7.2. Range Check

value min < abort" Value too small"

11.7.3. Sorting Logic

a b < if swap then  \ ensure larger value is on top

11.7.4. Equality Check

a b < if
  \ a < b
else
  a b > if
    \ a > b
  else
    \ a = b
  then
then

11.8. 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

11.9. 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

Created: 2026-02-24 Tue 23:35

Validate