AT&T 3B2/310 and 3B2/400 System Internals
Last Updated: 2017-11-25
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.
- The WE 32100 Microprocessor Information Manaual (1985, PDF)
- WE32-Bit Microprocessors and Peripherals (1987, PDF)
- Hardware Configurations and I/O Protocol of the WE32100 Microprocessor Chipset (1986, PDF)
- 3B2 IO Bus (1983, PDF)
- 3B2 CIO Hardware (1983, PDF)
- AT&T 3B2 and 3B5 Computer Driver Design Guide (1984, PDF)
- "The Design of the UNIX Operating System", Maurice J. Bach, 1986
- AT&T UNIX System V Release 3 Source Code (9.8 MB, gzipped TAR file)
- AT&T 3B2 ROM Images (Link to GitHub)
- Disassembled Model 400 ROM image (Link to GitHub)
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
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
(decimal1000
) by UNIX in the functionclkstrt()
. 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 Memory Map
4.1 ROM Space
The ROM is mapped too the bottom 64KB of the address space, at
physical addresses 0x00000000
– 0x0000ffff
. 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
4.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
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
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.
4.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 |
4.3 Memory
Main memory ("mainstore") appears to start at 0x2000000
on the 3B2.
Interestingly, on SYSVR3 this is mapped to /dev/mainstore
.
4.4 The Equipped Device Table (EDT)
4.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:
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.
Field | Width (bits) | Description |
---|---|---|
opt_code |
16 | Option code |
name |
10 | Option name |
padding |
6 | Padding for word alignment |
4.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.
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 |
5 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.
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) |
5.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 |
5.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).
5.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?)
5.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.
5.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)
5.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.
5.2 Interrupt Hanlder Example
The PCB pointed at by the PCBP 0x0200BC8
is in RAM space, so the ROM
must set it up during startup.
The PCB gets set up like this:
Address | Value | Notes |
---|---|---|
0x02000BC8 |
0x0081E180 |
Processor status word |
0x02000BCC |
0x000040A0 |
Program Counter |
0x02000BD0 |
0x020010E8 |
Stack Pointer |
This sets up the address of the routine to call at 0x40A0
.
000040a0: 84 ce fc 40 MOVW -4(%isp),%r0 000040a4: 84 50 7f 58 12 00 02 MOVW (%r0),$0x2001258 000040ab: 70 NOP 000040ac: 84 c0 04 7f 5c 12 00 02 MOVW 4(%r0),$0x200125c 000040b4: 70 NOP 000040b5: 87 00 7f 60 12 00 02 MOVB &0x0,$0x2001260 000040bc: 70 NOP 000040bd: 2c 5c 7f ec 64 00 00 CALL (%sp),$0x64ec 000040c4: 30 c8 RETPS
Here, the call to 0x64EC
is the important bit.
000064ec: 10 49 SAVE %fp 000064ee: 9c 4f 00 00 00 00 4c ADDW2 &0x0,%sp 000064f5: 2c 5c ef f8 11 00 02 CALL (%sp),*$0x20011f8 000064fc: 04 c9 e8 4c MOVAW -24(%fp),%sp 00006500: 20 49 POPW %fp 00006502: 08 RET 00006503: 70 NOP
The routine at 0x64EC
is responsible for calling a routine pointed
at by 0x20011f8
. That location is the "real" interrupt handler, and
is frequently updated inside the ROM as different handlers are
required. Thus, the ROM can insert any arbitrary code as an interrupt
handler at any time.
6 Installation Floppy Format
Software distributed on floppy has the following requirements:
- The diskette label should be the short name of the product, e.g. "sgu" for Software Generation Utilities" or "nsu" for "Network Service Utilities"
- The filesystem should be a normal S51K (System V 1K) filesystem
- The filesystem should be named "instal" or "/instal", because
it is mounted on the
/install
mountpoint by default.
7 Decoding the 3B2 ROMs
According to Section 2.11.1 of the WE32100 Microprocessor Information Manaul, on reset the CPU does the following
- Changes to Physical Addressing Mode (same effect as DISVJMP privileged instruction)
- Fetch word at location 80 hex and stores it in the PCBP register.
pcbp = 00 00 05 d8
- Fetch the word a the PCB address and store it in the status word.
The word at 05D8 is 0081e180, so we set that to the status word:
psw = 00 81 e1 80
Now let's interpret this:
3 2 1 0 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 --------------------------------------------------------------- 0 0 0 0 0 0|0|0|1|0|0 0 0 0|0|1 1 1 1|0 0|0 0|1 1|0 0 0 0|0|0 0 From right to left, the fields are: ET = 0 (Exception type b00 is "Reset Exception") TM = 0 ISC = 0 (Exception Internal State Code b0000 is "Old PCB* Fault") RI = 3 (R=1, I=1) PM = 0 (Previous Mode = Kernel level) CM = 0 (Current Mode = Kernel level) IPL = 15 (Highest Level: Nothing may interrupt the CPU) TE = 0 NZVC = 0 (No flags set) OE = 0 CD = 1 (Cache is disabled) QIE = 0 CFD = 0 NB: PCB = "Process Control Block"
- Fetch the word at the Process Control Block (PCB) address + 4 bytes,
and store it in the PC.
pcbp + 4 = 00 00 12 74
So we set PC = 00 00 12 74
- Fetch the word at the PCB address + 8 bytes, and store it in the SP.
pcbp + 8 = 02 00 00 08
So we set SP = 02000008
- If the PSW I bit (from RI) is set (yes, it is), CLEAR the bit (RI
becomes 10) then fetch the word at PCB address + 12 bytes, and
store it in the PCBP
PCBP = 00 00 00 00
- Start running at the PC (0x1274)
- This means we can start to disassemble code starting at address 0x1274 in the ROM image, because it is mapped to memory location 0.
That initial part of the ROM, when disassembled, looks like this:
00001274: 04 7f 08 00 00 02 4c MOVAW $0x2000008,%sp 0000127b: 04 7f 08 00 00 02 49 MOVAW $0x2000008,%fp 00001282: 04 7f 08 00 00 02 4a MOVAW $0x2000008,%ap 00001289: 04 7f 08 08 00 02 4e MOVAW $0x2000808,%isp 00001290: 87 16 7f 0f 20 04 00 MOVB &0x16,$0x4200f 00001297: 70 NOP 00001298: 87 6f 64 7f 03 20 04 00 MOVB &0x64,$0x42003 000012a0: 70 NOP 000012a1: 87 5f 94 00 7f 0f 20 04 00 MOVB &0x94,$0x4200f 000012aa: 70 NOP 000012ab: 87 0a 7f 0b 20 04 00 MOVB &0xa,$0x4200b 000012b2: 70 NOP 000012b3: 87 6f 74 7f 0f 20 04 00 MOVB &0x74,$0x4200f 000012bb: 70 NOP 000012bc: 24 7f d5 12 00 00 JMP $0x12d5 ...
The very first thing the ROM does is set up the programmable timer.
The next thing it does is a complex set of power-on self test diagnostics. These are actually incredibly useful, because they exercise the CPU, and therefore also exercise the simulator.
Once power on self test is completed, a magic word is deposited into
the p_runflag
memory location (0x02000864
). It can be any one of
the following:
0xFEEDBEEF
: Fatal error. System reset.0x3B02F1D0
: MAS has been init'ed (what's MAS?)0xA11C0DED
: Reset goes torst_handler
0x8BADF00D
: Reboot w/o diags for UN*X0xADEBAC1E
: Re-enter firmware from a reset w/o failure message
8 Simulation Notes
For the 3B2 simulator, if we want to mimic an 10MHz system clock, each virtual machine cycle has a 100 ns period.
One step of the interval timer clock input is 10 ms. So every 100000 steps of the simulator is one step of the interval timer coming from the 8253 SIT.
9 Booting
9.1 Hard Disk Initialization
The hard disk is initialized on boot as described below.
- The hard disk controller is asked to reset with an AUX RESET command.
- The processor examines bit 7 of the status register, CONTROLLER
BUSY. If the device is available, we clear the data buffer and CE
bits, then give it the SPECIFY command with the following arguments:
- 0x18 means Soft Sectored, Stepping Rate 3.
- 0xf2 is the DTLH byte. The first nybble means:
- initialize the Polynomial Counter with all 1s
- Select ID and data pad of 0x4e
- Polling mode is OFF
- 0x00 is the DTLL byte. It is appended to the low nybble of DTLH to form the word 0x200, meaning a data length of 512 bytes.
- 0x03 is the Ending Track Number (ETN)
- 0x11 is the Ending Sector Number (ESN)
- 0x0d is the Gap 2 Length
- 0x00 is the Reduced Write Current cylinder high byte
- 0x80 is the Reduced Write Current cylinder low byte
NB: "ETN" and "ESN" are used to convert logical cylinders and sectors to physical cylinders and sectors, as described in the uPD7261 datasheet:
"LSN is incremented at the end of each sector until the value of ESN is reached. LSN is then set to 0 and LHN is incremented. If LHN reaches the value of ETN, then LHN is cleared and LCN is incremented."
- The host checks to see if the command completed successfully. If it did, the CEH bit of the status register should be set, and the CEL bit should be clear.
- The host issues a CLEAR CE BITS command to clear CEH and CEL.
- The host issuesa CLEAR DATA BUFFER command.
- The host issues another CLEAR CE BITS command.
- The host issues a SENSE UNIT STATUS command with the argument 0x1e.
This argument is the UNIT STATUS (UST) byte and is broken down into
the following bits:
- bits 7-5: Always 0
- bit 4: Drive Selected SET
- bit 3: Seek Complete SET
- bit 2: Track 0 SET
- bit 1: Ready SET
- bit 0: Write Fault CLEAR
- The host again checks for successful completion of this command.
- The host then reads the data field, which should be a UNIT STATUS
byte containing the current status of the drive:
- bits 7-5: Always 0
- bit 4: Drive Selected SET
- bit 3: Seek Complete SET
- bit 2: Track 0 SET
- bit 1: Ready SET
- bit 0: Write Fault CLEAR
- The host clears the data buffer and the CE bits again
- The host issues a RECALIBRATE command. RECALIBRATE repositions the drive head to Cylinder 0. IST is available as a result byte.
… Much more to come, as I need to document it.
10 Appendix A: System Board Components
The System Board has 157 integrated circuits and 2 crystal oscillators. The table below summarizes the parts.
10.1 Major Components
In this figure, numbers are somewhat arbitrarily ordered, but roughly from top to bottom, right to left.
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) |
10.2 All Parts
IC | Qty. | Description | Notes |
---|---|---|---|
2681 | 1 | Dual UART | Console serial I/O |
26LS32 | 1 | Quad differential line receiver | Hard disk MFM receiver |
27LS31 | 1 | Quad differential line driver | Hard disk MFM 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 | Non-inverted G input |
74LS126 | 1 | Quad bus buffers with tri-state outputs | Inverted G input |
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 | Some boards use MC1488 parts |
75189 | 1 | Quad RS-232 line receivers | Some boards use MC1489 parts |
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) | Marked: AAUWW, AAUYA |
D2764A | 4 | EPROM | Marked: AAYYC, AAYYD, AAYYE, AAYYF |
D8253C | 1 | Programmable interval timer | Interrupt source |
DP8465 | 1 | PLL | Used in data separator for HD controller |
MM58174A | 1 | Real time clock | TOD clock. Supported by a 32.768 KHz xtal |
TMS2797 | 1 | Floppy disk controller | |
μDP7261 | 1 | Hard disk controller | Uses DP8465 as PLL/data separator |
WE32100 | 1 | CPU | |
WE32101 | 1 | MMU | |
WE32102 | 1 | Bi-phase 10MHz xtal osc. | Clock source for the WE32100 |
WE32106 | 1 | FPU/MAU | |
WE62C | 1 | Unknown | Unknown. Marked: "O WE 62C" |
Total | 159 |
10.3 Notes
- The 12
82S153
PLAs are marked: AAUWG, ABGLU, AAUWS, AAYBN, AAUWH, AAUWL, AAUWT, ABGWT, AAUWN, AAUWK, AAUWR, AAUWJ
11 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.
11.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 |
11.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 |
11.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] |