Multifunction Board

Early PDP-11 systems had boards for each individual function. There was a board for the line-time clock even it was only a single register. Also a boot ROM (in early stages this was just a diode matrix) filled a complete board. Later with smaller systems that only had a limited number of slots there were several multifunction boards. The latest systems then integrated all these functions directly on the CPU board.

In order to not overload the CPU board with features I decided to build a dedicated board that adds all the functions which are required for a complete PDP-11 system.

  • Console and two DLV11
  • BootROM
  • LTC Register
  • TOY (compatible with the clock of the PDP-11/93) using a DS1215 RTC

System Bus

Description

This board also uses it's own version of the Q-Bridge. The MCU used is a Atmega1280. Most registers are implemented in software. Some registers like the DLV11 control registers, LTC and TOY are implemented directly in the CPLD Initially it was planned to add a TU-58 Emulation. The hardware, SD-Card interface, is included but the software does not yet implement this feature.

Console and DLV11 Emulation

This is a very simple emulation of a serial interface. Each DLV11 is represented by four registers.

  • Receiver Control/Status Register
  • Receiver Buffer Register
  • Transmitter Control/Status Register
  • Transmitter Buffer Register

The Q-Bridge logic translates DATI and DATO/DATOB to the buffer registers to interrupts of the MCU. The MCU then moves the low byte of the data between the Q-Bus and the USART data register. The rest of the DLV11 interface is integrated into the Q-Bridge CPLD.

The Atmega1280 has 4 USARTS. The first is mapped to the console and the next two are mapped to two DLV11. The forth is initially mapped to the monitor programm running in the Atmega1280, but can be dynamically mapped to another DLV11. Later a TU-58 emulation can be mapped to either DLV11.

The interrupt logic is also completely integrated in the CPLD. CSR and vector addresses are programmed into the CPLD. Instead of jumpers you need to create a new CPLD design file.

Baud-rate and character format can be set in the microcontroller program.

BootROM

The multifunction board also emulates a bootrom at 165000(8) and 173000(8). Whenever the PDP‐11 performs a word read to one of the BootROM ranges an interrupt is generated for the MCU and the MCU then places the ROM data onto the Q-Bus. The ROM data is part of the Flash Memory of the Atmega1280. Due to the nature of the Q-Bridge access to the ROM it is not very fast with about 3µs access time. For Boot ROMs this is fast enough.

LTC Register

Another part of the multifunction board is the LTC register at the standard address. The clock is derived from the microcontroller.

TOY

The PDP‐11/93 introduced a TOY (time of year) real-time clock using the phantom clock chip DS1215N. This clock chip is activated by writing a patter to the data port. Once the pattern is recognized you can either read the real-time clock or set the real-time clock. Unfortunately RSX-11MPlus only recognizes the TOY if the CPU module is identified as a PDP‐11/93. However I modified Oleg Safiullin's TOY which can be used in the STARTUP.CMD to propose the current time in the RTC to be set as the system time (just hit return when asked for the time). I added an option so you can actually set the RTC to the current system time in order to set or adjust the RTC.

Schematic

The PDP-11 Hack

The PDP-11 Hack

The PDP-11 Hack

The PDP-11 Hack

CPLD Design

Name     MFV-11B ;
PartNo   00 ;
Date     01.04.2018 ;
Revision 01 ;
Designer 	 ;
Company  PRIVAT ;
Assembly None ;
Location ATHOME ;

/*
    MFV-11B is the follow-up of the MFV-11. It will have the following
    features:
	
    -   Small Bootroms at 173000 and 165000
    -   Console (simple SLU without break)
    -   SLUA, SLUB two DLV11(-F, -E?) with break support
    -   LTC
    -   Additional Status Register, implementing bit 8 for TOY
					
        Register	Read                    Write
        --------	----                    -----
        0           Read DAL7..0            Write D7..0
        1           Read DAL15..0           Write D15..8
        2           Read A8..1              Set TXRDYA
        3           Read Status             Set TXRDYB
        4           ACK INT0                Set RXDRA
        5           ACK INT1                Set RXDRB
        6           ACK INT2                Set TXRDYC console
        7                                   Set RXDRC console
        8
        9                                   Write D15..8 mapped to UCSRnA

    2018-05-16  Version 1.0 MFV-11B
    2018-08-02  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                !!!!!!!!!!!!!!!!!!!!!!!!!!!!! DO NOT CHANGE DO NOT CHANGE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                This design file matches the version loaded to the CPLD of the MFV11-B board that supports 
                RT11 V5.7 and RSX-11Mplus V4.6 BL87

PROPERTY ATMEL {cascade_logic=ON};
 */
