2019-03-15 13:06:56 +01:00
|
|
|
# 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.
|
|
|
|
|
2019-05-23 19:49:23 +02:00
|
|
|
## Instruction Table
|
2019-03-15 13:06:56 +01:00
|
|
|
|
2019-03-21 21:34:05 +01:00
|
|
|
| Opcode | Muri | Full Name | Data Stack | Address Stack |
|
|
|
|
| ------ | ---- | ------------------ | ---------- | ------------- |
|
|
|
|
| 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 | en | end | - | - |
|
|
|
|
| 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,
|
|
|
|
|
2019-09-23 22:02:11 +02:00
|
|
|
Opcode 4 Opcode 3 Opcode 2 Opcode 1
|
2019-03-21 21:34:05 +01:00
|
|
|
00000000:00000000:00000000:00000000
|
|
|
|
|
2019-09-23 22:02:11 +02:00
|
|
|
If we have a bundle of `duliswst`, it would look like:
|
2019-03-21 21:34:05 +01:00
|
|
|
|
2019-09-23 22:02:11 +02:00
|
|
|
st sw li du
|
|
|
|
00010000:00000100:00000001:00000010
|
2019-03-21 21:34:05 +01:00
|
|
|
|
|
|
|
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:
|
|
|
|
|
2019-09-23 22:02:11 +02:00
|
|
|
00000000:00000000:00000001:00000001
|
2019-03-21 21:34:05 +01:00
|
|
|
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:
|
|
|
|
|
2019-09-23 22:02:11 +02:00
|
|
|
| Address | Returns |
|
|
|
|
| ------- | ---------------------- |
|
|
|
|
| -1 | Data stack depth |
|
|
|
|
| -2 | Address stack depth |
|
|
|
|
| -3 | Maximum Image Size |
|
|
|
|
| -4 | Minimum Integer Value |
|
|
|
|
| -5 | Maximum Integer Value |
|
2019-03-21 21:34:05 +01:00
|
|
|
|
|
|
|
## 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.
|
|
|
|
|
|
|
|
## Trivia
|
2019-03-15 19:35:34 +01:00
|
|
|
|
|
|
|
There are 810,000 possible combinations of instructions. Only
|
|
|
|
73 are used in the implementation of RETRO.
|