## Linear Always-Mapped Extents

LAMEbus is a simple no-fuss system bus architecture. There are 32 slots, each of which is associated with a fixed-size addressable region. These regions are mapped in order into the system physical memory space. There is no DMA; data transfers are done by the CPU using transfer buffers appearing within a device's address space. (However, DMA may be added in a future version.)

### Structure of the Bus Region

There are 32 slots, and each slot has a 64K address space. Thus, the whole bus region takes 64K*32 = 2MB. The base physical address of this region is called LAMEBASE; because different processor types impose different restrictions on the organization of physical memory, its value depends on the processor architecture.

The bus controller always appears in slot 31; its 64K address space is divided in two. The lower half is divided into 32 1K config regions, one per slot. The upper half is divided into 32 1K control regions, one per CPU. In addition to configuration, the config region of the bus controller's config region contains the bus controller's own registers, described below.

### Addressing the Bus

Thus, the physical address for slot `N`, holding the registers and other material for the device placed the slot, is given by

    	LAMEBASE + (0x10000*N)

The physical address for slot `N`'s config region is given by

    	LAMEBASE + (0x10000*31) + (0x400*N)

The physical address for CPU `N`'s control region is given by

    	LAMEBASE + (0x10000*31) + 0x8000 + (0x400*N)

Virtual addresses will of course vary depending on processor architecture and MMU state.

### Physical Memory Layout

MIPS.

On 32-bit MIPS processors, the first 512 megabytes of the physical address space is hardwired to appear at kernel virtual addresses 0x8000 0000 (cached) and 0xA000 0000 (uncached). Also, several virtual addresses starting at 0xbfc0 0000 are hardwired into the architecture and must point into the firmware ROM.

For this reason, LAMEBASE is set to 0x1fe0 0000, so the LAMEbus mapping area appears at the top end of these regions. The physical memory map is as follows:

Address | Region
--- | ---
`0xffff ffff` | Upper physical RAM (above 508 MB)
`0x2000 0000`
`0x1fff ffff` | LAMEbus devices
`0x1fe0 0000`
`0x1fdf ffff` | Boot ROM area
`0x1fc0 0000`
`0x1fbf ffff` | First 508 MB of physical RAM
`0x0000 0000`

Virtual memory map:

Address | MIPS Segment | Region | MIPS hardwired address
--- | --- | --- | ---
`0xffff ffff` | kseg2 | TLB-mappable kernel space |
`0xc0000000` |
`0xbfffffff` | kseg1 | LAMEbus mapping area |
`0xbfe00000` |
`0xbfdfffff` | Boot ROM area (uncached) |
`0xbfc00180` | Exception address if "boot" flag is set
`0xbfc00100` | UTLB exception address if "boot" flag is set
`0xbfc00000` | Execution begins here after processor reset.
`0xbfbfffff` | First 508 MB of RAM (uncached) |
`0xa0000000` |
`0x9fffffff` | kseg0 | Cached LAMEbus (not useful) |
`0x9fe00000` |
`0x9fdfffff` | Boot ROM area (cached) |
`0x9fc00000` |
`0x9fbfffff` | First 508 MB of RAM (cached) |
`0x80000080` | Exception address if "boot" flag not set.
`0x80000000` | UTLB exception address if "boot" flag not set.
`0x7fffffff` | kuseg | User space |
`0x00000000` |

Because the MIPS has a 32-bit memory bus, all registers (all LAMEbus device registers are 32-bit) can be read or written atomically in a single instruction.

Ant-32.

The experimental Ant-32 build of System/161 is deprecated.

i386.

LAMEbus for i386 has not been implemented, and probably will not be; however, if it is, the projected layout is with LAMEBASE at 0xffe0 0000, a boot ROM area below that, and all the rest of the physical address space potentially used by RAM:

Address | Region
--- | ---
`0xffff ffff` | LAMEbus devices
`0xffe0 0000`
`0xffdf ffff` | Boot ROM area
`0xffc0 0000`
`0xffbf ffff` | Physical RAM (up to 4092 MB)
`0x0000 0000`
|

Note that this is not compatible with the traditional ISA-derived mess found on stock i386-based machines.

Also note that on i386 the virtual memory map can be arranged however desired.

### Bus Configuration