PROPERTY ATMEL {preassign=KEEP};
PROPERTY ATMEL {open_collector=BRPLY, BIRQ, BIRQ5, BIRQ6, BEVNT};

$INCLUDE C:\Wincupl\WinCupl\MFV-11B\MFV-11B-PIN-V1-0-3.txt
$INCLUDE C:\Wincupl\WinCupl\MFV-11B\SLU-DEFS.txt

PINNODE     =  [D15..0]      ; /* ROM Data Register                                             */

PINNODE     =  TXRDYA        ; /* UART A Transmit Ready                                         */
PINNODE     =  BRKA          ; /* UART A Send Break                                             */

PINNODE     =  TXRDYB        ; /*                                                               */
PINNODE     =  BRKB          ; /*                                                               */

PINNODE     =  RXIEA         ; /* receive interrupt enable flag                                 */
PINNODE     =  RXIRQA        ; /* interrupt flag latched                                        */
PINNODE     =  RXACKA        ; /* interrupt acknowledge flag                                    */

PINNODE     =  RXDRA         ; /*                                                               */

PINNODE     =  TXIEA         ; /* transmit interrupt enable flag                                */
PINNODE     =  TXIRQA        ; /* interrupt flag latched                                        */
PINNODE     =  TXACKA        ; /* interrupt acknowledge flag                                    */

PINNODE     =  RXIEB         ; /* receive interrupt enable flag                                 */
PINNODE     =  RXIRQB        ; /* interrupt flag latched                                        */
PINNODE     =  RXACKB        ; /* interrupt acknowledge flag                                    */

PINNODE     =  RXDRB         ; /*                                                               */

PINNODE     =  TXIEB         ; /* transmit interrupt enable flag                                */
PINNODE     =  TXIRQB        ; /* interrupt flag latched                                        */
PINNODE     =  TXACKB        ; /* interrupt acknowledge flag                                    */

PINNODE     =  TXRDYC        ; /*                                                               */
PINNODE     =  RXDRC         ; /*                                                               */

PINNODE     =  TXIEC         ; /* transmit interrupt enable flag                                */
PINNODE     =  TXIRQC        ; /* interrupt flag latched                                        */
PINNODE     =  TXACKC        ; /* interrupt acknowledge flag                                    */

PINNODE     =  RXIEC         ; /* receive interrupt enable flag                                 */
PINNODE     =  RXIRQC        ; /* interrupt flag latched                                        */
PINNODE     =  RXACKC        ; /* interrupt acknowledge flag                                    */

PINNODE     =  KWIE          ; /* KW-11 Interrupt Enable Bit                                    */
PINNODE     =  KWSET;

PINNODE     =  [A8..0]       ; /*                                                               */
PINNODE     =  SLU           ; /* Either SLU selected                                           */
PINNODE     =  ROM           ; /* Either ROM selected                                           */
PINNODE     =  ALT           ; /* Other selected                                                */
PINNODE     =  SLUC          ; /* Latch to save the CONSOLE sel'd status                        */
PINNODE     =  TOY           ; /* Time of Year selected                                         */
PINNODE     =  KW            ; /* Latch to save the Line Time Clock sel'd status                */
PINNODE     =  CSR           ; /* Any CSR selected                                              */

PINNODE     =  INT0CE        ; /* Internal Variables                                            */
PINNODE     =  INT1CE        ; /* Internal Variables                                            */

PINNODE     =  RS0; 		/* 65 */
PINNODE     =  RS1; 		/* 64 */
PINNODE     =  RS2; 		/* 67 */
PINNODE     =  RS3; 		/* 80 */

/*
	Register offset defintions. 
 */
$DEFINE   RCSR  !A2 & !A1 & !A0

$DEFINE   RBUF  !A2 &  A1

$DEFINE   XCSR   A2 & !A1 & !A0

$DEFINE   XBUF   A2 &  A1 & !A0

/*
	Other address definitions
 */
