DEC PDP11 Rebuild
This document contains information I have gathered when trying to bring some DEC PDP11 boards together to have a “working” system.
Summary of boards
I have collected some boards in the last years.
CPU boards:
- M8186 LSI-11/23 CPU (C Revision, so capable of 22 bit addressing)
RAM boards:
- M8044 MSV11-DD 32K RAM, 18Bit
- M8067 512KB RAM, 22 Bit
Serial boards:
- M8028 DLV-11F serial board
- M3104 serial board
Multi Purpose Boards:
- M8047 MXV11-A Multi Purpose Card, 18 Bit.
Disk controllers:
- M8029 RX02 Disk Controller, 18 Bit
- EMULEX CS02H1 Controller.
Cages, Backplanes, Misc:
- H9278-A backplane
- BA11-MF mounting box with H9270-A backplane
- H780-F power supply
Power consumption in Ampere for some boards:
Board | 5V | 12V |
---|---|---|
M8186 | >2 | 0.14 |
M8044 | 0.96 | 0.07 |
M8029 | 1.38 | 0.0 |
Minimal system
A minimal system would let the CPU boot up and enter the ODT debugger built into the CPU itself. The CPU would need RAM to execute code and a serial card for interacting with the user. This is not very useful, but already a complicated step.
Looking at my set of boards, I have several options for this minimal system.
I could use the multipurpose module M8047 and get this small system:
- M8186 CPU Board
- M8047 MXV11-A Multi Purpose Card, 18 Bit
But the multipurpose board has overwhelming 60 jumpers to configure all of its functions. This is too complicated for me in the first step. So I will try it with another configuration, that needs one card more. This system should be able to come up to ODT console:
- M8186 CPU Board
- M8044 MSV11-DD 32 KBytes RAM
- M8028 DLV-11F Serial Board
M8186 CPU jumper configuration
The CPU board has 18 jumpers to configure.
The purpose of the jumpers is described in KD11-AA User’s Guide, chapter 2.1.
The following table lists the values I think are needed in my configuration.
Jumper | Purpose | O=Open, I=Inserted | Comment |
---|---|---|---|
W1 | Master Clock Enable | I | |
W2 | Reserved | O | |
W3 | Reserved | I | |
W4 | Line Event O=enabled | O | Check later |
W5 | Power Up Mode | I | see below |
W6 | Power Up Mode | O | see below |
W7 | Halt Trap O=enter ODT | O | Go to ODT on HALT |
W8 | Bootstrapmode I=173000 | O | I do not want bootstrapmode |
W9 | Bootstrap address | I | Not used |
W10 | Bootstrap address | I | Not used |
W11 | Bootstrap address | I | Not used |
W12 | Bootstrap address | I | Not used |
W13 | Bootstrap address | I | Not used |
W14 | Bootstrap address | I | Not used |
W15 | Bootstrap address | I | Not used |
W16 | Reserved | I | |
W17 | Reserved | I | |
W18 | Wake up circuit 0=enabled | I | Check later |
W5, W6: Values I,O means console ODT. This is what I want.
W4: I keep it at O=Open, so the event is enabled. This event triggers an BEVENT interrupt in CPU, which executes the “line clock vector” at address octal 100. This can be used to implement a 60 Hz triggered real time clock. My hope is that this mechanism does not disturb the ODT.
W18: I keep it at I=Inserted. So that circuit is disabled. As far as I understood, the wake up circuit is for environments where unattended restarts need to be possible. So I guess it is ok to have this disabled.
For all jumpers with purpose Reserved, I have listed the factory defaults.
Some “Jumpers” are in reality 0 Ohms resistors or just soldered wires.
M8044 MSV11-DD RAM jumper configuration
My board is a M8044-DA , Module name MSV11-DD.
The RAM board has 5 jumpers to configure. In fact it has some more, but some are soldered and need no modification. Like battery backup use, bank 7 disable and parity config.
The remaining 5 jumpers do configure the start address of the RAM.
The purpose of the jumpers is described in LSI11 Systems Service Manual, page 487ff.
In a system with only this RAM, we can start RAM at address 0.
In this case, S1-1 …, S1-5 need to be set to N as can be seen in the manual N means On = closed. The opposite is F, which means Off = Open.
M8028 DLV-11F Serial Board Jumper Configuration
My board is a revision E with the newest chips on board 1985. This late revision is described well in Digital Microcomputer Interfaces Handbook, 1980 starting at page 201.
This board has a bunch of jumpers.
Jumper | Purpose | O=Open, I=Inserted | Comment |
---|---|---|---|
A3-A12 | Bits A3..A12 of address word | =177560 | see below |
V3-V8 | Vector bits A3..A8 | =60/64 | see below |
R0-R3 | Rx baud rate bits | O,O,O,O | 19.200 baud |
T0-T3 | Tx baud rate bits | O,O,O,O | 19.200 baud |
BG | Break generation; if inserted break | I | allow break |
P | Parity bit generation if inserted | O | No parity |
E | Check for parity and generate parity bits | O | No parity |
1 | Number of data bits | O | 8 bits |
2 | Number of data bits | O | 8 bits |
PB | Programmable baud rate if inserted | O | forbid first |
C | Common speed op if inserted | I | |
C1 | Common speed op if inserted | I | |
S | Split speed op if inserted | O | |
S1 | Split speed op if inserted | O | |
H | Assert BHALT L bus line if inserted | I | |
B | Negate BDCOK H bus line if inserted; puts CPU to HALT | O | |
-B | Negate BDCOK H bus line if inserted; puts CPU to HALT | I | |
1A,2A,3A | Activate 20mA current Rx loop if inserted | O,O,O | |
1P,2P | Deactivate 20mA current Rx loop if inserted | I,I | |
4A,5A | Activate 20mA current Tx loop if inserted | O,O | |
3P,4P | Deactivate 20mA current Tx loop if inserted | I,I | |
EF | Enable error flags to be read in high byte of Rx buffer if removed | I | disable first |
M,M1 | Test jumpers for manufacturing | O,O | Do not touch |
MT | Maintenance bit if inserted | O | Do not touch |
BG: Hope that generation of break signal does not disturb ODT
Baud rate: newer boards allow 19.200 baud
C,C1,S,S1: no split speed op. Both Rx and Tx have same speed
EF: disable error flag handling; hopefully has no effect
Changing jumpers
The jumpers are all wire-wrapped wires. I have no wire wrap tooling. Because many wires need to be removed and other wires need to be added, I do not want to do this without proper tooling. Nice thing is that wire wrapping seems to be a dead technique and I could get a used professional tool set for some few Euros on ebay.
Image showing some of the jumpers, which are wire bridges in reality.
It needs some days until the tools arrive. In this time I will study what addresses A3-A12 and vector V3-V8 can be set.
How does addressing of a board work?
What I currently do not understand is, how the CPU finds a device board.
For accessing RAM board this is no problem, because RAM is there or not. CPU simply uses RAM by reading and writing from/to addresses in the address range. 0..(256-4)K.
I’ve read that upper 4K is reserved for external boards. The boards have some registers via which the CPU communicates with them. Boards appear at a base address and need some addresses to map in their registers. The base address can be set by jumpering some address bits, like A3-A12 for M8028. A13-A15 are always read as logical one. A0-A2 are used to address the board registers.
So this is all understandable. But how does the CPU finds the console device? Maybe console device has a well-defined, known base address. The same is maybe also true for the vector bits.
After some study I found this: Console needs to be present at fixed base address 177560 . Its 4 registers are at this and the three following addresses, last at 177566.
Standard vectors are RCSR=060 and XCSR=064 (receive and transmit).
Next I’ve created a three wire RS232 connection cable.
A standard 40 pin IDE connector fits into the BERG connector of the board. The nose at the plug needs to be removed, this can simply be done with a file. Connector is numbered from A to VV, as can be seen on next picture.
The connector looks a little over-engineered, because we need only three wires of the 40…
BERG Pin | DEC Signal | IDE Pin | DB9 Pin (Null Modem) | DB9 Signal |
---|---|---|---|---|
E | EIA Interlock In | 36 | See below | |
F | EIA Serial Out | 35 | 2 | RxD |
J | EIA Serial In | 33 | 3 | TxD |
M | EIA Interlock Out | 30 | See below | |
VV | GND | 1 | 5 | GND |
The M8028 board requires that BERG Pin E and M are connected to work with EIA mode.
The information in the table comes from Minimal RS232 cable: KL8-E to 9-Pin DTE Device and https://homepage.divms.uiowa.edu/~jones/pdp8/hard8e/bc01v.html .
Switching on for the first time
Finally the wire wrap tools arrived.
Top: tool to remove isolation from wire, right Wrap/Unwrap tool, bottom left: Another tool to remove isolation from wire.
After having jumpered the CPU, the RAM and the serial board, I’ve switched on the whole system. Output of RS232 line was connected to an oscilloscope.
In my initial setup, I have the boards M8186 (CPU), M8028 (serial board), M8044 (RAM). All inside a BA11-MF housing. Power supply is from a PC PSU.
The oscilloscope in the background shows the first ASCII output of the CPU via serial board.
Closer look to the BA11-MF housing.
After some switching on and off: the scope catched the live sign of the system:
The yellow signal shows the raw RS232 signal levels. What can be seen in the green lower line is the decoded RS232 data:
000000
@
This is the correct output for a PDP11 CPU going to ODT (Online Debug Terminal).
After some trouble with connecting to the right wires, I managed finally to get the ODT also working with a Linux Terminal window running kermit.
The command line always starts with @
created by the CPU.
After that commands can be entered. A valid command is
R0/
. This prints out the content of CPU register R0 in the same line, directly after
the /
.
Same command
can be done for all registers R0..R7. R
needs to be in capital letters,
as can be seen in the line where I tried r
. CPU immediately responds with a question mark.
Next I entered a non-existent register R8, resulting again in a question mark.
It is also possible to get the content of any RAM address, by entering
for example 1000/
, which prints the content of that address 1000.
If the content has been printed out, it is possible to just enter a new value for that register or address. When hitting return key, the value then is written to register or address.
Using ODT, I was even able to verify that my RAM board is working.
SRUN bus signal is emitted by CPU if it is running, this means not in HALT/ODT mode. I have checked that signal, which is not a stable voltage but a periodic signal with about 600 Khz. See next image.
Above: SRUN signal while executing code. If The Enable/Halt switch is moved to Halt-position, the signal disappears, and the CPU enters Halt mode / ODT.
Some experiments with ODT, all copied from Diane Neisius page:
# "handle" traps
@0/176377 0
@2/000000
@4/177777 2
@6/000000
@10/177777 6
@12/000000
@14/177777 12
@242/000000
@244/177777 242
# init SP
@R6/000000 700
# Code that writes to RAM in a loop incrementing address
@1000/177677 5000 # clr r0
@1002/000000 5720 # tst (r0)+
@1004/177777 776 # br .-2
@1006/000000
# Execute that code, ends with "bus Error" trap at location 4
@1000G
000004
# Check result = last valid memory address + 2
@R0/160002
So my RAM board seem to have octal 160.000 addresses. This is 57.334 decimal or 0xe000 (64 - 8)K , 56K.
Hm. This result is somewhat confusing, because I thought that the RAM board has 32K Words (16 bit words). The result then should be something below 32.768 decimal. Strange…
I have to check this.
Time to rest
Bringing all the boards, bought over the years together into a system that is able to boot up until ODT, is a landmark on its own. To get there, I need to replace the not so well working power supply H780 with a PC PSU, and also to replace the Switch&Lights Boards (which is part of the H780 in case of the OBA-11MF) with an own solution took some days to bring everything together.
The final steps were supported by members of the great forum https://forum.classic-computing.de/. Many thanks to them.
So I will take a rest of some days before continuing in my rebuild. Next steps are already pointed out:
- replace the poor-wired RS232 connection with a better one
- Add cooling fans to my build (done)
- Become familiar with ODT; There are some sites to check (done)
- Get closer to PDP11 assembler code (done. Erm. Ok yeah, not. To become really acquainted, could last a life. So not done but: Moved Forward.)
- Test out my second CPU board (done, does work after heavy cleaning)
- Test out my boardless PDP11 CPU I’ve got (done, chip is ok)
- New action item: Check what happened to my first CPU board (it broke, oh no, while I was typing). Where is my SALEA-Clone (what it has 8 bits only :-( ). And I sold my one hundred and what line Tektronix Logic Analyzer years ago… The HP Logic Analyzer also left. Puh. Hard work.
After these steps I want to:
- Try to get the complex board M8047 MXV11-A Multi Purpose Card working
- Connect a virtual tape drive running on my Notebook via M8047
- Boot RT-11 operating system from tape drive
- Do some assembler code programming using DECs Macro-11 assembler
- Make a virtual tape drive from an Arduino, a ATMega or an Raspberry, whatever is least effort
- Test out floating point unit
Reading the PROMs from the M8047 MXV11-A Multi Purpose Card
This board has DEC Boot PROMs, two sockets for up to 2x4 KBytes.
For the two PROMs on the board, I could find the DEC part numbers 23-03901-00 and 23-04001-00 on them, which are 6341 Chips with 512x8 Bytes each. These ROMs are MXV 11-A2 Boot ROMs for RX02, RX01, or TU58
With My Batronix Barlino II Eprommer I was able to read out both ROMs. I need to create a small adapter. The PROMs contain LO and HI byte of a PDP word.
The chip numbered with E67 (“outer” one) has HI bytes.
After reading out both PROMs, the original boot code could be recreated by merging both data sets into one file.
Result is a 512 word file, with size of 1024 bytes of course.
This file can be disassembled by a PDP11 disassembler.
I can currently not verify that the data is 100% valid. The PROMs were burned in 1981 or later, I suspect not much later than that, because newest date code on the board is from 1980.
So as of today, 2022, these PROMs keep their content for, ehm, 42 years. Wow.
That’s what a disassembler dumps out from my file. There are some “invalid opcode” lines.
;
; pdp11dasm version 0.0.3
; disassembly of output-lo-hi
;
000000: 012700 000340 mov #340,r0 ; @.`.
000004: 106400 mtps r0 ; ..
000006: 000005 reset ; ..
000010: 111701 movb (r7),r1 ; A.
000012: 005004 clr r4 ; ..
000014: 012721 173032 mov #173032,(r1)+ ; Q..v
000020: 010011 mov r0,(r1) ; ..
000022: 011706 mov (r7),r6 ; F.
000024: 011414 mov (r4),(r4) ; ..
000026: 005724 tst (r4)+ ; T.
000030: 000775 br 24 ; }.
;
000032: 005744 tst -(r4) ; d.
000034: 005003 clr r3 ; ..
000036: 005002 clr r2 ; ..
000040: 010212 mov r2,(r2) ; ..
000042: 005722 tst (r2)+ ; R.
000044: 020204 cmp r2,r4 ; .
000046: 101774 blos 40 ; |.
000050: 024202 cmp -(r2),r2 ; .(
000052: 001401 beq 56 ; ..
000054: 000000 halt ; ..
;
000056: 005702 tst r2 ; B.
000060: 001373 bne 50 ; {.
000062: 010322 mov r3,(r2)+ ; R.
000064: 020204 cmp r2,r4 ; .
000066: 101775 blos 62 ; }.
000070: 005103 com r3 ; C.
000072: 074342 xor -(r2),r3 ; bx
000074: 005112 com (r2) ; J.
000076: 001401 beq 102 ; ..
000100: 000000 halt ; ..
;
000102: 005103 com r3 ; C.
000104: 074312 xor (r2),r3 ; Jx
000106: 005702 tst r2 ; B.
000110: 001367 bne 70 ; w.
000112: 005103 com r3 ; C.
000114: 001362 bne 62 ; r.
000116: 010406 mov r4,r6 ; ..
000120: 004567 000574 jsr r5,720 ; w.|.
000124: 173300 subf f3,r0 ; @v
000126: 174400 divf f0,r0 ; .y
000130: 012702 000010 mov #10,r2 ; B...
000134: 012700 174404 mov #174404,r0 ; @..y
000140: 012720 000013 mov #13,(r0)+ ; P...
000144: 004567 000074 jsr r5,244 ; w.<.
000150: 000004 iot ; ..
000152: 032711 000001 bit #1,(r1) ; I5..
000156: 001011 bne 202 ; ..
000160: 016103 000006 mov 6(r1),r3 ; C...
000164: 042703 177730 bic #177730,r3 ; CEX.
000170: 001443 beq 300 ; #.
000172: 022703 000006 cmp #6,r3 ; C%..
000176: 101440 blos 300 ; .
000200: 000755 br 134 ; m.
;
000202: 004514 jsr r5,(r4) ; L.
000204: 000010 invalid opcode ; ..
000206: 011003 mov (r0),r3 ; ..
000210: 042703 000177 bic #177,r3 ; CE..
000214: 005203 inc r3 ; ..
000216: 010340 mov r3,-(r0) ; `.
000220: 004514 jsr r5,(r4) ; L.
000222: 000006 rtt ; ..
;
000224: 005037 174402 clr @#174402 ; ...y
000230: 005020 clr (r0)+ ; ..
000232: 012710 177400 mov #177400,(r0) ; H...
000236: 004514 jsr r5,(r4) ; L.
000240: 000014 invalid opcode ; ..
000242: 000413 br 272 ; ..
;
000244: 010704 mov r7,r4 ; D.
000246: 012511 mov (r5)+,(r1) ; I.
000250: 032711 100200 bit #100200,(r1) ; I5..
000254: 001775 beq 250 ; }.
000256: 100401 bmi 262 ; ..
000260: 000205 rts r5 ; ..
;
000262: 005726 tst (r6)+ ; V.
000264: 077255 sob r2,134 ; -~
000266: 000000 halt ; ..
;
000270: 000713 br 120 ; K.
;
000272: 005000 clr r0 ; ..
000274: 004567 000406 jsr r5,706 ; w...
000300: 004567 000414 jsr r5,720 ; w...
000304: 173442 cmpf f0,-(r2) ; "w
000306: 177412 ldcdf f0,(r2) ; ..
000310: 004567 000430 jsr r5,744 ; w...
000314: 005003 clr r3 ; ..
000316: 012701 177412 mov #177412,r1 ; A...
000322: 010311 mov r3,(r1) ; I.
000324: 005041 clr -(r1) ; !.
000326: 012741 177400 mov #177400,-(r1) ; a...
000332: 012741 000005 mov #5,-(r1) ; a...
000336: 032711 100200 bit #100200,(r1) ; I5..
000342: 001775 beq 336 ; }.
000344: 100010 bpl 366 ; ..
000346: 012711 000001 mov #1,(r1) ; I...
000352: 105711 tstb (r1) ; I.
000354: 100376 bpl 352 ; ~.
000356: 062703 020000 add #20000,r3 ; Ce.
000362: 103355 bcc 316 ; m.
000364: 000426 br 442 ; ..
;
000366: 010300 mov r3,r0 ; @.
000370: 006300 asl r0 ; @.
000372: 006100 rol r0 ; @.
000374: 006100 rol r0 ; @.
000376: 006100 rol r0 ; @.
000400: 004567 000302 jsr r5,706 ; w.B.
000404: 000764 br 356 ; t.
;
000406: 004567 000306 jsr r5,720 ; w.F.
000412: 173120 subf f1,(r0)+ ; Pv
000414: 177000 ldcif f0,r0 ; .~
000416: 005011 clr (r1) ; ..
000420: 012700 001000 mov #1000,r0 ; @...
000424: 016040 157776 mov 157776(r0),-(r0) ; .~_
000430: 005700 tst r0 ; @.
000432: 001374 bne 424 ; |.
000434: 004567 000246 jsr r5,706 ; w.&.
000440: 000627 br 120 ; ..
;
000442: 004567 000252 jsr r5,720 ; w.*.
000446: 173406 cmpf f0,r6 ; .w
000450: 177172 004567 ldcif f1,@4567(r2) ; z~w.
000454: 000272 invalid opcode ; :.
000456: 005046 clr -(r6) ; &.
000460: 000404 br 472 ; ..
;
000462: 012700 000020 mov #20,r0 ; @...
000466: 074016 xor (r6),r0 ; .x
000470: 001746 beq 406 ; f.
000472: 111600 movb (r6),r0 ; ..
000474: 004567 000154 jsr r5,654 ; w.l.
000500: 000013 invalid opcode ; ..
000502: 111102 movb (r1),r2 ; B.
000504: 100366 bpl 462 ; v.
000506: 012703 000100 mov #100,r3 ; C.@.
000512: 032702 000040 bit #40,r2 ; B5 .
000516: 001403 beq 526 ; ..
000520: 052700 000400 bis #400,r0 ; @U..
000524: 006303 asl r3 ; C.
000526: 005002 clr r2 ; ..
000530: 012705 000001 mov #1,r5 ; E...
000534: 004567 000114 jsr r5,654 ; w.L.
000540: 000007 mfpt ; ..
000542: 010511 mov r5,(r1) ; I.
000544: 004514 jsr r5,(r4) ; L.
000546: 012711 000001 mov #1,(r1) ; I...
000552: 004514 jsr r5,(r4) ; L.
000554: 100714 bmi 406 ; L.
000556: 004567 000072 jsr r5,654 ; w.:.
000562: 000003 bpt ; ..
000564: 032737 004000 177170 bit #4000,@#177170 ; _5..x~
000572: 001413 beq 622 ; ..
000574: 010311 mov r3,(r1) ; I.
000576: 004514 jsr r5,(r4) ; L.
000600: 010211 mov r2,(r1) ; ..
000602: 004514 jsr r5,(r4) ; L.
000604: 122525 cmpb (r5)+,(r5)+ ; U%
000606: 060302 add r3,r2 ; B`
000610: 060302 add r3,r2 ; B`
000612: 022702 001000 cmp #1000,r2 ; B%..
000616: 001346 bne 534 ; f.
000620: 000404 br 632 ; ..
;
000622: 006303 asl r3 ; C.
000624: 111122 movb (r1),(r2)+ ; R.
000626: 004514 jsr r5,(r4) ; L.
000630: 077303 sob r3,624 ; C~
000632: 005000 clr r0 ; ..
000634: 105716 tstb (r6) ; N.
000636: 001401 beq 642 ; ..
000640: 005200 inc r0 ; ..
000642: 005741 tst -(r1) ; a.
000644: 004567 000036 jsr r5,706 ; w...
000650: 005721 tst (r1)+ ; Q.
000652: 000703 br 462 ; C.
;
000654: 012504 mov (r5)+,r4 ; D.
000656: 050004 bis r0,r4 ; .P
000660: 010437 177170 mov r4,@#177170 ; ..x~
000664: 010704 mov r7,r4 ; D.
000666: 005741 tst -(r1) ; a.
000670: 032711 000240 bit #240,(r1) ; I5 .
000674: 001775 beq 670 ; }.
000676: 005721 tst (r1)+ ; Q.
000700: 000205 rts r5 ; ..
;
000702: 005737 170000 tst @#170000 ; _..p
000706: 022737 000240 000000 cmp #240,@#0 ; _% ...
000714: 001024 bne 766 ; ..
000716: 005007 clr r7 ; ..
000720: 012537 000004 mov (r5)+,@#4 ; _...
000724: 012737 000340 000006 mov #340,@#6 ; _.`...
000732: 012501 mov (r5)+,r1 ; A.
000734: 012706 004000 mov #4000,r6 ; F...
000740: 005711 tst (r1) ; I.
000742: 000115 jmp (r5) ; M.
;
000744: 004517 jsr r5,(r7) ; O.
000746: 004517 jsr r5,(r7) ; O.
000750: 012700 000004 mov #4,r0 ; @...
000754: 010604 mov r6,r4 ; ..
000756: 005003 clr r3 ; ..
000760: 010710 mov r7,(r0) ; H.
000762: 010406 mov r4,r6 ; ..
000764: 077332 sob r3,702 ; Z~
000766: 000205 rts r5 ; ..
;
000770: 000000 halt ; ..
000774: 000000 halt ; ..
...
001776: 000000 halt ; ..
M8186 CPU board problems
The board I have used the first days suddenly stopped working. I have a second board, that is that what was part of the OBA11 machine. This also had contact issues in the beginning, and I switched the failing one with the second board.
The issue with the first board was, that it seems not to transmit data correctly. If I switch the machine on, then some well known characters should be sent to the console. But console gets only a SI,STX sequence. Because the serial board receives these characters, it was obviously correctly addressed, so I guess the addressing lines are all ok. But the data path somehow is faulty.
What a pity. I had a short look at the schematics of the CPU board, but this is a complex thing and would need MUCH more effort to trace the bug.
Let’s hope the second CPU board has no problems.
Further reading
https://www.pdp-11.nl/ - Great info and also software site