## System/161 LAMEbus Devices

These devices have LAMEbus vendor id 1 (System/161 Development Team).

DID | DRL |
--- | --- | ---
1 | 1 | Old uniprocessor bus controller -- see LAMEbus spec
2 | 1 | Timer/clock card
3 | 2 | Fixed disk
4 | 1 | Serial console
5 | 1 | Text screen
6 | 2 | Network interface
7 | 1 | Emulator filesystem
8 | 1 | Hardware trace control
9 | 1 | Random number generator
10 | 1 | Multiprocessor bus controller -- see LAMEbus spec

#### Timer/clock card

Device id: 2
Oldest revision: 1
Current revision: 1
Registers:

> Offset | Description
> --- | ---
> 0-3 | Current time (seconds)
> 4-7 | Current time (nanoseconds)
> 8-11 | Restart-on-expiry flag
> 12-15 | True if interrupt (reading clears)
> 16-19 | Countdown time (usec) (writing starts timer)
> 20-23 | Speaker (write any value to beep)
> 24-27 | Reserved
> 28-31 | Reserved

An interrupt is generated when the countdown time reaches 0. The countdown timer is automatically restarted if the restart-on-expiry register has a nonzero value.

Reading from the speaker produces undefined behavior.

The current time registers represent UTC, where the epoch is midnight on January 1, 1970, as per the Unix `time` call. (In 2038 this will break. Oh no.)

#### Fixed disk

Device id: 3
Oldest revision: 2
Current revision: 2
Registers:

> Offset | Description
> --- | ---
> 0-3 | Number of sectors (total)
> 4-7 | Status
> 8-11 | Sector number
> 12-15 | Rotation speed (RPM)

A 512-byte sector transfer buffer is mapped at offset 32768.

The disk can do one operation at a time. To perform an operation, store the sector number into the sector register, and then write either the read-in-progress or write-in-progress values into the status register. Changing the sector number register while an operation is in progress produces undefined results.

The status register reports the present state of the disk. When it is reporting a completed operation, the IRQ line is raised. Writing zero back (or starting another operation) clears the interrupt condition. Writing zero back when an operation is in progress aborts the operation. Writing values other than zero or the values that start operations into the status register produces undefined results.

The disk is assumed to never need low-level formatting. The sector size is 512 bytes. Note that the 32-bit linear sector addressing limits disk size to 2^32 * 512 = 2^41 bytes, or 2 TB. In practice implementations may have lower limits.

The status register bits are as follows:

> Code | Description
> --- | ---
> 1 | Operation in progress
> 2 | Operation is write
> 4 | Operation completed
> 8 | Invalid sector number
> 16 | Media error

This results in the following values being meaningful in the status register:

> Code | Description
> --- | ---
> 0 | Device idle
> 1 | Read operation in progress
> 3 | Write operation in progress
> 4 | Read operation succeeded
> 6 | Write operation succeeded
> 12 | Invalid sector number on read
> 14 | Invalid sector number on write
> 20 | Media error on read
> 22 | Media error on write

Once a write operation has reported successful completion, the disk guarantees that the complete sector written will in fact make it to stable storage.

#### Serial console

Device id: 4
Oldest revision: 1
Current revision: 1
Registers:

> Offset | Description
> --- | ---
> 0-3 | Character buffer
> 4-7 | Write IRQ register
> 8-11 | Read IRQ register
> 12-15 | Reserved

This is a very, very simple console interface. Writing to the first register causes a character to be printed. Reading from it returns the last character typed.

You must wait until one write has completed before starting another one, or the output may be garbled.

The two IRQ registers have three bits each. Bit 0 (IRQEN) controls whether interrupts are generated; if bit 0 is clear, interrupts for writes or reads (respectively) will not be generated at all.

Bit 1 (CMPL) is latched on when the device completes a (write or read, respectively) operation. It can be cleared by software. Bit 2 (FORCE) is controlled only by software. The device's IRQ line is asserted if either the write or read IRQ register is in an asserting state; an IRQ register is in an asserting state if bit 0 is set and either bit 1 or bit 2 is set.

The FORCE bit can be used to perform polled I/O without causing the IRQ line to flap, which can cause problems in multiprocessor configurations. The basic approach is to set FORCE during the polled I/O if an IRQ was already pending, to keep it pending until the polled I/O is complete, and to clear IRQEN during the polled I/O if an IRQ was not already pending, to avoid triggering a spurious interrupt. See the OS/161 2.x driver (1.99.06 or higher) for example code.

NOTE: Bit 2 is only supported in System/161 versions 1.99.05 and up. The device revision is 1 regardless; if necessary the feature can be probed by writing FORCE (without IRQEN) to one of the IRQ registers and then reading the register back. If FORCE is read back, the feature is present; if 0 is read back, the feature is not available. Note that drivers written for prior versions of System/161 without the FORCE bit will continue to work as before.

The characters read from the device are 8-bit ASCII and control characters in the range 0-255. Non-ASCII keys, such as cursor keys or function keys, may appear as strings beginning with an escape sequence, or as values greater than 255. Unfortunately, in practice such characters may come from any of a number of sources and it is not practical to attempt to document their values or even map them into a single consistent set.

#### Screen console

Device id: 5
Oldest revision: 1
Current revision: 1
Registers:

> Offset | Description
> --- | ---
> 0-3 | Cursor position
> 4-7 | Display size
> 8-11 | Character input buffer
> 12-15 | Read IRQ register

Memory mapped screen interface. 32k of screen memory is mapped at offset 32768. The cursor position and display size registers are encoded with the X value in the most significant 16 bits and the Y value in the least significant 16 bits, with a zero base.

To make the cursor invisible, move it off the screen. This may or may not work depending on the display.

Reading is the same as with the serial console device. Writing is accomplished by scribbling in screen memory, one byte per character, increasing addresses moving first to the right then down across the screen.

Writing to the display size register should, in principle, work, but in practice will not.

#### Network interface

Device id: 6
Oldest revision: 2
Current revision: 2
Registers:

> Offset | Description
> --- | ---
> 0-3 | Receive interrupt register
> 4-7 | Transmit interrupt register
> 8-11 | Control register
> 12-15 | Status register

A 4k read buffer followed by a 4k write buffer is mapped at offset 32768. Packets may not exceed 4k.

Simple network interface.

Bit 0 of each interrupt register is set when a receive (or transmit) is complete. These bits may be cleared by writing 0 back. If either interrupt register is nonzero, the card's IRQ line is asserted.

The control register contains two bits: bit 0 controls promiscuous mode, and bit 1 controls packet sending. If the promiscuous mode bit is set, all packets seen will be received, even those whose destination is elsewhere. Setting bit 1 starts a packet transmit. Do not set bit 1 while a transmit is already in progress; undefined behavior may result. The rest of the control register is reserved and should be set to 0.

The lower 16 bits of the status register report the device hardware address. The rest is reserved. The status register is read-only.

To transmit, a packet should first be assembled in the send buffer. The destination and length fields in the link-level header must be set correctly. (The source and frame fields will be set by the card during transmit. However, the entire link-level header should be placed in the send buffer.) Then bit 1 of the control register should be set to 1 to start transmission. An interrupt will occur when transmission is complete.

To receive, merely copy each packet out of the receive buffer as receive interrupts occur. Further packets arriving are discarded while the receive interrupt register is nonzero, so packets may be copied without being corrupted by further input.

The link-level packet header is 8 bytes long and has the following fields (always in network byte order):

> Offset | Size | Description
> --- | --- | ---
> 0 | 2 | Framing word (0xa4b3)
> 2 | 2 | Hardware from-address
> 4 | 2 | Total packet length
> 6 | 2 | Hardware to-address

The length field should hold the entire packet length, including the space taken by the header.

The hardware address 0xffff is the broadcast address; the hardware address 0x0000 is reserved for sending keepalives to the network hub. Software should not send packets to hardware address 0x0000.

#### Emulator passthrough filesystem

Device id: 7
Oldest revision: 1
Current revision: 1
Registers:

> Offset | Description
> --- | ---
> 0-3 | Handle number to do I/O with
> 4-7 | File offset for read/readdir/write
> 8-11 | Length of I/O
> 12-15 | Operation code
> 16-19 | Result code
> 20-31 | Reserved

A 16384-byte I/O buffer is mapped at offset 32768.

The operation codes are:

> Code | Description
> --- | ---
> 1 | Open a file
> 2 | Create a file
> 3 | Create a file exclusively (O_EXCL)
> 4 | Close a file
> 5 | Read from a file
> 6 | Read one filename from a directory
> 7 | Write to a file
> 8 | Get size of a file
> 9 | Truncate a file

The result codes are:

> Code | Description
> --- | ---
> 0 | Operation in progress or device idle
> 1 | Success
> 2 | Bad handle
> 3 | Bad operation code
> 4 | Bad pathname
> 5 | Bad I/O size
> 6 | File exists
> 7 | File is a directory
> 8 | Media error
> 9 | Out of handles
> 10 | Out of disk space
> 11 | File is not a directory
> 12 | Unknown other error
> 13 | Unsupported operation

The rest of the documentation for this device is reserved, on the grounds that it is complicated, messy, unclean, and may be subject to frequent change.

#### Hardware trace controller

Device id: 8
Oldest revision: 1
Current revision: 1
Registers:

> Offset | Description
> --- | ---
> 0-3 | Trace-on register
> 4-7 | Trace-off register
> 8-11 | Debugging printout register
> 12-15 | System state dump register

This device controls `trace161`'s trace flags, allowing them to be set or cleared on the fly. To set a trace flag, write the letter of its trace option to the trace-on register; to clear it, use the trace-off register. The letters are the same as those used on the `trace161` command line. If running `sys161` rather than `trace161`, this device may exist and be used, but the trace registers have no effect.

The debugging printout register, if written to, causes `trace161` or `sys161` to print a debug message, which includes the value written to the register.

The system state dump register, if written to, will cause a complete dump of the simulation state, tagged with the value written to the register. This feature is primarily intended for testing and debugging System/161 itself.

All these registers are write-only.

#### Random number generator

Device id: 9
Oldest revision: 1
Current revision: 1
Registers:

> Offset | Description
> --- | ---
> 0-3 | Random value

Reading the register returns a 32-bit random value. In the simulated version, this value is generated by a pseudo-random generator whose seed can be specified explicitly. This allows for repeatable results, which can be helpful in some contexts.