$DEFINE   BOOTROM    'o'173xxx          /* BOOT ROM Address Range, x means wildcards   */
$DEFINE   BOOTROM2   'o'165xxx          /* 2nd BOOT ROM Address window                 */
$DEFINE   TOYREG     'o'177526..177527  /* Time of Year clock                          */
$DEFINE   KW11       'o'177546..177547  /* Line Time Clock CSR Address                 */

/*
	Field definitions
 */
FIELD     ADDR      = [A8..0];          /* Latched address used for register and ROM address    */
FIELD     RS        = [RS3..0];         /* Register Select Address for Atmega 162 reads/writes  */
FIELD     ROMADDR   = [A8..1];          /* Sub-field, ROM Word address only uses 8 bits         */
FIELD     IOADDR    = [BDAL12..0];      /* Access to IO Page only requires address lines 0..12  */
/*
    In case we need an inverted address/data bus. E.g. when interfacing to the real Q-Bus
    or to the KM1801VM2, perhaps we will consider to change the polarity of the address/data
    bus on our Q-Bus/64 as well. INV is used for input (.io extension) and INW is used for
    equations that set DAL0..15.
 */
$DEFINE INV      
$DEFINE INW      
/*
	On every bus cycle we latch the address and the requested CSR
 */
ADDR.d    =  INV [BDAL8..0].io;
ADDR.ck   =  BSYNC;

KW.d      =  BBS7  & INV IOADDR.io:[KW11];
KW.ck     =  BSYNC;

SLU.d     =  BBS7  & INV IOADDR.io:[DL11A]
          #  BBS7  & INV IOADDR.io:[DL11B];
SLU.ck    =  BSYNC;

SLUC.d    =  BBS7  & INV IOADDR.io:[DL11C];
SLUC.ck   =  BSYNC;

ROM.d     =  BBS7  & INV IOADDR.io:[BOOTROM]
          #  BBS7  & INV IOADDR.io:[BOOTROM2];
ROM.ck    =  BSYNC;

ALT.d     =  BBS7  & INV IOADDR.io:[DL11B]
          #  BBS7  & INV IOADDR.io:[BOOTROM2];
ALT.ck    =  BSYNC;

TOY.d      =  BBS7  & INV IOADDR.io:[TOYREG];
TOY.ck     =  BSYNC;

CSR.d      =  BBS7  & INV IOADDR.io:[DL11A]
           #  BBS7  & INV IOADDR.io:[DL11B]
           #  BBS7  & INV IOADDR.io:[DL11C]
           #  BBS7  & INV IOADDR.io:[TOYREG]
           #  BBS7  & INV IOADDR.io:[KW11];
CSR.ck     =  BSYNC;

/*
	When the PDP-11 writes the transmit buffer register we will rise INT0.
	The MCU then takes the byte and writes it to the USART data register.
	
	Note: only writes to the lower address interrupt the MCU writes to the
	high byte does nothing and does not make sense.
 */
INT0CE    =  BWTBT  &  BBS7 & INV IOADDR.io:[XBUFA]
          #  BWTBT  &  BBS7 & INV IOADDR.io:[XBUFB]
          #  BWTBT  &  BBS7 & INV IOADDR.io:[XBUFC];

INT0.d    =  INT0CE;
INT0.ck   =  BSYNC;
INT0.ar   =  RS:['d'4] &  RD
          #  BINIT;

/*
	When the PDP-11 reads the receive buffer register we will rise INT1.
	The MCU will then write the error bits and the received character to
	the internal data register.
	
 */
INT1CE    = !BWTBT  &  BBS7 & INV IOADDR.io:[RBUFA]
          # !BWTBT  &  BBS7 & INV IOADDR.io:[RBUFB]
          # !BWTBT  &  BBS7 & INV IOADDR.io:[RBUFC];

INT1.d    =  INT1CE;
INT1.ck   =  BSYNC;
INT1.ar   =  RS:['d'5] &  RD
          #  BINIT;
 
/*
	INT2 is used as a ROM read request. ALT is used to distinguish between the
	ROM ranges 165xxx and 173xxx.
 */
INT2.d    =           BBS7 & INV IOADDR.io:[BOOTROM]
          #           BBS7 & INV IOADDR.io:[BOOTROM2];
INT2.ck   =  BSYNC;
INT2.ar   =  RS:['d'6] &  RD
          #  BINIT; 

/*
	We only have internal registers therefore we only latch the minimal amount of
	address bits of the external memory interface.
 */
