AT&T 3B2/310 and 3B2/400 System Internals

Last Updated: 2018-01-15

1 Introduction and Overview

The purpose of this document is to keep track of my exploration of the internals of the AT&T 3B2/310 and 3B2/400 computers, for the eventual purpose of emulating the system.

There is scant information online about the internals of the 3B2. It has proven very difficult – nearly impossible, in fact – to find detailed documentation about how the 3B2 actually works. This document is a collection of notes taken during the process of reverse engineering the 3B2 system.

But why the 3B2? In main part because it is historically significant, and yet not very well known. The 3B2 was AT&T's main porting platform for System V Release 3 UNIX™ (SVR3). It is a fully 32-bit computer system built around a microprocessor and chipset by Western Electric called the WE32100. The WE32100 and its earlier predecessors, the WE32000 and the BELLMAC 32 processor, represent major leaps forward in building architectures specially suited for UNIX.

2 Links and Source Materials

The following are the source materials I've been using in my quest to understand how the 3B2 works.

3 Hardware

3.1 Major Components

Visual inspection reveals the following major components on the System Board.

  • WE32100 CPU
  • WE32101 MMU
  • WE32102 Bi-phase Crystal Oscillator
  • WE32106 Math Accelerator Unit (Optional)
  • 4 x D2764A EPROMs holding the system boot ROM
  • TMS2797NL floppy disk controller
  • NEC μPD7261A hard disk controller
  • NEC μPD8253C interval timer
  • AM9517A Multimode DMA Controller
  • SCN2681A Dual UART
  • MM58174A Real Time/Time of Day clock


Figure 1: 3B2 System Board Block Diagram

In addition to these major components, there is a tremendous amount of LSI glue logic, plus 14 PLAs/PALs on the system board. These seem to implement the DRAM controller, Control Status Register, and Interrupt Logic. Their exact layout is unknown, as no schematics are available.

Finally, there is one 18-pin DIP package IC labeled with in-house part number "O WE 62C", stamped with a date code and the number "53". The chip remains unidentified. Presumably it is custom LSI logic.

3.2 WE32100 CPU

As stated, the CPU is the WE32100 32-bit CPU. It has both a 32-bit address bus and a 32-bit data bus. The CPU has 9 general purpose and 7 special purpose 32-bit registers, supports four privilege modes (User, Supervisor, Executive, Kernel), supports addressing in words (32-bit), halfwords (16-bit), and bytes (8-bit), and has a highly orthogonal instruction set with many addressing modes. It is paired with the WE32101 MMU, the WE32102 dual-phase crystal oscillator which provides two 10MHz clocks 90° out of phase, and the optional WE32106 Math Accelerator UNIT.

3.3 WE32101 MMU

The WE32101 MMU provides virtual address to physical address translation using both segmented and paged memory.

On the 3B2, virtual address space is divided into four sections, identified by the top two bits of the address.

The MMU uses these top two bits as a Segment ID (SID) to look up the address in physical memory of a Segment Descriptor Table (SDT).

The next 13 bits of the address are known as the Segment Select field, and are used to index into the Segment Descriptor Table to find a Segment Descriptor.

The Segment Descriptor contains a bit that determines whether the virtual address being translated is to be treated as a Contiguous Segment, or Paged.

The rest of the bits of the virtual address are then treated differently depending on the value of this bit.

This process is described in great detail in the WE 32100 Microprocessor Information Manual and in the WE 32101 MMU datasheet.

3.3.1 Segmented Memory Virtual Addresses

Segmented virtual addresses further divide the virtual address into a Segment Offset (SOT). The physical memory address is then translated as in the figure below.

 31    30  29   17   16      0
|   SID  |   SSL   |    SOT    |


Figure 2: Segmented Memory Translation

3.3.2 Paged Memory Virtual Addresses

Paged virtual addresses further divide the lower 17 bits into a 6-bit Page Select field and an 11 bit Page Offset field. The physical memory address is then translated as in the figure below.

 31    30  29   17   16   11  10    0
|   SID  |   SSL   |   PSL  |   POT  |


Figure 3: Paged Memory Translation

3.4 8253 Programmable Interval Timer

This timer is responsible for driving much of the interrupt system. Its functions are IO mapped to the following addresses:

Physical Address 8253 Function SBD Function
0x42003 Counter 0 Sanity Timer (used for softpower)
0x42007 Counter 1 Interval Timer
0x4200b Counter 2 Not yet known
0x4200f Command  
0x42013 Clear Latch  
Counter 0
Set during ROM init. This appears mainly to be used for softpower status. The clock for Counter 0 on pin 9 runs at 100KHz.
Counter 1
Set during UNIX boot. Provides the level 15 interrupt used by UNIX for process switching. This is initialized to 0x03e8 (decimal 1000) by UNIX in the function clkstrt(). This gives us a period of 10ms, since the clock on Counter 1 on pin 15 runs at 100KHz.
Counter 2
Set during ROM init. The clock for Counter 2 on pin 18 runs at 2MHz. We don't know what this is for. It's not referenced in the AT&T source code. The ROM initialization puts 0xa (decimal 10) into the counter, so the timer output (if enabled) would pull low for 500ns every 5μs. So far, I have observed only that the gate is set so that this timer is not enabled.

3.5 Control Status Register

This is just a set of latches that can be set or cleared by writing to various memory locations, or read as a single 16-bit value. The base address of the CSR is at 0x44000.

Two 74LS374 Octal D-Type latches provide the 16-bit CSR.

The structure struct wcsr in usr/src/uts/3b2/sys/csr.h describes the programmer-accessible latch bits. There are no comments in the source, so comments are my own.