Because the bus is always mapped, and interrupt lines are always connected, no explicit configuration of system resources is required. However, it is still necessary for system software to inspect the bus to find what devices are connected, and to perform certain control operations. For that reason, as mentioned above, a 1K config region is associated with each slot. Each such config region contains the following registers:

Name | Offset | Description
--- | --- | ---
VID | `0x00-0x03` | Vendor ID
DID | `0x04-0x07` | Device ID
DRL | `0x08-0x0b` | Device Revision Level
| `0x0c-0x3ff` | Reserved
|

The Vendor ID, Device ID, and Device Revision Level in combination uniquely identify the hardware device present in the slot.

Vendor IDs defined are as follows:

Value | Organization
--- | ---
`0` | No card present
`1` | System/161 Development Team
`0xffff ffff` | Private experimental or research use
Other | Reserved
|

If no card is present in a given slot, the other config registers may contain invalid values, and references to that slot's mapping area will (normally) cause memory bus errors.

The Device ID and Device Revision Level values are defined by the vendors. The System/161 Development Team devices are documented in an accompanying document.

### Bus Controller

Offsets 512-1023 (0x200-0x3ff) of the bus controller's own configuration region are mapped to the bus controller's own registers.

The System/161 2.x multiprocessor bus controller (VID 1, DID 10) has the following registers:

Name | Offset | Description
--- | --- | ---
RAMSZ | 0x200-0x203 | Size of physical RAM in bytes
IRQS | 0x204-0x207 | Mask of slots presently interrupting
PWR | 0x208-0x20b | Power enable register
IRQE | 0x20c-0x20f | Global interrupt enable register
CPUS | 0x210-0x213 | Mask of CPUs present in the system
CPUE | 0x214-0x217 | Mask of CPUs powered up and executing
SELF | 0x218-0x21b | Bit corresponding to reading CPU
| 0x21c-0x3ff | Reserved
|

RAMSZ reports the system main board configuration. Writes are rejected. Where the physical RAM appears in the physical address space, and whether it is contiguous (and if not, where the gaps are) depends on the processor type.

The IRQS register holds a 1 for each slot that is presently asserting its IRQ line. Writes to IRQS are rejected; interrupts should be cleared on the devices generating them. Bit 0 represents slot 0, etc. Thus bit 31 is the bus controller's bit.

The PWR register holds a 1 for each slot that is currently powered. Writing to this register powers devices on and off. Powering off the system mainboard switches the system off. Note: if the mainboard is powered off, all other slots should be powered off as well. At startup, slots with devices in them are powered; others are unpowered.

The IRQE register holds a 1 for each slot that is allowed to generate interrupts. Slots whose bit in IRQE is zero may assert their IRQ line (and thus appear in IRQS) but will not generate a processor interrupt by doing so.

The CPUS register holds a 1 for each CPU that is present on the system board. These are not necessarily contiguous in the word; in a two-CPU configuration the CPUs present may be e.g. 0 and 16, leading to a value of 0x0001 0001 in this register.

The CPUE register holds a 1 for each CPU that is enabled, that is, powered up and executing. Upon board reset only one CPU (the boot CPU) will be enabled; this will normally be CPU 0. Others that are present may be activated by writing 1s into this register. Enabling a CPU that is not present has undefined results.

The SELF register holds a 1 in the bit position corresponding to the currently executing CPU that is reading the register. This allows distinguishing CPUs from one another. (Note that the system board cannot distinguish among cores on the same CPU; that requires additional on-chip facilities.)

Device Revision Level. The device revision level of the multiprocessor system board is 1.

### Old Bus Controller

The older System/161 1.x uniprocessor bus controller (VID 1, DID 1), which is still supported and may be configured as "oldmainboard", has the following registers:

Name | Offset | Description
--- | --- | ---
RAMSZ | 0x200-0x203 | Size of physical RAM in bytes
IRQS | 0x204-0x207 | Mask of slots presently interrupting
PWR | 0x208-0x20b | Power enable register
IRQE | 0x20c-0x20f | Interrupt enable register
| 0x210-0x3ff | Reserved
|

RAMSZ, IRQS, and IRQE are the same as in the multiprocessor bus controller.

The PWR register switches the system off if the value 0 is written into it. Other writes have no effect, and reading produces undefined results.

Device Revision Levels. Two levels of the bus controller device are defined.

- DRL 1, the baseline, supports the RAMSZ, IRQS, and PWR registers.
- DRL 2, introduced in System/161 1.15, adds support for the IRQE register.