RS.l      =  [AD3..0].io;
RS.le     =  ALE;

/*
	The Data Ready (DR) bit is set by the MCU when a character has been received.
	When the PDP-11 reads the receive buffer (RBUF) register the flag will be
	cleared.
 */
RXDRA.ar   =  SLU & !ALT &  BSYNC &  RBUF &  BDIN
           #  BINIT;
RXDRA.ce   =  RS:['d'4];
RXDRA.ck   = !WR;
RXDRA.d    = 'b'1;

RXDRB.ar   =  SLU &  ALT &  BSYNC &  RBUF &  BDIN
           #  BINIT;
RXDRB.ce   =  RS:['d'5];
RXDRB.ck   = !WR;
RXDRB.d    = 'b'1;

/*

 */
RXDRC.ar   =  SLUC       &  BSYNC &  RBUF &  BDIN
           #  BINIT;
RXDRC.ce   =  RS:['d'7];
RXDRC.ck   = !WR;
RXDRC.d    = 'b'1;

/*
	Transmitter Status and Data
	
	Whenever the CPU writes transmitter date the Transmitter Ready
	bit needs to be cleared. If the MCU has finished trasmitting
	data it will have to set the Transmitter Ready bit

	Whenever the CPU writes to the Transmitter Buffer register we
	generate an interrupt. This is a write only register and all
	the MCU has to do is fetch DAL7..0. Reading XBUF reas always 0.
 */
TXRDYA.ce =  SLU & !ALT &  XBUF;
TXRDYA.ap =  RS:['d'2]  & WR
          #  BINIT;
TXRDYA.ck = !BDOUT;
TXRDYA.d  = 'b'0;

TXRDYB.ce =  SLU &  ALT &  XBUF;
TXRDYB.ap =  RS:['d'3]  & WR
          #  BINIT;
TXRDYB.ck = !BDOUT;
TXRDYB.d  = 'b'0;

TXRDYC.ce =  SLUC       &  XBUF;
TXRDYC.ap =  RS:['d'6]  & WR
          #  BINIT;
TXRDYC.ck = !BDOUT;
TXRDYC.d  = 'b'0;

/*
	Break Support is added in Hardware. TXD of the USARTS of the MCU
	are passed through the CPLD which will create a continuous SPACE
	signal when BRK is set in the XCRS
 */
BRKA.d    =  INV BDAL0.io;
BRKA.ck   = !BDOUT;
BRKA.ce   =  SLU & !ALT & XCSR;
BRKA.ar   =  BINIT;

BRKB.d    =  INV BDAL0.io;
BRKB.ck   = !BDOUT;
BRKB.ce   =  SLU &  ALT & XCSR;
BRKB.ar   =  BINIT;

TXDAO     =  TXDAI & !BRKA;
TXDBO     =  TXDBI & !BRKB;

/*
	MCU interface to read data from the PDP-11 and the CPLD via the
	multiplexed address/data bus of the external memory interface. 
	
	There are 4 registers the MCU can read, the lower byte of the
	current data bus, the upper byte of the current data bus, the
	latched address A1..A8, which correspond to the ROM address and
	the status

	The status contains a set of bits potentially useful for the MCU.
 */
	
[AD7..0]  =  INV [BDAL7..0].io  & RS:['d'0]
          #  INV [BDAL15..8].io & RS:['d'1]
          #      ROMADDR        & RS:['d'2];

APPEND
AD6       =  RXDRC   & RS:['d'3];

APPEND
AD5       =  RXDRB   & RS:['d'3];

APPEND
AD4       =  RXDRA   & RS:['d'3];


APPEND
AD2       =  SLUC    & RS:['d'3];

APPEND
AD1       =  SLU     & RS:['d'3];

APPEND
AD0       =  ALT     & RS:['d'3];
	
[AD7..0].oe= RD;

/*
	Interrupt Enable Bits and interrupt controller (built after the logic of a DC003)
 */
RXIEA.d     =  INV BDAL6.io;                        /* Interrupt enable flag, only when this flag is     */
RXIEA.ck    = !BDOUT;                               /* set an interrupt will be requested                */
RXIEA.ce    =  SLU    & !ALT   & RCSR;
RXIEA.ar    =  BINIT;

