Skip to content

5 ‐ IO

QualityCroissant edited this page Apr 13, 2026 · 9 revisions

I/O can behave differently for separate Memory Channel values. This page seeks to provide a guide on how they each behave.

Main Memory and the Callstack

Operations to Main Memory and the Callstack are regular and predictable; each handle manual operations the same way: for any value of MAR, if a ld is performed, the data at the address in MAR overwrites MDR; if a st is performed, the data at the address in MAR is overwritten with the contents of MDR.

Secondary Storage

Operations to secondary storage work on the basis of controlling the position of the file-read and the data that is read as separate things:-

Memory Channel Instruction Operation Performed
inp ld The position of the file-pointer is placed in MDR (it is 0 at the start of the disk)
st The position of the file-pointer is set to the contents of MDR (0 is the start of the disk)
out ld The byte on the disk at the file-pointer overwrites MDR, and then the file-pointer is incremented by 1
st The lowest byte in MDR overwrites the byte on the disk at the file-pointer, and then the file-pointer is incremented by 1

Screen Buffer

As of v0.4-alpha, graphical operations are supported via the Screen Buffer. Because of the complexity of graphics operations, the way these are handled is implemented in a fairly different way to the other I/O operations.

Each operation involving the Screen Buffer requires a st operation in the inp or out file (either can be used), at address 2 in MAR. The value in MDR must not the instruction itself, but rather the memory address of the instruction in MEM. This is because each instruction takes up a variable number of cells.

The structure of an instruction passed to the Graphics API is always the instruction itself, followed by the parameters it expects. Some instructions return values. They do this by overwriting the memory in the cells after the instruction opcode. This means these cells must be occupied before executing these instructions.

Note: SWAP_BUFFERS can be called to ensure that the window is visible, even if SET_WINDOW_VISIBILITY has already been called.

Each instruction supported by the Graphics API can be seen in the table below:-

Instruction Parameters Name Description
0 width, height SET_WINDOW_DIMENSIONS Set the width and height of the window, in pixels.
1 width, height, depth SET_WORKING_DIMENSIONS Set the maximum values for width, height, and depth of the world, as referenced by the program.
2 length, title SET_WINDOW_TITLE Set the title of the window to a new title, of length characters.
3 visible SET_WINDOW_VISIBILITY Set whether or not the window is visible on the screen. If visible is non-zero, the window will be visible.
4 fullscreen SET_WINDOW_FULLSCREEN Set whether or not the window is fullscreen (using the primary monitor). If fullscreen is non-zero, the window will be fullscreen.
5 vsync SET_WINDOW_VSYNC Set whether or not the window uses vsync. If vsync is zero, vsync is disabled; otherwise, the swap interval is set to vsync. This should be 1 for standard vsync.
6 r, g, b, a, x0, y0, z0, x1, y1, z1, x2, y2, z2 DRAW_TRIANGLE Draw a triangle of colour (r, g, b, a) (0-255), with vertexes at (x0, y0, z0), (x1, y1, z1), (x2, y2, z2).
7 SWAP_BUFFERS Swap the buffers (draw the _Screen Buffer_ to the screen).
8 projection SET_PROJECTION Set the projection used to draw. If _projection_ is 0, orthographic projection is used; otherwise, perspective projection is used.
9 CLEAR_BUFFERS Clears the depth and colour buffers for the screen.
10 closure GET_WINDOW_SHOULD_CLOSE Sets _closure_ to non-zero if the window should close (i.e. if the user has pressed 'close').
11 width, height GET_WINDOW_DIMENSIONS Set _width_ and _height_ to the current dimensions of the window in pixels.

The coördinate system used to draw to the screen references (0, 0, -1) as the bottom-left (negative numbers are in 2's-complement form). Positive x is rightwards, positive y is upwards, and negative z is forwards (away from the camera). anything greater than -1 is not visible on the screen.

The default width, height, and depth of the working-dimensions (the maximum values of x, y, and z), are 1280, 720, and 1280 respectively. The default projection mode is orthographic. The default title for the window is "FVMR Screen". VSYNC is off by default.

The buffers are not cleared when the program starts, and the window is hidden in windowed-mode (not fullscreen) by default. Executing the fi instruction will close the window as the VM shuts down.

Keyboard

As of v0.8-beta, input from the keyboard can be detected and read, when the window for the screen buffer is made visible and selected by the user. Keypresses are stored in a buffer (the Keypress Queue) from which they can be read. The handling of keyboard operations is done in a similar manor to that of Secondary Storage operations:-

Memory Channel Instruction Operation Performed
inp ld The next keypress event in the Keypress Queue is dequeued and placed in the MDR in the format
[2 bytes 0s][1 byte action][1 byte modifiers][4 bytes GLFW key code].
If there are no keypresses in the Keypress Queue, the MDR is set to 0.
st The next keypress event in the Keypress Queue is dequeued and placed in the MDR in the format
[2 bytes 0s][1 byte action][1 byte modifiers][4 bytes plaftorm-specific scancode].
If there are no keypresses in the Keypress Queue, the MDR is set to 0.
out ld The number of keypresses in the Keypress Queue is placed in the MDR
st The value stored in the MDR is interpreted as a GLFW key code, and translated into its corresponding platform-specific scancode. This value then overwrites the MDR.

Different platforms will send different scancodes for the same keys, though they will remain consistent for the individual platforms.

GLFW key codes are numbers assigned to keyboard-keys which aim to be the same for all platforms. A list of them can be found here.

The modifiers and action that are a part of each keypress are also from GLFW. The bits for the byte for modifiers will have a value of 1 for every modifier that is active for the keypress and 0 for every modifier that isn't. Which bits mean what modifiers can be found here. The action byte can have one of the following values, depending on what the keypress event was:-

Value Meaning
0 The key was released
1 The key was pressed
2 The key was held down until it repeated (should only be used for inputting text)
4294967295 (-1 or [ffff'ffff]x) Key unknown

Clone this wiki locally