I/O Devices

I/O devices on Nga are exposed via three instructions:

ie  enumerate i/o devices iq  query i/o device for class and version ii  invoke i/o interaction

All devices are registered with the VM. How this occurs is implementation dependent.

Counting Devices

Use the ie instruction to return the number of attached devices.

i ie......

Upon running, the stack will contain the number of devices. You can then query these by passing the device number to iq.

Query Devices

Use iq to query an attached device. This will return two values, a device class and a revision number.

The device class will be the top value on the stack.

Invoking a Device

You can trigger an I/O operation by passing the device handle to the ii instruction.

E.g., to display a character (ASCII code 98 in this case):

i liliii.. d 98 d 0

Be sure to pass the device handle, not the device class.

Device Class

Ultimately devices are implementation-specific, but the standard system provides or reserves the following:

 ID  | Device Class     | Notes                      | -----+------------------+----------------------------+ 0000 | Generic Output   | Always present as handle 0 | 0001 | Keyboard         |                            | 0002 | Floating Point   |                            | 0003 | Block Storage    | Raw, 1024 cell blocks      | 0004 | Filesystem       | Unix-style Files           | 0005 | Clock            |                            | 0006 |                  |                            | 0007 | Network: Sockets |                            | 0008 | Syscalls: Unix   |                            | 0009 | Scripting Hooks  |                            | 0010 | Random Number    |                            | 1000 | Image Saving     |                            |

It must be noted here that nothing forces devices to use these class identifiers, and one must take care to use an Nga implementation that provides the devices they need.

Device Revisions

Over time, the functionality a device provides may change. To allow detection of this, the query functionality provides a revision number. Your code can use this to ensure that the device provided supports the level of functionality you need.

Device Class Details

0000: Generic Output

Supported by all Nga implementations. This is required to be the first device, and is the only one guaranteed to be provided. It consumes a value from the stack, writing to to the host-specific output. (This does not need to be a screen).

0001: Keyboard

Read and return a keypress.

Consumes no data, returns a single value representing the character that was read.

No subcommands are defined.

0002: Floating Point

The current revision is 1.

It currently provides:

n:to-float  (n-_f:-n) s:to-float  (s-_f:-n) f:to-number (f:a-__-n) f:to-string (f:n-__-s) f:+     (f:ab-c) f:-     (f:ab-c) f:*     (f:ab-c) f:/     (f:ab-c) f:floor (f:ab-c) f:ceiling (f:f-f) f:sqrt  (f:f-f) f:eq?   (f:ab-c) f:-eq?  (f:ab-c) f:lt?   (f:ab-c) f:gt?   (f:ab-c) f:depth (-n) f:dup   (f:a-aa) f:drop  (f:a-) f:swap  (f:ab-ba) f:log   (f:ab-c) f:power (f:ab-c) f:sin   (f:f-f) f:cos   (f:f-f) f:tan   (f:f-f) f:asin  (f:f-f) f:acos  (f:f-f) f:atan  (f:f-f) f:push  (f:f-) f:pop   (f:-f) f:adepth  (-n)

0003: Block Storage

Reserved for future use.

0004: Filesystem

Currently at revision 0.

This implements a device providing traditional Unix-like files.

Takes a value indicating an operation, and each operation takes additional values.

| Operation | Stack | Action                           | | --------- | ----- | -------------------------------- | | 0         | sm-h  | Open a file                      | | 1         | h-    | Close a file                     | | 2         | h-c   | Read a byte from a file          | | 3         | ch-   | Write a byte to a file           | | 4         | h-n   | Return current pointer into file | | 5         | nh-   | Move pointer in a file           | | 6         | h-n   | Return the size of a file        | | 7         | s-    | Delete a file                    | | 8         | h-    | Flush pending writes             |

0010: Random Number Generator

This is currently at revision 0.

On invocation, this returns a random number.

Implementation Details (C)

On the C implementation, each I/O device has the needed support functions defined, then a query function and invocation function defined.

As an example, to add a device that has two functions, I might do:

void one() {   stack_push(100); }

void two() {   stack_push(200); }

Handler device_actions[] = {   one, two }

void io_device() {   device_actions[stack_pop()](); }

void query_device() {   stack_push(0);    /* Revision     */   stack_push(1234); /* Device Class */ }

Then add pointers to io_device to IO_deviceHandlers and query_device to IO_queryHandlers and increase the NUM_DEVICES by one.

You will then need to write a set of Retro words to use the new device.

:device:one #1 #1234 io:scan-for io:invoke ; :device:two #2 #1234 io:scan-for io:invoke ;

Rebuild the VM, adding these to image.