RXIRQA.d    =  'b'0;                                /* Note the IRQ flag are inverted!                   */
RXIRQA.ck   =  RXIEA  & RXDRA;                      /* The IRQ flag is actually only used to detect a    */
RXIRQA.ap   =  RXACKA & BIAKI;                      /* pending interrupt when RXIE is set, once set it   */
RXIRQA.ar   =  BINIT;                               /* will stay set, only BINIT resets the flag         */

RXACKA.d    = !RXIRQA &  RXIEA &  RXDRA;            /* ACK remembers that we requested an interrupt      */
RXACKA.ck   =  BDIN;                                /* and that it is our interrupt acknowledge cycle    */
RXACKA.ar   =  BINIT;

TXIEA.d     =  INV BDAL6.io; 
TXIEA.ck    = !BDOUT;
TXIEA.ce    =  SLU    & !ALT   & XCSR;
TXIEA.ar    =  BINIT;

TXIRQA.d    =  'b'0;
TXIRQA.ck   =  TXIEA  & TXRDYA;
TXIRQA.ap   =  TXACKA & BIAKI  & !RXACKA;
TXIRQA.ar   =  BINIT;

TXACKA.d    = !TXIRQA &  TXIEA &  TXRDYA;
TXACKA.ck   =  BDIN;
TXACKA.ar   =  BINIT;
/*

 */
RXIEB.d     =  INV BDAL6.io;                        /* Interrupt enable flag, only when this flag is     */
RXIEB.ck    = !BDOUT;                               /* set an interrupt will be requested                */
RXIEB.ce    =  SLU    &  ALT   & RCSR;
RXIEB.ar    =  BINIT;

RXIRQB.d    =  'b'0;                                /* Note the IRQ flag are inverted!                   */
RXIRQB.ck   =  RXIEB  & RXDRB;                      /* The IRQ flag is actually only used to detect a    */
RXIRQB.ap   =  RXACKB & BIAKI;                      /* pending interrupt when RXIE is set, once set it   */
RXIRQB.ar   =  BINIT;                               /* will stay set, only BINIT resets the flag         */

RXACKB.d    = !RXIRQB &  RXIEB &  RXDRB;            /* ACK remembers that we requested an interrupt      */
RXACKB.ck   =  BDIN;                                /* and that it is our interrupt acknowledge cycle    */
RXACKB.ar   =  BINIT;

TXIEB.d     =  INV BDAL6.io; 
TXIEB.ck    = !BDOUT;
TXIEB.ce    =  SLU    &  ALT   & XCSR;
TXIEB.ar    =  BINIT;

TXIRQB.d    =  'b'0;
TXIRQB.ck   =  TXIEB  & TXRDYB;
TXIRQB.ap   =  TXACKB & BIAKI  & !RXACKB;
TXIRQB.ar   =  BINIT;

TXACKB.d    = !TXIRQB &  TXIEB &  TXRDYB;
TXACKB.ck   =  BDIN;
TXACKB.ar   =  BINIT;

/*

 */
RXIEC.d     =  INV BDAL6.io;                        /* Interrupt enable flag, only when this flag is     */
RXIEC.ck    = !BDOUT;                               /* set an interrupt will be requested                */
RXIEC.ce    =  SLUC            & RCSR;
RXIEC.ar    =  BINIT;

RXIRQC.d    =  'b'0;                                /* Note the IRQ flag are inverted!                   */
RXIRQC.ck   =  RXIEC  & RXDRC;                      /* The IRQ flag is actually only used to detect a    */
RXIRQC.ap   =  RXACKC & BIAKI;                      /* pending interrupt when RXIE is set, once set it   */
RXIRQC.ar   =  BINIT;                               /* will stay set, only BINIT resets the flag         */

RXACKC.d    = !RXIRQC &  RXIEC &  RXDRC;            /* ACK remembers that we requested an interrupt      */
RXACKC.ck   =  BDIN;                                /* and that it is our interrupt acknowledge cycle    */
RXACKC.ar   =  BINIT;

TXIEC.d     =  INV BDAL6.io; 
TXIEC.ck    = !BDOUT;
TXIEC.ce    =  SLUC            & XCSR;
TXIEC.ar    =  BINIT;

TXIRQC.d    =  'b'0;
TXIRQC.ck   =  TXIEC  & TXRDYC;
TXIRQC.ap   =  TXACKC & BIAKI  & !RXACKC;
TXIRQC.ar   =  BINIT;

