Internals: Nga Virtual Machine
Overview
At the heart of Retro is a simple MISC (minimal instruction
set computer) processor for a dual stack architecture.
This is a very simple and straightforward system. There are
30 instructions. The memory is a linear array of signed 32
bit values. And there are two stacks: one for data and one
for return addresses.
Instruction Table
| Stacks |
| Opcode | Muri | Full Name | Data | Address |
| ------ | ---- | ------------------ | ----- | ------- |
| 0 | .. | nop | - | - |
| 1 | li | lit | -n | - |
| 2 | du | dup | n-nn | - |
| 3 | dr | drop | n- | - |
| 4 | sw | swap | xy-yx | - |
| 5 | pu | push | n- | -n |
| 6 | po | pop | -n | n- |
| 7 | ju | jump | a- | - |
| 8 | ca | call | a- | -A |
| 9 | cc | conditional call | af- | -A |
| 10 | re | return | - | A- |
| 11 | eq | equality | xy-f | - |
| 12 | ne | inequality | xy-f | - |
| 13 | lt | less than | xy-f | - |
| 14 | gt | greater than | xy-f | - |
| 15 | fe | fetch | a-n | - |
| 16 | st | store | na- | - |
| 17 | ad | addition | xy-n | - |
| 18 | su | subtraction | xy-n | - |
| 19 | mu | multiplication | xy-n | - |
| 20 | di | divide & remainder | xy-rq | - |
| 21 | an | bitwise and | xy-n | - |
| 22 | or | bitwise or | xy-n | - |
| 23 | xo | bitwise xor | xy-n | - |
| 24 | sh | shift | xy-n | - |
| 25 | zr | zero return | n-? | - |
| 26 | ha | halt | - | - |
| 27 | ie | i/o enumerate | -n | - |
| 28 | iq | i/o query | n-xy | - |
| 29 | ii | i/o invoke | ...n- | - |
Encoding
Up to four instructions can be packed into each memory cell.
As an example,
Opcode 4 Opcode 3 Opcode 2 Opcode 1
00000000:00000000:00000000:00000000
If we have a bundle of duliswst, it would look like:
st sw li du
00010000:00000100:00000001:00000010
Each li should have a value in the following cell(s). These
values will be pushed to the stack. E.g., lili.... and
1, 2:
00000000:00000000:00000001:00000001
00000000 00000000 00000000 00000001 (1)
00000000 00000000 00000000 00000010 (2)
Shifts
sh performs a bitwise arithmetic shift operation.
This takes two values:
xy
And returns a single one:
z
If y is positive, this shifts x right by y bits. If negative,
it shifts left.
Queries: Memory, Stacks
The fe instruction allows queries of some data related to
the Nga VM state. These are returned by reading from negative
addresses:
| Address | Returns |
| ------- | ---------------------- |
| -1 | Data stack depth |
| -2 | Address stack depth |
| -3 | Maximum Image Size |
| -4 | Minimum Integer Value |
| -5 | Maximum Integer Value |
I/O Devices
Nga provides three instructions for interacting with I/O devices.
These are:
ie i/o enumerate returns the number of attached devices
iq i/o query returns information about a device
ii i/o interact invokes an interaction with a device
As an example, with an implementation providing an output source,
a block storage system, and keyboard:
ie will return `3` since there are three i/o devices
0 iq will return 0 0, since the first device is a screen (0)
with a version of 0
1 iq will return 1 3, since the second device is a block
storage (3), with a version of 1
2 iq will return 0 1, since the third device is a keyboard
(1), with a version of 0
In this case, some interactions can be defined:
: c:put
i liiire..
d 0
: c:get
i liiire..
d 2
Setup the stack, push the device ID to the stack, and then use
ii to invoke the interaction.
A Retro system requires one I/O device (a generic output for a
single character). This must be the first device, and must have
a device ID of 0.
All other devices are optional and can be specified in any order.
The currently supported and reserved device identifiers are:
| ID | Device Type | Notes |
| ---- | ---------------- | -------------------------- |
| 0000 | Generic Output | Always present as device 0 |
| 0001 | Keyboard | |
| 0002 | Floating Point | |
| 0003 | Block Storage | Raw, 1024 cell blocks |
| 0004 | Filesystem | Unix-style Files |
| 0005 | Network: Gopher | Make gopher requests |
| 0006 | Network: HTTP | Make HTTP requests |
| 0007 | Network: Sockets | |
| 0008 | Syscalls: Unix | |
| 0009 | Scripting Hooks | |
| 0010 | Random Number | |
This list may be revised in the future. The only guaranteed
stable indentifier is 0000 for generic output.