Address Name Description
0x44003 c_sanity Clear softpower timer bit
0x44007 c_parity Clear parity error bit
0x4400b s_reqrst Request firmware reset
0x4400f c_align Clear memory alignment trap
0x44013 s_led Turn on the green LED
0x44017 c_led Turn off the green LED
0x4401b s_flop Enable floppy motor
0x4401f c_flop Disable floppy motor
0x44023 s_timers Unknown (not used in SVR3?)
0x44027 c_timers Unknown (not used in SVR3?)
0x4402b s_inhibit Unknown (not used in SVR3?)
0x4402f c_inhibit Unknown (not used in SVR3?)
0x44033 s_pir9 Request Programmed Interrupt 9
0x44037 c_pir9 Clear Programmed Interrupt 9
0x4403b s_pir8 Request Programmed Interrupt 8
0x4403f c_pir8 Clear Programmed Interrupt 8

The 16 bits of the CSR, when read, map to the following values.

Name Mask
CSRTIMO 0x8000
CSRPARE 0x4000
CSRRRST 0x2000
CSRALGN 0x1000
CSRLED 0x0800
CSRFLOP 0x0400
N/A 0x0200
CSRITIM 0x0100
CSRIFLT 0x0080
CSRCLK 0x0040
CSRPIR8 0x0020
CSRPIR9 0x0010
CSRUART 0x0008
CSRDISK 0x0004
CSRDMA 0x0002
CSRIOF 0x0001

3.6 2681 Dual UART

The UART provides two serial ports integrated into the main system. One is the console, the other is a secondary TTY. Additionally, the UART provides a general purpose counter/timer circuit with an interrupt output.

The UART is clocked at 230.525 KHz. Due to the 16-bit counter, the maximum delay for the UART interrupt timer is 284 ms.

3.7 Floppy Drive

The standard floppy drive (known as IF, "Integrated Floppy") is a CDC 9429. The floppy format used is a little unusual: It is a Double-Sided, Quad Density format (DSQD) holding 720KB per diskette. The format is:

  • Double sided
  • 80 tracks per side
  • 9 sectors per track
  • 512 bytes per sector
  • 3:1 interleave
  • 250kbps MFM data

4 Expansion Cards

Expansion cards, or "Feature Cards", are IO devices that can be added to the 3B2's IO bus. The 3B2/310 has four slots, while the 3B2/400 has twelve.

Cards are automatically probed and configured at startup.

4.1 Registers

Each intelligent feature card has four 8-bit registers:

  • ID
  • ID/Vector
  • Control
  • Status

The vectors for each slot map to the following addresses:

Slot ID ID/Vector Control Status
0 0x0200000 0x0200001 0x0200003 0x0200005
1 0x0400000 0x0400001 0x0400003 0x0400005
2 0x0600000 0x0600001 0x0600003 0x0600005
3 0x0800000 0x0800001 0x0800003 0x0800005
4 0x0a00000 0x0a00001 0x0a00003 0x0a00005
5 0x0c00000 0x0c00001 0x0c00003 0x0c00005
6 0x0e00000 0x0e00001 0x0e00003 0x0e00005
7 0x1000000 0x1000001 0x1000003 0x1000005
8 0x1200000 0x1200001 0x1200003 0x1200005
9 0x1400000 0x1400001 0x1400003 0x1400005
10 0x1600000 0x1600001 0x1600003 0x1600005
11 0x1800000 0x1800001 0x1800003 0x1800005

4.2 Startup Procedure

  • CPU writes to the Status register of each slot, which causes the card to do a reset. If no card is present in the slot, the CSRTIMO bit will be set in the CSR and a memory exception will occur.
  • The feature card then initializes itself and prepares to have its board ID read.
  • The CPU reads the board ID from the ID and ID/Vector addresses, high and low bytes, respectively. Reading the ID triggers an INT0 on the feature card, letting the card know that it is about to be sysgen'ed.
  • The Feature Card then stops and waits for INT1.
  • The CPU reads the Control Register, causing an INT1
  • The Feature Card reads a special memory location, virtual address 0x2000000, and reads a pointer to a sysgen data block:
struct sysgen {
    long request;            /* address of request queue */
    long complt;             /* address of completion queue */
    unsigned char req_size;  /* number of entries in request queue */
    unsigned char ceq_size;  /* number of entries in completion queue */
    unsigned char int_vec;   /* base interrupt vector */
    unsigned char no_rque;   /* number of request queues */

request and complt both point to queue structures in memory, request queue and completion queue structures respectively.

typedef struct {
    ENTRY express;         /* Express Entry */

    struct {
        union {            /* Load and Unload pointers */
            uint32_t all;
            struct {
                uint16_t load;
                uint16_t unload;
            } bit16;
            struct {
                uint8_t pad1;
                uint8_t load;
                uint8_t pad2;
                uint8_t unload;
            } bit8;
        } p_queues;

        /* the queue entris RQSIZE or CQSIZE */
        ENTRY entry[qsize];
    } queue[num_queues];

Each entry in the queue uses the following structure:

typedef struct {
    uint16   byte_count;  /* # of bytes to transfer */
    uint8    subdevice;   /* Subdevice number */
    uint8    opcode;      /* Opcode/Return code of command */
    uint32_t address;     /* Address / Data */
    uint32_t app_data;    /* App-specific data */

4.3 PORTS Card Example

The following is a very high level of how the PORTS expansion card starts up and operates.

4.3.1 Determine Version

The first step is to sysgen the card and establish two-way communication queues between the card and the system board.

  1. The system board performs a normal RESET / INT0 / INT1 sysgen sequence.
  2. The PORTS card responds with an Express Queue response and an interrupt with IPL 10 and the appropriate vector.
  3. The system board requests the CARD's version with a PPC Version request (opcode 80)
  4. If the PORTS card is ROM version 1, it doesn't know how to respond, so completes with an error code (Response code 2). If the PORTS card is ROM version 2, it responds by writing the version to the correct place in memory, set by the request.

At this point, the card is properly sysgen'ed, and the system board knows what version it is.

4.3.2 Download Pump Code

The actual firmware of the PORTS card is stored on the 3B2's hard disk in the file /lib/pump/ports. This code, called the pump code, is uploaded to the card and executed through a request from the system board.

  1. Full RESET / INT0 / INT1 Sysgen sequence.
  2. Express Completion Queue reply (IPL 10)
  3. The system board begins downloading the file /lib/pump/ports to the card's memory using a series of Download Memory Express Queue requests (opcode 1)
  4. After each incremental download request, the PORTS card responds with an Express Queue entry and an interrupt at IPL 10 and the appropriate vector.
  5. After all segments of the file /lib/pump/ports have been downloaded to the card, the system board initiates a Force Function Call request to the card, telling the card to start running code at address 0x000500.
  6. The PORTS card responds with an Express Queue response and an interrutp with IPL 10 and the appropriate vector.

The card is now ready to serve requests.

4.3.3 Serving Requests

The following is an example of what occurs when the user types $ echo "foo" > /dev/tty11 at the shell. Each element represents either a Request Queue entry or a Completion Queue entry.

First, the system board issues a Connect command for the requested card and port.

Table 1: CONNECT Request
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x00 0x22 0x00 0x00000000 00 00 00 00
Table 2: CONNECT Completion
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x00 0x22 0x00 0x00000000 00 00 00 00

If the port has a DTR signal and is ready to transmit data, it responds out-of-band with an Asynchronous completion in addition to the Connect completion.

Here, the bit 0x01 in the first byte of the App Data means that a connection has been detected on the requested port/subdevice (0).

Table 3: ASYNC Completion
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x00 0x3C 0x00 0x00000000 01 00 00 00

Now the system board sends an Options command.

The PORTS board reads the Options structure at the supplied address (0x18 bytes long) and configures itself.

Table 4: OPTIONS Request
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x18 0x20 0x00 0x020AFE46 00 00 00 00
Table 5: OPTIONS Completion
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x18 0x20 0x00 0x020AFE46 00 00 00 00

Now the system board sends a series of seven Receive requests. Note that the PORTS card does not immediately respond to these requests. It queues them up for later processing.

Table 6: RECEIVE Request 1
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3F 0x32 0x05 0x020AFE46 00 00 00 00
Table 7: RECEIVE Request 2
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3F 0x32 0x05 0x020AFED6 00 00 00 00
Table 8: RECEIVE Request 3
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3F 0x32 0x05 0x020AFF66 00 00 00 00
Table 9: RECEIVE Request 4
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3F 0x32 0x05 0x020AFF1E 00 00 00 00
Table 10: RECEIVE Request 5
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3F 0x32 0x05 0x020AFDFE 00 00 00 00
Table 11: RECEIVE Request 6
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3F 0x32 0x05 0x020AFDB6 00 00 00 00
Table 12: RECEIVE Request 7
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3F 0x32 0x05 0x020AFD6E 00 00 00 00

Now the system board sends a Transmit request and waits for a Transmit completion.

Table 13: TRANSMIT Request
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3 0x21 0x00 0x020AFD26 00 00 00 00
Table 14: TRANSMIT Completion
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3 0x21 0x00 0x020AFD26 00 00 00 00

After transmission is complete, the system board sends a series of express Device requests with different values in the application data.

Here, 0x07 in byte 0 of the Application Data means DR_RES, or "Resume Transmit on a Device". 0x03 in byte 0 of the Application Data means DR_ABR, or "Abort Reception on a Device".

On completion, the received application data is placed in byte 1 of the Completion Queue Entry's Application Data, and a response code (in this case, 0x00 for "Executed Normally") is placed in byte 0.

Table 15: DEVICE Request
Type Byt Cnt Op Subdev Addr App Data
EXPRESS 0x0 0x28 0x00 0x00000000 07 00 00 00
Table 16: DEVICE Completion
Type Byt Cnt Op Subdev Addr App Data
EXPRESS 0x0 0x28 0x00 0x00000000 00 07 00 00
Table 17: DEVICE Request
Type Byt Cnt Op Subdev Addr App Data
EXPRESS 0x0 0x28 0x00 0x00000000 03 00 00 00
Table 18: DEVICE Completion
Type Byt Cnt Op Subdev Addr App Data
EXPRESS 0x0 0x28 0x00 0x00000000 00 03 00 00

The board sends another Device request with the command "Abort Reception", immediately followed by a Disconnect before the board has a chance to respond to the Device.

In the Disconnect command, the Application Data byte 1 value 0x03 is the OR'ed combination of GR_DTR (0x01) and GR_CREAD (0x02). The value 0x07 is the number of CBLOCKS to be returned to the system (matching the 7 requests above)

Table 19: DEVICE Request
Type Byt Cnt Op Subdev Addr App Data
EXPRESS 0x0 0x28 0x00 0x00000000 03 00 00 00
Table 20: DISCONNECT Request
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x0 0x23 0x00 0x00000000 07 03 00 00

Then, we get the response to the previous Device request.

Table 21: DEVICE Request
Type Byt Cnt Op Subdev Addr App Data
EXPRESS 0x0 0x28 0x00 0x00000000 00 03 00 00

Now we get a series of responses to the Receive requests made above. These seem to be in no predictable order.

Additionally, each of these Receive requests is followed by the system board issuing an INT1 (Attention) interrupt to the PORTS board.

Table 22: RECEIVE Completion 1
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3F 0x32 0x00 0x020AFE8E 01 00 00 00
Table 23: RECEIVE Completion 2
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3F 0x32 0x00 0x020AFF66 01 00 00 00
Table 24: RECEIVE Completion 3
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3F 0x32 0x00 0x020AFE46 01 00 00 00
Table 25: RECEIVE Completion 4
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3F 0x32 0x00 0x020AFDFE 01 00 00 00
Table 26: RECEIVE Completion 5
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3F 0x32 0x00 0x020AFDB6 01 00 00 00
Table 27: RECEIVE Completion 6
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3F 0x32 0x00 0x020AFD6E 01 00 00 00
Table 28: RECEIVE Completion 7
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x3F 0x32 0x00 0x020AFED6 01 00 00 00

Finally, the last message is the completion of the Disconnect sent above, before the Device and Receive messages.

Table 29: DISCONNECT Completion
Type Byt Cnt Op Subdev Addr App Data
REGULAR 0x00 0x23 0x00 0x00000000 00 00 00 00

5 Memory Map

5.1 ROM Space

The ROM is mapped too the bottom 64KB of the address space, at physical addresses 0x000000000x0000ffff. The ROM itself is only 32KB, so I still need to do some additional diagnostic programming to determine exactly how the ROM maps to the top half of its space, if at all.

When running under SVR3, the ROM is mapped at virtual address 0x00020000.

I have decoded and disassembled the ROM, and discovered that there are several distinct areas

  • Strings
  • Vector Tables
  • Code
  • System Version Number

5.1.1 Vector Tables

The Vector Tables are described in detail in the SVR3 source code, in the header file sys/firmware.h.

Special RAM Locations

Table 30: Pointers to RAM Locations
ROM Pointer SVR3 Name Description
Addr Addr    
0x48c 0x02000864 p_runflag Flag indicating whether system is safe for booting
0x490 0x02001514 p_edt Ptr. to Equipped Device Table (EDT)
0x494 0x020011f8 p_inthand Ptr. to location containing address of interrupt handlers
0x498 0x020011f4 p_exchand Ptr. to location containing address of exception handler
0x49c 0x02000858 p_rsthand Ptr. to location containing address of reset handler
0x4a0 0x02001200 p_cmdqueue Ptr. to command queue for boot command
0x4a4 0x020012a8 p_fl_cons Ptr. to float cons struct
0x4a8 0x0200126c p_option Ptr. to Ptr. to Option Number (for getedt)
0x4c4 0x02001268 p_access Access permissions for printf, etc.
0x4e0 0x020011f0 p_num_edt Ptr. to location containing number of devices in EDT
0x4e4 0x020011ec p_memsize Ptr. to location containing size of main memory
0x4e8 0x02001504 p_memstart Ptr. to location containing start of main memory for UNIX
0x4f0 0x02000a80 p_physinfo Ptr. to disk physical info
0x4f4 0x02001258 p_pswstore Ptr. to PSW before exception or interrupt
0x4f8 0x0200125c p_pcstore Ptr. to PC before exception or interrupt
0x4fc 0x020011e8 p_console Ptr. to pointer to console UART
0x504 0x02001264 p_save_r0 Ptr. to %r0 before exception
0x50c 0x020012d8 p_bpthand Ptr. to location containing address of exception handler
0x510 0x020012d0 p_spwrinh Location for soft power inhibit
0x514 0x0200086c p_meminit Location for memory init flag
0x52c 0x020012dc dmn_vexc Demon virtual process / stack exception handler PCB
0x530 0x020012e0 dmn_vgate Demon virtual gate table location
0x534 0x020012e4 dmn_vsint Demon virtual stray interrupt PCB location
0x544 0x02000a74 p_hdcspec Location of fw hdc spec params

ROM Routines

Table 31: Pointers to ROM Routines
ROM Pointer Name Description
Addr Addr    
0x4ac 0x00004dd4 p_getedt Routine to fill EDT structure
0x4b0 0x000044e4 p_printf Location of printf routine
0x4b4 0x00004360 p_gets Location of gets routine
0x4b8 0x00004ae4 p_sscanf Location of sscanf routine
0x4bc 0x00007f68 p_strcmp Location of strcmp routine
0x4c0 0x00002af8 p_excret Routine to set up a return point for exceptions
0x4c8 0x00004484 p_getstat Routine to check console for a character present
0x4cc 0x00005320 p_chknvram Location of routine to verify checksum over NVRAM
0x4d0 0x00005224 p_rnvram Location of routine to read NVRAM
0x4d4 0x000052a0 p_wnvram Location of routine to write NVRAM
0x4d8 0x00007698 p_hd_acs Location of routine to access hard disk
0x4dc 0x00007b2c p_fd_acs Location of routine to access floppy disk
0x4ec 0x00001168 p_release Pointer to location containing release of code
0x500 0x00003d74 p_setbaud Pointer to setbaud routine
0x508 0x00007ff0 p_serno Pointer to serial number struct
0x518 0x00005438 p_bzero Pointer to memory zero routine
0x51c 0x00005450 p_setjmp Pointer to setjmp routine
0x520 0x000054a1 p_longjmp Pointer to longjmp routine
0x524 0x00004e14 p_dispedt Pointer to display edt routine
0x528 0x00005504 p_hwcntr pointer to DUART counter delay routine
0x538 0x000055ec p_fw_sysgen Pointer to generic sysgen routine
0x53c 0x00005baa p_ioblk_acs Pointer to ioblk_acs routine
0x540 0x000051d2 p_brkinh Pointer to break inhibit routine
0x548 0x0081e100 p_symtell Function to tell xmcp where the symbol table is
0x54c 0x0000421f p_demon Function to enter demon without init

String Locations

There's a large block of string literals in the ROM which are referenced by the various subroutines. I have added these to the ROM source code as I've found them.

5.2 IO Space

Looking through the SVR3 source code has revealed the following system board map, in the file usr/src/uts/3b2/vuifile.

Name Address Description
unxsbdst 0x40000 System Board Start Address
mmusdc1 0x40000 MMU SDC bits 0-31
mmusdc2 0x40100 MMU SDC bits 32-64
mmupdc1r 0x40200 MMU Right Half PDC Bits 0-31
mmupdc2r 0x40300 MMU Right Half PDC Bits 32-63
mmupdc1l 0x40400 MMU Left Half PDC Bits 0-31
mmupdc2l 0x40500 MMU Left Half PDC Bits 32-63
mmusrama 0x40600 MMU Section RAM A
mmusramb 0x40700 MMU Section RAM B
mmufltcr 0x40800 MMU Fault Code Register
mmufltar 0x40900 MMU Fault Address Register
mmucr 0x40a00 MMU Configuration Register
mmuvar 0x40b00 MMU Virtual Address Register
sbdpit 0x42000 Programmable interval timer (8253)
clrclkint 0x42013 Clear clock interrupt
sbdnvram 0x43000 NVRAM (0x400 bytes)
sbdrcsr 0x44000 CSR Read (reads the whole 16-bit halfword)
sbdwcsr 0x44000 CSR Write base address
dmaid 0x45000 DMA Integrated Disk (hard disk) page buffer
dmaiuA 0x46000 DMA UART A page buffer
dmaiuB 0x47000 DMA UART B page buffer
dmac 0x48000 DMA controller status/command register
duart 0x49000 2681 UART
idisk 0x4a000 7261 Disk Controller
ifloppy 0x4d000 2797 Floppy Controller
dmaif 0x4e000 DMA Integrated Floppy page buffer

5.3 Memory

Main memory ("mainstore") appears to start at 0x2000000 on the 3B2. Interestingly, on SYSVR3 this is mapped to /dev/mainstore.

5.4 The Equipped Device Table (EDT)

5.4.1 Basic Structure

The EDT lives in main memory at 0x2001514, referenced by ROM pointer p_edt at ROM vector address 0x490.

The EDT holds information about cards on the IO bus discovered at start-up. Each slot is 128 bytes long (4 words), and uses the following structure:

Table 32: Device Structure
Field Width (bits) Description
opt_code 16 Option code
opt_slot 4 Slot number the board is in
opt_num 4 Which of given option types the board is
rq_size 8 Request queue entry size
cq_size 8 Completion queue entry size
resrvd 14 Reserved for future use
cons_cap 1 1 = can support console, 0 = cannot
cons_file 1 0 = no pump file for console, 1 = does
boot_dev 1 1 = has possible boot device
word_size 1 0 = 8-bit, 1 = 16 bit
brd_size 1 0 = single width, 1 = double width
smrt_brd 1 0 = dumb board, 1 = smart board
n_subdev 4 Subdevice count
subdev 32 Pointer to array of n_subdev subdevice structures
dev_name 10 10-byte (including terminator) name
diag_file 10 Name of resident file containing diag. phases
padding 12 Padding for word alignment

Note that in the table, slot entries are aligned on 8-word boundaries. So the first slot 0, the system board (SBD) is at 0x2001514, while slot two appears at 0x2001534, slot three at 0x2001554, and so on.

Subdevice structures are very simple 4-byte entries.

Table 33: Sub-Device Structure
Field Width (bits) Description
opt_code 16 Option code
name 10 Option name
padding 6 Padding for word alignment

5.4.2 Detecting Devices

The ROM startup code is responsible for filling the skeleton of the EDT with option codes and slot numbers, and for keeping track of the total number of entries.

On start-up, it begins by filling in the SBD entry in slot 0. Then it queries each card address from slot 1 to slot 12, one by one, probing for cards. It does so by writing the byte 0x00 into the card's command register (the slot's base address + 5), then by reading the card's option ID in two bytes: the high byte of the ID from the base address, and the low byte of the ID from base address + 1.

If an External Memory Exception occurs during either write or read, and the TIMEO bit is set in the CSR indicating that a bus timeout occurred, it is assumed that no card is available in the slot and it is removed from the EDT.

Table 34: IO Slot Base Addresses
Slot No. Base Address
0 N/A (SBD)
1 0x200000
2 0x400000
3 0x600000
4 0x800000
5 0xa00000
6 0xc00000
7 0xe00000
8 0x1000000
9 0x1200000
10 0x1400000
11 0x1600000
12 0x1800000

6 Interrupts

The WE32100 has fairly complex interrupt handling capabilities. Interrupt vectors can be set by the external device, or internally set via an auto-vector. Interrupts may be handled via a "quick-interrupt" handler, which is a simulated GATE instruction, or via a "full-interrupt" handler, which is a full process switch analogous to CALLPS. And finally, there's an non-maskable interrupt (NMI).

The 3B2 ROM and UNIX SVR3 do not use NMI, auto-vector interrupts, or quick interrupts at all. Running the 3B2 under a logic analyzer revealed that the /NMI, /AVEC, and /INTOPT inputs on the CPU is never asserted, either during ROM initialization or UNIX boot. Everything is handled via the full interrupt sequence.

Moreover, interrupts are completely disabled during ROM initialization, before UNIX boot. The IPL in the processor status word is always set to 15 (1111b), so no interrupts except NMIs will be handled. Interrupts are enabled in in the PSW by the UNIX kernel when it starts the 10ms interval timer.

The ROM area that would normally be used for quick interrupt handlers is instead used for PCBPs.

Table 35: Full-interrupt vector table in ROM
Address Contents IPL Notes
0x8C 0x02000BC8   NMI Handler
0x90 0x02000BC8 0 Auto-Vector Handler (not used)
0x94 0x02000BC8 1 PCBPs (31 words)
0xAC 0x02000C18 8 Programmed Interrupt 8 (PIR8)
0xB0 0x02000C68 9 Programmed Interrupt 9 (PIR9)
0xB4 0x02000CB8    
0xB8 0x02000D08 11 Hard Disk & Floppy
0xBC 0x02000D58    
0xC0 0x02000DA8 13 UART
0xC4 0x02000DA8    
0xC8 0x02000E48 15 10ms interval timer and Syserr
0xCC 0x02000BC8    
0xD0 0x02000BC8    
0x10C 0x02000BC8   Device Interrupt Handler
0x110 0x02000BC8   PCBPs (224 words)
  (All identical PCBPs)

6.1 3B2/400 System Board Interrupt Sources

The 3B2 interrupt subsystem takes interrupt inputs from several sources on the system board and translates them into values on the CPU's four bit IPL (Interrupt Priority Level) bus. The IPL bus is fed by a 74LS148 priority encoder.

The hard disk controller (ID), floppy disk controller (IF), and DUART (IU) interrupt outputs are directly connected to the priority encoder (potentially through inverters), and are cleared when the originating device de-asserts its IRQ line. The System Timer, however, is supplied to the priority encoder through a latch that is reset by software. Likewise, the CSRPIR8 and CSRPIR9 software interrupts are supplied through the CSR latches, and are reset by software.

IRQs are serviced by the CPU if and only if the PSW (processor status word) has an IPL field that is less than the corresponding IPL bus level. For example, if the PSW's IPL field is set to 15, no IRQs will be processed. If the PSW's IPL field is set to 12, only IRQs with priority level 13 or 15 will be processed.

An IPL bus level of 15 means that no IRQs are pending.

The 3B2 interrupt subsystem takes input from the following sources:

Source IPL Latched? Reset Notes
CSRPIR8 8 No Software Software IRQ
CSRPIR9 9 No Software Software IRQ
Hard Disk 11 No Hardware  
Floppy 11 No Hardware  
IUA 13 No Hardware Console
IUB 13 No Hardware ConTTY
IU Timer 13 No Hardware  
DMAC 13 Yes Software  
System Timer 15 Yes Software 10 ms timer

6.1.1 CSRPIR8 and CSRPIR9

CSRPIR8 and CSRPIR9 are both software interrupts. That is, they are set and cleared by software.

When the corresponding bit in the CSR is set, the IPL bus immediately asserts IPL 8 or IPL 9. When software resets the corresponding CSR bit, the IPL level returns to 15 (no IRQs pending).

6.1.2 Hard Disk and Floppy

The uPD7261A hard disk controller's INT output and the WDC2797 INTRQ output are both tied directly to the priority encoder and trigger IPL 11 on activation. As long as either output is asserted, IPL 11 will be on the IPL bus. The IPL bus is restored to level 15 when the INT or INTRQ output is deasserted.

Assertion of the WDC2797's INTRQ output also sets the CSRDISK bit in the CSR. Software can differentiate between interrupts generated by both controllers by checking this bit in the CSR. (TODO: How is the CSRDISK bit cleared? Is it cleared when CSRFLOP bit, connected to the drive motor, is cleared?)

6.1.3 DUART

The 2681 dual UART's INTRN output is tied directly to the priority encoder and triggers IPL 13 on activation. As long as the INTRN output is asserted, IPL 13 will be on the IPL bus. The IPL bus is restored to level 15 when INTRN is de-asserted.

6.1.4 DMAC

The DMAC can generate an interrupt at IPL 13 via the CSRDMA bit in the CSR by pulling down its EOP output, which, if associated with a UART Rx or Tx (signaled by the DUART's OP0/OP1 pins), will be latched in the CSR. Note that ONLY DUART transfers cause EOP to be latched as CSRDMA. No other DMAC EOP assertion will cause an interrupt at IPL 13. (TODO: I'd like to trace out exactly how this is wired, to better understand how OP0/OP1 and EOP are combined into the latched CSRDMA bit)

6.1.5 System Timer

The system timer is an 8253 interval timer with three independent 16-bit counters and corresponding timer outputs. Output 1 is latched and causes an interrupt at IPL 15. (TODO: trace and figure out where it's latched) In the SVR3, this timer output is used as the 10ms/100Hz system timer, and drives process switching and general housekeeping tasks in the operating system.

7 Miscellaneous Notes

7.1 Installation Floppy Format

Software distributed on floppy has the following requirements:

  1. The diskette label should be the short name of the product, e.g. "sgu" for Software Generation Utilities" or "nsu" for "Network Service Utilities"
  2. The filesystem should be a normal S51K (System V 1K) filesystem
  3. The filesystem should be named "instal" or "/instal", because it is mounted on the /install mountpoint by default.

7.2 Compiling a debug version of lboot

The first step is to change the load map (lbld) to incrase the size of the lbcode section:

        lbcode: origin = 0x020ef000, length = 0x13000
        lbbss:  origin = 0x02102000, length = 0x3c00
        lbstack:origin = 0x020ed000, length = 0x2000
        .text:  {
                stext = .;
                }  > lbcode
        .data:  {} > lbcode
        .bss:   {} > lbbss
                sstack = .;
                estack = .+0x2000;
                }  > lbstack

Then, edit and uncomment the line:

        -DDEBUG1 \
        -DDEBUG1f -DDEBUG1g -DDEBUG1h -DDEBUG1i \

It can also be nice to uncomment the line


so you get a memory map printed out on completion.

7.3 Installing a new lboot and mboot

These are the initial boot programs on the hard disk. mboot is responsible for loading lboot, and lboot is responsible for loading the kernel, or generating a new kernel.

After compiling a new lboot or mboot, they can be installed with this command:

# newboot /lib/lboot /lib/mboot /dev/idsk06

8 Appendix A: System Board Components

The System Board has 157 integrated circuits and 2 crystal oscillators. The table below summarizes the parts.

8.1 Major Components


In this figure, numbers are somewhat arbitrarily ordered, but roughly from top to bottom, right to left.

Table 36: Major Components
Number Name Purpose
1 WE32100 CPU
2 WE32101 MMU
3 WE32106 Math Accelerator Unit
10 WE32102 CPU clock source
4,5,6,7 i2764 System ROM
8 8253 Interval timer interrupt source
57 TMS2797 Floppy disk controller
93 AM9517A Multimode DMA controller
94 2681 Dual UART and interval timer interrupt source
156 μDP7261 Hard disk controller
A Header Floppy disk connector
B Header MFM hard disk data connector
C Header MFM hard disk data connector
D Header MFM hard disk control connector
E,F Connector Backplane card edge connector
G Memory Memory slot A (1MB,2MB)
H Memory Memory slot B (1MB,2MB)

8.2 All Parts

Table 37: AT&T 3B2/310 and 3B2/400 System Board (Part # ED-4C637-32-G)
IC Qty. Description
2681 1 Dual UART
26LS32 1 Quad differential line receiver
27LS31 1 Quad differential line driver
7406 2 Hex inverter buffer drivers with O.C. outputs
7407 2 Hex buffer drivers with O.C. outputs
74F04 1 Hex inverters
74F11 1 Triple 3-input AND gates
74LS00 1 Quad 2-input NAND gates
74LS02 1 Quad 2-input NOR gates
74LS04 5 Hex inverters
74LS05 1 Hex inverters with O.C. outputs
74LS08 2 Quad 2-input AND gates
74LS09 1 Quad 2-input AND gates with O.C. outputs
74LS10 1 Triple 3-input NAND gates
74LS11 1 Triple 3-input AND gates
74LS112 1 Dual neg.-edge-triggered master/slave J-K flip-flops
74LS125 1 Quad bus buffers with tri-state outputs
74LS126 1 Quad bus buffers with tri-state outputs
74LS138 6 3-to-8 line decoder/demux
74LS139 1 Dual 2-to4 decoder/demux
74LS14 2 Hex inverter with Schmitt trigger inputs
74LS148 1 8-to-3 priority encoder
74LS151 1 8-input multiplexer
74LS157 1 Quad 2-input multiplexers
74LS164 1 8-bit serial-in/parallel-out shift reg.
74LS174 1 Hex D-type flip-flops
74LS21 3 Dual 4-input AND gates
74LS244 5 Non-inverting buffer/driver
74LS257 7 Quad 2-input multiplexers with tri-state outputs
74LS279 4 Quad SR Latches
74LS32 5 Quad 2-input OR gates
74LS374 6 Octal D-Type latches with tri-state outputs
74LS390 1 Dual decade counter
74LS393 2 Dual 4-state binary counter
74LS645 9 Octal bus transceiver
74LS646 4 Octal bus transceiver with tri-state output
74LS74 5 Dual D-type flip-flop
74S00 2 Quad 2-input NAND gates
74S02 1 Quad 2-input NOR gates
74S03 1 Quad 2-input NAND gates with O.C. outputs
74S04 1 Hex inverters
74S05 1 Hex inverters with O.C. outputs
74S08 3 Quad 2-input AND gates
74S10 1 Triple 3-input NAND gates
74S112 1 Dual neg.-edge-triggered master/slave J-K flip-flops
74S174 2 Hex D-type flip-flops
74S175 4 Quad D-type flip-flops
74S32 2 Quad 2-input OR gates
74S74 8 Dual D-Type positve edge triggered flip-flops
75188 1 Quad RS-232 line drivers
75189 1 Quad RS-232 line receivers
82S153 12 Field programmable logic array (PLA)
974-6033-0 1 20 MHz xtal osc.
AM29843 5 Bus interface latches
AM29853 5 Parity bus transceiver
AM9517A 1 Multimode DMA controller
AMPAL16 2 Programmable array logic (PAL)
D2764A 4 EPROM
D8253C 1 Programmable interval timer
DP8465 1 PLL
MM58174A 1 Real time clock
TMS2797 1 Floppy disk controller
μDP7261 1 Hard disk controller
WE32100 1 CPU
WE32101 1 MMU
WE32102 1 Bi-phase 10MHz xtal osc.
WE32106 1 FPU/MAU
WE62C 1 Unknown (marked "O WE 62C")
Total 159  

8.3 Notes


9 Appendix B: IO Expansion Connectors

There are two card edge connectors on the system board, Connector A (100 pins) and Connector B (60 pins). These together form the I/O Expansion Bus. A backplane fits into these connectors and provides 4 (on the 3B2/300 and 3B2/310) or 12 (on the 3B2/400) Peripheral Connectors.

The connectors are documented in: "3B2 IO Bus", December 1983.

9.1 100-Pin I/O Expansion Connector A

Pin Number Signal   Pin Number Signal
1 VCC   2 PPA[23]
3 PPA[22]   4 GRD
5 PPA[21]   6 PPA[20]
7 PPA[19]   8 GRD
9 PPA[18]   10 PPA[17]
11 VCC   12 GRD
13 PPA[16]   14 PPA[15]
15 PPA[14]   16 GRD
17 PPA[13]   18 PPA[12]
19 PPA[11]   20 PPA[10]
21 VCC   22 PPA[09]
23 PPA[08]   24 GRD
25 PPA[07]   26 PPA[06]
27 PPA[05]   28 GRD
29 PPA[04]   30 PPA[03]
31 VCC   32 GRD
33 PPA[02]   34 PPA[01]
35 PPA[00]   36 GRD
37 /PLOCK   38 /PR1W
39 /PPAS   40 GRD
41 VCC   42 /PBACK
43 /PBRQ   44 GRD
45 PD[15]   46 PD[14]
47 PD[13]   48 GRD
49 PD[12]   50 PD[11]
51 VCC   52 GRD
53 PD[10]   54 PD[09]
55 PD[08]   56 GRD
57 PD[07]   58 PD[06]
59 PD[05]   60 GRD
61 VCC   62 PD[04]
63 PD[03]   64 GRD
65 PD[02]   66 PD[01]
67 PD[00]   68 GRD
69 /PDS[1]   70 /PDS[0]
71 VCC   72 GRD
73 /PDTACK   74 /PSIZE16
75 /PFLT   76 GRD
77 /PFAIL   78 /PBUSY
79 /SYSRST   80 GRD
81 VCC   82 /PIAK[0]
83 /RQRST   84 /PIAK[1]
85 /PINT[0]   86 /PIAK[2]
87 /PINT[1]   88 GRD
89 /PINT[2]   90 VBKUP
91 VCC   92 GRD
93 /PCS[01]   94 V12N
95 /PCS[02]   96 GRD
97 /PCS[03]   98 V12P
99 /PCS[04]   100 GRD

9.2 60-Pin I/O Expansion Connector B

Pin Number Signal   Pin Number Signal
1 VCC   2 /PCS[05]
3 VCC   4 GRD
5 /PCS[06]   6 GRD
7 VCC   8 GRD
9 VCC   10 GRD
11 /PCS[07]   12 GRD
13 VCC   14 GRD
15 VCC   16 GRD
17 /PCS[08]   18 GRD
19 VCC   20 GRD
21 VCC   22 GRD
23 /PCS[09]   24 GRD
25 VCC   26 GRD
27 VCC   28 GRD
29 /PCS[10]   30 GRD
31 VCC   32 GRD
33 VCC   34 GRD
35 /PCS[11]   36 GRD
37 VCC   38 GRD
39 VCC   40 GRD
41 /PCS[12]   42 GRD
43 VCC   44 GRD
45 VCC   46 GRD
47 /PCS[13]   48 GRD
49 VCC   50 GRD
51 VCC   52 GRD
53 /PCS[14]   54 GRD
55 VCC   56 GRD
57 VCC   58 GRD
59 /PCS[15]   60 GRD

9.3 86-Pin Peripheral Connector

Pin Number Signal   Pin Number Signal
1 V12P   2 /PINT[2]
3 V12N   4 /PINT[1]
5 /PBACKI   6 /PINT[0]
7 PCS   8 /RQRST
9 GRD   10 /SYSRST
11 VBKUP   12 /PFAIL
13 /PIAKO[2]   14 /PFLT
15 /PIAKI[2]   16 GRD
17 /VCC   18 /PDTACK
19 /PIAKI[1]   20 /PDS[1]
21 /PIAKO[1]   22 PD[00]
23 /PIAKI[0]   24 PD[02]
25 GRD   26 PD[03]
27 /PBUSY   28 PD[05]
29 /PIAKO[0]   30 PD[07]
31 /PSIZE16   32 GRD
33 /PDS[0]   34 PD[08]
35 PD[01]   36 PD[10]
37 GRD   38 PD[12]
39 PD[04]   40 VCC
41 GRD   42 PD[13]
43 PD[06]   44 PD[15]
45 PD[09]   46 /PBRQ
47 PD[11]   48 GRD
49 GRD   50 /PPAS
51 PD[14]   52 /PLOCK
53 /PBACKO   54 PPA[00]
55 /PR1W   56 GRD
57 GRD   58 PPA[02]
59 PPA[01]   60 PPA[04]
61 PPA[03]   62 PPA[05]
63 PPA[06]   64 VCC
65 GRD   66 PPA[07]
67 PPA[09]   68 PPA[08]
69 PPA[10]   70 PPA[11]
71 PPA[12]   72 GRD
73 GRD   74 PPA[13]
75 PPA[15]   76 PPA[14]
77 PPA[17]   78 PPA[16]
79 PPA[20]   80 GRD
81 GRD   82 PPA[18]
83 PPA[23]   84 PPA[19]
85 PPA[21]   86 PPA[22]

Author: Seth Morabito

Created: 2018-01-15 Mon 18:44

Emacs 25.3.1 (Org mode 8.2.10)