TXACKC.d    = !TXIRQC &  TXIEC &  TXRDYC;
TXACKC.ck   =  BDIN;
TXACKC.ar   =  BINIT;

BIRQ        = !RXIRQA &  RXIEA  &  RXDRA
            # !TXIRQA &  TXIEA  &  TXRDYA
            # !RXIRQB &  RXIEB  &  RXDRB
            # !TXIRQB &  TXIEB  &  TXRDYB
            # !RXIRQC &  RXIEC  &  RXDRC
            # !TXIRQC &  TXIEC  &  TXRDYC;

BIAKO       = BIAKI   & !RXACKA & !TXACKA & !RXACKB & !TXACKB & !RXACKC & !TXACKC;

/*
    Line Time Clock

    The line time clock drives the BEVENT line of the bus periodically. The falling edge sets the
    event flip-flop on the CPU board which then causes the CPU to trap via the vector at address 100.
    The CPU will acknowledge the EVENT using a special GPWRITE code which clears the EVENT flip-flop
    on the CPU board. 
 */
KWIE.d     =  INV BDAL6.io;                         /* Interrupt enable flag, only when this flag is set */
KWIE.ck    = !BDOUT;                                /* we will drive the BEVENT line                     */
KWIE.ce    =  KW;
KWIE.ar    =  BINIT;
/*
    A flag will be set each time the LTC asserts BEVENT. This flag can only be cleared by writing
    a 0 to bit 7 of the CSR
 */
KWSET.ck   =  LTC;
KWSET.d    = 'b'1;
KWSET.ar   =  KW &  BDOUT & INV(!BDAL7.io);

BEVNT      =  LTC & KWIE;
/*
    Q-Bus read data register low byte
 */
[D7..0].d  =  [AD7..0].io;
[D7..0].ck = !WR;
[D7..0].ce =  RS:['d'0];

/*
    DAL7 and DAL0 
 */
