245 lines
15 KiB
HTML
245 lines
15 KiB
HTML
|
<?xml version="1.0" encoding="utf-8"?>
|
||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||
|
<html xmlns="http://www.w3.org/1999/xhtml"><head>
|
||
|
<title>.</title>
|
||
|
<style type="text/css">
|
||
|
|
||
|
* { color: #000; background: #fff; max-width: 700px; }
|
||
|
tt, pre { background: #dedede; color: #111; font-family: monospace;
|
||
|
white-space: pre; display: block; width: 100%; }
|
||
|
.indentedcode { margin-left: 2em; margin-right: 2em; }
|
||
|
.codeblock {
|
||
|
background: #dedede; color: #111; font-family: monospace;
|
||
|
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||
|
padding: 7px;
|
||
|
display: block;
|
||
|
}
|
||
|
|
||
|
.indentedlist { margin-left: 2em; color: #000; }
|
||
|
|
||
|
span { white-space: pre; }
|
||
|
.text { color: #000; white-space: pre; background: #dedede; }
|
||
|
.colon { color: #000; background: #dedede; }
|
||
|
.note { color: #000; background: #dedede; }
|
||
|
.str { color: #000; text-decoration: underline; background: #dedede; }
|
||
|
.num { color: #000; background: #dedede; font-weight: bold; font-style: italic; }
|
||
|
.fnum { color: #000; font-weight: bold; background: #dedede; }
|
||
|
.ptr { color: #000; font-weight: bold; background: #dedede; }
|
||
|
.fetch { color: #000; font-style: italic; background: #dedede; }
|
||
|
.store { color: #000; font-style: italic; background: #dedede; }
|
||
|
.char { color: #000; background: #dedede; }
|
||
|
.inst { color: #000; background: #dedede; }
|
||
|
.defer { color: #000; background: #dedede; }
|
||
|
.imm { color: #000; font-weight: bold; background: #dedede; }
|
||
|
.prim { color: #000; font-weight: bolder; background: #dedede; }
|
||
|
|
||
|
.tt { white-space: pre; font-family: monospace; background: #dedede; }
|
||
|
|
||
|
.h1, .h2, .h3, .h4 { white-space: normal; }
|
||
|
.h1 { font-size: 125%; }
|
||
|
.h2 { font-size: 120%; }
|
||
|
.h3 { font-size: 115%; }
|
||
|
.h4 { font-size: 110%; }
|
||
|
.hr { display: block; height: 2px; background: #000000; }
|
||
|
</style>
|
||
|
</head><body>
|
||
|
<p><span class="h1">I/O Devices</span>
|
||
|
<br/><br/>
|
||
|
I/O devices on Nga are exposed via three instructions:
|
||
|
<br/><br/>
|
||
|
<tt class='indentedcode'>ie enumerate i/o devices</tt>
|
||
|
<tt class='indentedcode'>iq query i/o device</tt>
|
||
|
<tt class='indentedcode'>ii invoke i/o interaction</tt>
|
||
|
<br/><br/>
|
||
|
All devices are registered with the VM. How this occurs is
|
||
|
implementation dependent.
|
||
|
<br/><br/>
|
||
|
<span class="h2">Counting Devices</span>
|
||
|
<br/><br/>
|
||
|
Use the <span class="tt">ie</span> instruction to return the number of attached devices.
|
||
|
<br/><br/>
|
||
|
<tt class='indentedcode'>i ie......</tt>
|
||
|
<br/><br/>
|
||
|
Upon running, the stack will contain the number of devices. You
|
||
|
can then query these by passing the device number to <span class="tt">iq</span>.
|
||
|
<br/><br/>
|
||
|
<span class="h2">Query Devices</span>
|
||
|
<br/><br/>
|
||
|
Use <span class="tt">iq</span> to query an attached device. This will return two values,
|
||
|
a device identifer and a revision number.
|
||
|
<br/><br/>
|
||
|
The device identifier will be the top value on the stack.
|
||
|
<br/><br/>
|
||
|
<span class="h2">Invoking a Device</span>
|
||
|
<br/><br/>
|
||
|
You can trigger an I/O operation by passing the device number to
|
||
|
the <span class="tt">ii</span> instruction.
|
||
|
<br/><br/>
|
||
|
E.g., to display a character (ASCII code 98 in this case):
|
||
|
<br/><br/>
|
||
|
<tt class='indentedcode'>i liliii..</tt>
|
||
|
<tt class='indentedcode'>d 98</tt>
|
||
|
<tt class='indentedcode'>d 0</tt>
|
||
|
<br/><br/>
|
||
|
Be sure to pass the device number, not the device identifier.
|
||
|
<br/><br/>
|
||
|
<span class="h2">Device Identifiers</span>
|
||
|
<br/><br/>
|
||
|
Ultimately device identifiers are implementation-specific, but the
|
||
|
most common system (Nga on Unix) provides or reserves the following:
|
||
|
<br/><br/>
|
||
|
<tt class='indentedcode'> ID | Device Type | Notes |</tt>
|
||
|
<tt class='indentedcode'>-----+------------------+----------------------------+</tt>
|
||
|
<tt class='indentedcode'>0000 | Generic Output | Always present as device 0 |</tt>
|
||
|
<tt class='indentedcode'>0001 | Keyboard | |</tt>
|
||
|
<tt class='indentedcode'>0002 | Floating Point | |</tt>
|
||
|
<tt class='indentedcode'>0003 | Block Storage | Raw, 1024 cell blocks |</tt>
|
||
|
<tt class='indentedcode'>0004 | Filesystem | Unix-style Files |</tt>
|
||
|
<tt class='indentedcode'>0005 | Clock | |</tt>
|
||
|
<tt class='indentedcode'>0006 | | |</tt>
|
||
|
<tt class='indentedcode'>0007 | Network: Sockets | |</tt>
|
||
|
<tt class='indentedcode'>0008 | Syscalls: Unix | |</tt>
|
||
|
<tt class='indentedcode'>0009 | Scripting Hooks | |</tt>
|
||
|
<tt class='indentedcode'>0010 | Random Number | |</tt>
|
||
|
<tt class='indentedcode'>1000 | Image Saving | |</tt>
|
||
|
<br/><br/>
|
||
|
It must be noted here that nothing forces devices to use these
|
||
|
identifiers, and one must take care to use an Nga implementation
|
||
|
that provides the devices they need.
|
||
|
<br/><br/>
|
||
|
<span class="h2">Device Revisions</span>
|
||
|
<br/><br/>
|
||
|
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.
|
||
|
<br/><br/>
|
||
|
<span class="h2">Nga/Retro-Unix Device Details</span>
|
||
|
<br/><br/>
|
||
|
<span class="h3">0000: Generic Output</span>
|
||
|
<br/><br/>
|
||
|
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).
|
||
|
<br/><br/>
|
||
|
<span class="h3">0001: Keyboard</span>
|
||
|
<br/><br/>
|
||
|
Read and return a keypress.
|
||
|
<br/><br/>
|
||
|
Consumes no data, returns a single value representing the
|
||
|
character that was read.
|
||
|
<br/><br/>
|
||
|
No subcommands are defined.
|
||
|
<br/><br/>
|
||
|
<span class="h3">0002: Floating Point</span>
|
||
|
<br/><br/>
|
||
|
The current revision is 1.
|
||
|
<br/><br/>
|
||
|
It currently provides:
|
||
|
<br/><br/>
|
||
|
<tt class='indentedcode'>n:to-float (n-_f:-n)</tt>
|
||
|
<tt class='indentedcode'>s:to-float (s-_f:-n)</tt>
|
||
|
<tt class='indentedcode'>f:to-number (f:a-__-n)</tt>
|
||
|
<tt class='indentedcode'>f:to-string (f:n-__-s)</tt>
|
||
|
<tt class='indentedcode'>f:+ (f:ab-c)</tt>
|
||
|
<tt class='indentedcode'>f:- (f:ab-c)</tt>
|
||
|
<tt class='indentedcode'>f:* (f:ab-c)</tt>
|
||
|
<tt class='indentedcode'>f:/ (f:ab-c)</tt>
|
||
|
<tt class='indentedcode'>f:floor (f:ab-c)</tt>
|
||
|
<tt class='indentedcode'>f:ceiling (f:f-f)</tt>
|
||
|
<tt class='indentedcode'>f:sqrt (f:f-f)</tt>
|
||
|
<tt class='indentedcode'>f:eq? (f:ab-c)</tt>
|
||
|
<tt class='indentedcode'>f:-eq? (f:ab-c)</tt>
|
||
|
<tt class='indentedcode'>f:lt? (f:ab-c)</tt>
|
||
|
<tt class='indentedcode'>f:gt? (f:ab-c)</tt>
|
||
|
<tt class='indentedcode'>f:depth (-n)</tt>
|
||
|
<tt class='indentedcode'>f:dup (f:a-aa)</tt>
|
||
|
<tt class='indentedcode'>f:drop (f:a-)</tt>
|
||
|
<tt class='indentedcode'>f:swap (f:ab-ba)</tt>
|
||
|
<tt class='indentedcode'>f:log (f:ab-c)</tt>
|
||
|
<tt class='indentedcode'>f:power (f:ab-c)</tt>
|
||
|
<tt class='indentedcode'>f:sin (f:f-f)</tt>
|
||
|
<tt class='indentedcode'>f:cos (f:f-f)</tt>
|
||
|
<tt class='indentedcode'>f:tan (f:f-f)</tt>
|
||
|
<tt class='indentedcode'>f:asin (f:f-f)</tt>
|
||
|
<tt class='indentedcode'>f:acos (f:f-f)</tt>
|
||
|
<tt class='indentedcode'>f:atan (f:f-f)</tt>
|
||
|
<tt class='indentedcode'>f:push (f:f-)</tt>
|
||
|
<tt class='indentedcode'>f:pop (f:-f)</tt>
|
||
|
<tt class='indentedcode'>f:adepth (-n)</tt>
|
||
|
<br/><br/>
|
||
|
<span class="h3">0003: Block Storage</span>
|
||
|
<br/><br/>
|
||
|
Reserved for future use.
|
||
|
<br/><br/>
|
||
|
<span class="h3">0004: Filesystem</span>
|
||
|
<br/><br/>
|
||
|
Currently at revision 0.
|
||
|
<br/><br/>
|
||
|
This implements a device providing traditional Unix-like files.
|
||
|
<br/><br/>
|
||
|
Takes a value indicating an operation, and each operation takes
|
||
|
additional values.
|
||
|
<br/><br/>
|
||
|
<tt class='indentedcode'>| Operation | Stack | Action |</tt>
|
||
|
<tt class='indentedcode'>| --------- | ----- | -------------------------------- |</tt>
|
||
|
<tt class='indentedcode'>| 0 | sm-h | Open a file |</tt>
|
||
|
<tt class='indentedcode'>| 1 | h- | Close a file |</tt>
|
||
|
<tt class='indentedcode'>| 2 | h-c | Read a byte from a file |</tt>
|
||
|
<tt class='indentedcode'>| 3 | ch- | Write a byte to a file |</tt>
|
||
|
<tt class='indentedcode'>| 4 | h-n | Return current pointer into file |</tt>
|
||
|
<tt class='indentedcode'>| 5 | nh- | Move pointer in a file |</tt>
|
||
|
<tt class='indentedcode'>| 6 | h-n | Return the size of a file |</tt>
|
||
|
<tt class='indentedcode'>| 7 | s- | Delete a file |</tt>
|
||
|
<tt class='indentedcode'>| 8 | h- | Flush pending writes |</tt>
|
||
|
<br/><br/>
|
||
|
<span class="h3">0010: Random Number Generator</span>
|
||
|
<br/><br/>
|
||
|
This is currently at revision 0.
|
||
|
<br/><br/>
|
||
|
On invocation, this returns a random number.
|
||
|
<br/><br/>
|
||
|
<span class="h2">Implementation Details (C)</span>
|
||
|
<br/><br/>
|
||
|
On the C implementation, each I/O device has the needed support
|
||
|
functions defined, then a query function and invocation function
|
||
|
defined.
|
||
|
<br/><br/>
|
||
|
As an example, to add a device that has two functions, I might do:
|
||
|
<br/><br/>
|
||
|
<tt class='indentedcode'>void one() {</tt>
|
||
|
<tt class='indentedcode'> stack_push(100);</tt>
|
||
|
<tt class='indentedcode'>}</tt>
|
||
|
<br/><br/>
|
||
|
<tt class='indentedcode'>void two() {</tt>
|
||
|
<tt class='indentedcode'> stack_push(200);</tt>
|
||
|
<tt class='indentedcode'>}</tt>
|
||
|
<br/><br/>
|
||
|
<tt class='indentedcode'>Handler device_actions[] = {</tt>
|
||
|
<tt class='indentedcode'> one, two</tt>
|
||
|
<tt class='indentedcode'>}</tt>
|
||
|
<br/><br/>
|
||
|
<tt class='indentedcode'>void io_device() {</tt>
|
||
|
<tt class='indentedcode'> device_actions[stack_pop()]();</tt>
|
||
|
<tt class='indentedcode'>}</tt>
|
||
|
<br/><br/>
|
||
|
<tt class='indentedcode'>void query_device() {</tt>
|
||
|
<tt class='indentedcode'> stack_push(0); /* Revision */</tt>
|
||
|
<tt class='indentedcode'> stack_push(1234); /* Device ID */</tt>
|
||
|
<tt class='indentedcode'>}</tt>
|
||
|
<br/><br/>
|
||
|
Then add pointers to <span class="tt">io_device</span> to <span class="tt">IO_deviceHandlers</span> and
|
||
|
<span class="tt">query_device</span> to <span class="tt">IO_queryHandlers</span> and increase the <span class="tt">NUM_DEVICES</span>
|
||
|
by one.
|
||
|
<br/><br/>
|
||
|
You will then need to write a set of Retro words to use the new
|
||
|
device.
|
||
|
<br/><br/>
|
||
|
<tt class='indentedcode'>:device:one #1 #1234 io:scan-for io:invoke ;</tt>
|
||
|
<tt class='indentedcode'>:device:two #2 #1234 io:scan-for io:invoke ;</tt>
|
||
|
<br/><br/>
|
||
|
Rebuild the VM, adding these to image.
|
||
|
</p>
|
||
|
</body></html>
|