The IRQE register is defined so as to be backwards compatible; that is, software that works with the DRL 1 device will work with the DRL 2 device without modification.

### CPU Control Area

Each CPU control area contains the following:

Name | Offset | Description
--- | --- | ---
CIRQE | 0x000-0x003 | Per-CPU interrupt enable register
CIPI | 0x004-0x007 | Per-CPU inter-processor interrupt register
| 0x008-0x2ff | Reserved
CRAM | 0x300-0x3ff | Per-CPU scratch buffer
|

CIRQE is the same as IRQE, but per-processor. This allows interrupts to be routed to one or more processors as desired. CIRQE is applied downstream of IRQE; that is, an interrupt disabled in IRQE will never be delivered regardless of the setting of CIRQE on any CPU. Note: there is no hardware support for dispatching interrupts to multiple CPUs round-robin fashion.

CIPI allows sending inter-processor interrupts. The inter-processor interrupt pin of each CPU is asserted if its CIPI register contains a nonzero value.

CRAM is a 128-byte scratch area used for system startup, as described below. After startup it can be used as desired by the OS.

On the old uniprocessor motherboard, the entire CPU control area is reserved and accesses yield undefined behavior.

### Supporting Both Controllers

A kernel that supports both mainboard types (uniprocessor and multiprocessor) requires abstraction of the mainboard functions in software. Having accomplished that, the uniprocessor mainboard can be made to mimic a multiprocessor mainboard with one CPU as follows:

- Reads from CPUS, CPUE, and SELF should yield a falsified value of 1.
- Writes to PWR of values other than 0 should be blocked/ignored.
- Accesses to CIRQE should be redirected to IRQE.
- Writes to CIPI should be blocked/ignored.
- Reads from CIPI should yield a falsified value of 0.
- Accesses to CRAM should be redirected to a reserved region in main memory.

Additionally, to be able to run on DRL 1 of the old mainboard such a kernel must not rely on individual interrupt masking via CIRQE or IRQE being available at all.

### Bus Power-Up

At power-up time, the devices present are automatically probed and the VID, DID, and DRL values become available in the configuration registers. The CPUS register, if present, is loaded. The amount of RAM present is probed and the RAMSZ register is loaded. The IRQE and CIRQE registers, if present, are loaded with 0xffff ffff. All devices are reset to a state such that they will not generate interrupts until otherwise programmed.

At this point, the boot CPU is started. On the multiprocessor board the CPUE register is loaded so as to enable the boot CPU, usually CPU 0. On the uniprocessor board, the one CPU is simply released from reset. Control is transferred to the boot ROM.

The boot ROM has no published entry points and supplies no services besides system startup. In fact, it may or may not actually be present, as in the System/161 environment system startup can be effected without it, inside the simulator.

### Boot ROM

The boot ROM loads an ELF kernel image in a suitable processor-dependent way, and jumps to the image's entry point. A bootup stack is established. A single null-terminated string (generated from the kernel arguments passed on the System/161 command line) is passed as a function argument to the entry point.

On the multiprocessor system board, the boot string is placed in a suitable but unspecified location in main memory. The boot stack is established at the top of the CRAM area.

For secondary CPUs and secondary cores on the boot CPU, which are not normally started until the kernel has taken control of the system, the boot stack is established at the top of the CRAM area, and the contents of the lowest word in the CRAM area are read and used as an entry point to begin execution within the kernel.

On the old uniprocessor system board, the boot string and the boot stack are placed in a suitable but unspecified location in main memory.

MIPS.

The kernel should be linked to run at or near virtual address 0x8000 0000. The kernel is loaded into the corresponding physical memory at or near physical address 0. The boot string (and, if appropriate, the boot stack) are placed at or near the high end of memory, to avoid conflicting with the kernel. The kernel should as soon as possible copy the boot string and establish its own stack in a known location. Then all memory may be used safely.

The address of the boot string is passed in the a0 ($4) register. The `sp` register points to the top of a stack region as previously defined. However, the startup code should not assume that a proper caller stack frame already exists on the stack. (That is, writing a0 back to its argument slot through the stack pointer may produce undefined behavior.) The contents of other registers, including the CPU configuration registers, are unspecified. The TLB state is unspecified. The CPU cache is in a state suitable for routine operation.

Ant-32.

The experimental Ant-32 build of System/161 is deprecated.

i386.

Not yet specified.