[BDAL7..0]= INV(!BIAKI &  ROM                        & [D7..0]
          #     !BIAKI &  SLU              &  RBUF   & [D7..0]
          #     !BIAKI &  SLUC             &  RBUF   & [D7..0]
          #     !BIAKI &  SLU    & !ALT    &  RCSR   & [RXDRA,  RXIEA, 'b'0, 'b'0, 'b'0, 'b'0, 'b'0, 'b'0]
          #     !BIAKI &  SLU    &  ALT    &  RCSR   & [RXDRB,  RXIEB, 'b'0, 'b'0, 'b'0, 'b'0, 'b'0, 'b'0]
          #     !BIAKI &  SLUC             &  RCSR   & [RXDRC,  RXIEC, 'b'0, 'b'0, 'b'0, 'b'0, 'b'0, 'b'0]
          #     !BIAKI &  SLU    & !ALT    &  XCSR   & [TXRDYA, TXIEA, 'b'0, 'b'0, 'b'0, 'b'0, 'b'0, BRKA]
          #     !BIAKI &  SLU    &  ALT    &  XCSR   & [TXRDYB, TXIEB, 'b'0, 'b'0, 'b'0, 'b'0, 'b'0, BRKB]
          #     !BIAKI &  SLUC             &  XCSR   & [TXRDYC, TXIEC, 'b'0, 'b'0, 'b'0, 'b'0, 'b'0, 'b'0]
          #     !BIAKI &  KW                         & ['b'0,   KWIE,  'b'0, 'b'0, 'b'0, 'b'0, 'b'0, 'b'0]
          #      BIAKI &  RXACKC                                                   & RXVECC
          #      BIAKI & !RXACKC &  TXACKC                                         & TXVECC
          #      BIAKI & !RXACKC & !TXACKC &  RXACKA                               & RXVECA
          #      BIAKI & !RXACKC & !TXACKC & !RXACKA &  TXACKA                     & TXVECA
          #      BIAKI & !RXACKC & !TXACKC & !RXACKA & !TXACKA &  RXACKB           & RXVECB
          #      BIAKI & !RXACKC & !TXACKC & !RXACKA & !TXACKA & !RXACKB &  TXACKB & TXVECB);

/*
    Q-Bus read data register high byte

    There are two addresses to write the high-byte, the first is form ROM reads
    and the second is for RBUF reads. When RBUF is read the MCU just writes a 
    copy of UCSRn0, the CPLD then maps the bits to the correct data bits. 

        FEn     = 4     Framing Error   ->  D13
        DORn    = 3     Data Overrun    ->  D14
        UPEn    = 2     Parity Error    ->  D12

    When the MCU receives a character the RX interrupt only sets RXDR(A,B,C) but
    leaves the control and status registers and data registers untouched. Only
    when the PDP-11 reads RBUF then the MCU will transfer the status bits and the
    data to the Q-Bus.
 */
[D15..8].d   = !RS3  &  [AD7..0].io;
[D15..8].ck  = !WR;
[D15..8].ce  =  RS:['d'1]
             #  RS:['d'9];

APPEND
D15.d        =  RS3  &  AD2.io
             #  RS3  &  AD3.io
             #  RS3  &  AD4.io;

APPEND
D14.d        =  RS3  &  AD3.io;

APPEND
D13.d        =  RS3  &  AD4.io;

APPEND
D12.d        =  RS3  &  AD2.io;

[BDAL15..8] = INW(!BIAKI &  BSYNC  &  ROM          & [D15..8]); /* ROM, ROM2 */

APPEND
BDAL15      = INW(!BIAKI &  BSYNC  &  (SLU # SLUC) &  RBUF &  D15);

APPEND
BDAL14      = INW(!BIAKI &  BSYNC  &  (SLU # SLUC) &  RBUF &  D14);

APPEND
BDAL13      = INW(!BIAKI &  BSYNC  &  (SLU # SLUC) &  RBUF &  D13);

APPEND
BDAL12      = INW(!BIAKI &  BSYNC  &  (SLU # SLUC) &  RBUF &  D12);

APPEND
BDAL8       = INW(!BIAKI &  BSYNC  &  TOY  &  TOYD.io);

/*
    Output Enable for CPU read and interrupt acknowledge cycles.
 */
[BDAL15..0].oe
           = !BIAKI &  BDIN &  BSYNC  &  ROM        /* Read ROM                             */
           # !BIAKI &  BDIN &  BSYNC  &  CSR        /* Read CSR                             */
           #  BIAKI &  BDIN &  RXACKA               /* SLUA Interrupt RX Vector             */
           #  BIAKI &  BDIN &  TXACKA               /* SLUA Interrupt TX Vector             */
           #  BIAKI &  BDIN &  RXACKB               /* SLUB Interrupt RX Vector             */
           #  BIAKI &  BDIN &  TXACKB               /* SLUB Interrupt TX Vector             */
           #  BIAKI &  BDIN &  RXACKC               /* Console Interrupt RX Vector          */
           #  BIAKI &  BDIN &  TXACKC;              /* Console Interrupt TX Vector          */

/*
    Generate RPLY. 

    In case the MCU needs to be alerted the corresponding interrupt is set. The interrupt is cleared
    as soon as the MCU has finished it's task. In other words assert RPLY except during the time
    the interrupt is set
 */
BRPLY      =  BSYNC &  CSR     &  !INT0  &  BDOUT
           #  BSYNC &  CSR     &  !INT1  &  BDIN
           #  BSYNC &  ROM     &  !INT2  &  BDIN
           #  BIAKI &  RXACKA            &  BDIN    /* Vectors are generated by the CPLD    */ 
           #  BIAKI &  TXACKA            &  BDIN    /*                                      */ 
           #  BIAKI &  RXACKB            &  BDIN    /*                                      */ 
           #  BIAKI &  TXACKB            &  BDIN    /*                                      */ 
           #  BIAKI &  RXACKC            &  BDIN    /*                                      */ 
           #  BIAKI &  TXACKC            &  BDIN;   /*                                      */ 

/*
    Interface to TOY chip DS1215, the Phantom Time Chip used in KDJ11-E, the CPLD interfaces to
    the pins CE, OE, WE, D and Q of the DS1215. The register can be addressed at 17777526 and
    bit 8 interfaces with D and Q of the DS1215.
 */
TOYCE      =  TOY &  BSYNC;
TOYD       =  INV(BDAL8.io);
TOYD.oe    =  TOY &  BDOUT;
TOYWE      =  TOY &  BDOUT;
TOYOE      =  TOY &  BDIN;

/*
    Make sure unused interrupts are de-asserted (active high) open collector outputs
 */

BIRQ5 = 'b'0;
BIRQ6 = 'b'0;

MCU Software

For the moment still work in progress. Please contact me if you like to get a preliminary version.