From 4e6f7c0e976b57ce83a9e12e5ab01b479fe2b614 Mon Sep 17 00:00:00 2001 From: Svjatoslav Agejenko Date: Mon, 23 Feb 2026 01:56:24 +0200 Subject: [PATCH] Expand opcode documentation (0-9): refined descriptions, clarified stack effects, added examples, and improved readability. --- doc/opcodes_00_09.org | 667 +++++++++++++++++++++++++++++++++------- doc/virtual machine.org | 23 +- 2 files changed, 574 insertions(+), 116 deletions(-) diff --git a/doc/opcodes_00_09.org b/doc/opcodes_00_09.org index 2713a94..14ca971 100644 --- a/doc/opcodes_00_09.org +++ b/doc/opcodes_00_09.org @@ -25,161 +25,618 @@ #+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) diff --git a/doc/virtual machine.org b/doc/virtual machine.org index d1e3633..4a73569 100644 --- a/doc/virtual machine.org +++ b/doc/virtual machine.org @@ -112,16 +112,16 @@ in FIFTH programming language): | # | Name | Stack effect | Description | Notes | |----+----------+-----------------------+----------------------------------------------------------+---------------------------------------------------------------------| -| 0 | [[id:4f0dee8a-647e-4d91-a252-aaf4782b5edc][nop]] | -- | No operation | | -| 1 | [[id:7c8841d3-2335-4ee9-b6b9-518d05354841][halt]] | -- | Halt CPU (exit emulator) | | -| 2 | [[id:820b1b90-4f4c-4ab1-b49f-9b4a52ea2528][kbd@]] | -- scancode | Read scancode of pressed or released key | | -| 3 | [[id:8721dc8c-b237-4e9a-a509-0ded1c02329b][num]] | -- n | Push immediate 32-bit number onto data stack | | -| 4 | [[id:a5c53b60-ffe9-4ba4-ab87-30c2ccc51a45][jmp]] | -- | Unconditional jump to specified address | | -| 5 | [[id:66efbd35-c2b6-4657-ba0f-ff00a3a2c312][call]] | | Call subroutine (save return address on return stack) | | -| 6 | [[id:76fe1c8f-756d-406e-9e8a-4ecc8f1d7369][1+]] | n -- n+1 | Increment top of data stack by 1 | | -| 7 | [[id:523f93a3-359e-4a6d-b296-df25008db403][1-]] | n -- n-1 | Decrement top of data stack by 1 | | -| 8 | [[id:2a6a449a-fc76-421c-a81c-c2024a15fc78][dup]] | n -- n n | Duplicate top of data stack | | -| 9 | [[id:4600dbeb-1833-4e7d-af7e-f6cc6c98d022][drop]] | n -- | Drop top of data stack | | +| 0 | [[id:4f0dee8a-647e-4d91-a252-aaf4782b5edc][nop]] | -- | No operation; execution continues to next instruction | Used for padding or placeholder | +| 1 | [[id:7c8841d3-2335-4ee9-b6b9-518d05354841][halt]] | -- | Stop execution and exit emulator | Cleanly terminates the Fifth environment | +| 2 | [[id:820b1b90-4f4c-4ab1-b49f-9b4a52ea2528][kbd@]] | -- scancode | Read keyboard scancode; returns 0 if no key pending | Make codes for press, break codes (value+128) for release | +| 3 | [[id:8721dc8c-b237-4e9a-a509-0ded1c02329b][num]] | -- n | Push 32-bit literal from instruction stream | Followed by 4 bytes (little-endian) | +| 4 | [[id:a5c53b60-ffe9-4ba4-ab87-30c2ccc51a45][jmp]] | -- | Unconditional jump to address from instruction stream | Followed by 4-byte target address | +| 5 | [[id:66efbd35-c2b6-4657-ba0f-ff00a3a2c312][call]] | -- | Call subroutine; push return address on return stack | Use ret (opcode 11) to return; follow with 4-byte target address | +| 6 | [[id:76fe1c8f-756d-406e-9e8a-4ecc8f1d7369][1+]] | n -- n+1 | Increment top of data stack by 1 | Efficient single-byte operation for counters and pointers | +| 7 | [[id:523f93a3-359e-4a6d-b296-df25008db403][1-]] | n -- n-1 | Decrement top of data stack by 1 | Efficient single-byte operation for countdown loops | +| 8 | [[id:2a6a449a-fc76-421c-a81c-c2024a15fc78][dup]] | n -- n n | Duplicate top of data stack | Preserve values before consuming operations | +| 9 | [[id:4600dbeb-1833-4e7d-af7e-f6cc6c98d022][drop]] | n -- | Remove and discard top of data stack | Clean up stack after operations | | 10 | [[id:d6f834b6-9a37-4414-91b3-62b3e1d920c1][if]] | n -- | Jump to address if top of stack is zero | | | 11 | [[id:6e683977-a985-4bb8-9d2c-c860d30e1df6][ret]] | | Return from subroutine (pop return address) | | | 12 | [[id:a2ce44f7-b661-44e0-909b-644ff52aa38e][c@]] | addr -- byte | Read byte from memory at specified address | | @@ -159,6 +159,7 @@ in FIFTH programming language): | 44 | [[id:fecb9438-d9d2-4224-a017-cc87dba9209e][cfill]] | byte addr len -- | Fill memory with specified byte value | | | 45 | [[id:ab45247c-44c3-464d-9e2a-337f483b4616][tvidput]] | addr1 addr2 x y -- | Blit image1 to image2 at (x,y) with transparency support | | | 46 | [[id:77fa76d3-9cd0-49c1-882c-f30383347352][depth]] | -- depth | Push current data stack depth | | -| 47 | [[id:4bb479cf-aae0-4128-9868-f016c286a162][charput]] | fg bg src dest x y -- | Draw character from source buffer to destination buffer | | +| 47 | [[id:4bb479cf-aae0-4128-9868-f016c286a162][charput]] | fg bg src dest x y -- | Draw character from source buffer to destination buffer | + -- 2.20.1