MCU based IO card


Introduction

As mentioned before, the ultimate goal is to run RT-11 from a TU-58 tape. For this I have designed a small expansion card that uses a CPLD ATF1508 and a microcontroller AVR128DB64. The CPLD connects to all expansion slot signals and has an interface to the microcontroller. The microcontroller connects to the data bus and of to the CPLD via the before mentioned interface. The design follows many ideas from my RLV12 emulators. In this chapter I will just present the schematics. The following chapters will gradually add more and more features to the CPLD and eventually start with the firmware of the microcontroller and explain the section of the schematic used for each step.

Breadboard Connector w/ CDP6402

The AVR128DB64 provides a multi-voltage IO port, which is port C. This is very useful, when you have to interface to devices operated at multiple voltages. In our case the MCU operates at 5V as it mostly interfaces with the DCJ11 and the CPLD which operates at 5v as well. Because SD-Cards operate at 3V3 and I want to interface the MCU IO board with an SD-Card in the future, port C is operated at 3V3 using a LDO voltage regulator. Port C provide the SPI to the SD-Card and USART1 that is used to interact with the MCU directly during debugging and configuration. The USART is galvanically isolated using a ADUM1201. When using a USB to TTL/Serial adapter the adapter must provide power to the ADUM1201. The voltage provided by the adapter must be in the range of 3V to 5V.

Breadboard Connector w/ CDP6402

The following shows the first version of the MCU IO based expansion card with the minimal components installed. These are the MCU, the CPLD, the programming connectors for both, the pin header for the serial MCU interface, the voltage regulator to create the 3V3 used for the MVIO port.

Breadboard Connector w/ CDP6402

Note, the CPLD and the microcontroller have a TQFP package with a 0.5mm pitch. Also you will need programmers for the CPLD and the microcontroller. You can also order the PCB with the TQFP packages already assembled. Many manufacturer offer the option to partially assemble PCBs. All other components are either SMD parts that are easy to solder or through hole parts.

CPLD Pin Assignement

Throughout all examples the header section of the CPLD design file is the same. It includes the device header, pin allocation, definition and fields. WinCUPL does not care whether an assignement is used or not.

Name     DCJ11MCUx;
PartNo   00 ;
Date     08.08.2025 ;
Revision 01 ;
Designer cbscpe ;
Company  PRIVAT ;
Assembly None ;
Location Switzerland ;

Device   f1508isptqfp100 ;

PROPERTY ATMEL {preassign = KEEP};
PROPERTY ATMEL {open_collector=ABORT};

/*
	Expansion Card with CPLD and MCU for MCU based IO
	
	A series of experiments using the MCU-V1-1 expansion card to gradually
	build a full blown PDP-11 using the DCJ11 SBC V1-3-x

 */
PIN        78 =  DAL0;		/* Data/Address Line				*/
PIN        77 =  DAL1;		/* Data/Address Line				*/
PIN        76 =  DAL2;		/* Data/Address Line				*/
PIN        68 =  DAL3;		/* Data/Address Line				*/
PIN        67 =  DAL4;		/* Data/Address Line				*/
PIN        65 =  DAL5;		/* Data/Address Line				*/
PIN        64 =  DAL6;		/* Data/Address Line				*/
PIN        63 =  DAL7;		/* Data/Address Line				*/
PIN        61 =  DAL8;		/* Data/Address Line				*/
PIN        60 =  DAL9;		/* Data/Address Line				*/
PIN        58 =  DAL10;		/* Data/Address Line				*/
PIN        57 =  DAL11;		/* Data/Address Line				*/
PIN        56 =  DAL12;		/* Data/Address Line				*/
PIN        55 =  DAL13;		/* Data/Address Line				*/
PIN        54 =  DAL14;		/* Data/Address Line				*/
PIN        53 =  DAL15;		/* Data/Address Line				*/

PIN         1 =  LAIO0;		/* Latched Address Input/Output			*/
PIN         2 =  LAIO1;		/* Latched Address Input/Output			*/
PIN        99 =  LAIO2;		/* Latched Address Input/Output			*/
PIN       100 =  LAIO3;		/* Latched Address Input/Output			*/

PIN        97 =  LBS0;		/* Latched Bank Select				*/
PIN        98 =  LBS1;		/* Latched Bank Select				*/

PIN        90 = !ALE;		/* Address Latch Enable				*/
PIN        93 = !BUFCTL;
PIN        92 = !CONT;		/* 						*/
PIN        10 = !ABORT;		/* 						*/
PIN        84 =  HALT;		/* 						*/
PIN        94 =  DV;		/* 						*/
PIN        96 = !SCTL;
PIN        89 = !STRB;
PIN         8 = !MISS;		/* 						*/
PIN        85 =  CLK;
PIN         5 =  INIT;
PIN         7 = !PWRF;
PIN         9 = !MAP;
PIN        12 = !EVENT;		/* 						*/
PIN        13 =  IRQ0;		/* 						*/
PIN        79 =  RCVIRQC;
PIN        70 =  XMTIRQC;
PIN        71 =  BRKIRQC;
PIN        72 = !DMR;

PIN        69 = !IO;		/* 	Console IO                              */
PIN        75 = !CE;		/* 	Memory Chip Enable                      */
PIN        80 = !OE;		/* 	SBC Output Enable                       */
PIN        83 = !WEL;		/* 	SBC Write Enable Lower Byte             */
PIN        81 = !WEU;		/* 	SBC Write Enable Upper Byte             */
PIN         6 =  NXM;		/* 	Non-Existant Memory Address             */

PIN        44 =  RQST;		/* 	MCU Request Signal			*/
PIN        46 =  ACKN;
PIN        45 =  INTR;
PIN        47 =  RS0;
PIN        30 =  RS1;
PIN        88 =  RD;
PIN        87 =  WR;

PIN        42 =  DX0;		/* 	Request Information 			*/
PIN        41 =  DX1;
PIN        40 =  DX2;
PIN        37 =  DX3;
PIN        36 =  DX4;
PIN        35 =  DX5;
PIN        33 =  DX6;
PIN        32 =  DX7;

PIN        49 =  ODT;
PIN        14 =  LTC;
PIN           =  PF;

PIN        27 =  BRKA;
PIN        28 =  BRKB;
PIN        29 =  TXOB;
PIN        31 =  TXOA;
PIN        50 =  TXDB;
PIN        52 =  TXDA;

PIN        17 =  PA0;
PIN        19 =  PA1;
PIN        20 =  PA2;
PIN        21 =  PA3;
PIN        22 =  PA4;
PIN        23 =  PA5;
PIN        24 =  PA6;
PIN        25 =  PA7;

PINNODE       =  DONE;
PINNODE       =  MCUIO;
PINNODE       =  INTIO;
PINNODE       =  LEVNT;
PINNODE       =  KWIE;
PINNODE       =  LPF;
PINNODE       =  PFACK;
PINNODE       =  RXIRQC;
PINNODE       =  RXACKC;
PINNODE       =  TXIRQC;
PINNODE       =  TXACKC;

PINNODE       =  MCUIRQ;
PINNODE       =  MCUACK;

PINNODE       = [A12..0];
PINNODE       = [PF7..0];

FIELD IOADDR  = [A12..1];
FIELD GPADDR  = [A7..0];
FIELD DAL     = [DAL15..0];
FIELD LBS     = [LBS1..0];
FIELD LAIO    = [LAIO3..0];
FIELD ONBIO   = [ONBIO3..0];
FIELD IACK    = [IACK3..0];

$DEFINE AIONIO      'b'1111
$DEFINE AIOGPREAD   'b'1110
$DEFINE AIOIACK     'b'1101
$DEFINE AIOINST     'b'1100
$DEFINE AIOREAD     'b'10xx
$DEFINE AIOGPWRITE  'b'0101
$DEFINE AIOWRITE    'b'000x
$DEFINE AIOBYTE     'b'001x

$DEFINE BSMEM       'b'00
$DEFINE BSSYS       'b'01
$DEFINE BSEXT       'b'10
$DEFINE BSINT       'b'11

Preparing the DCJ11 SBC

Before you can use the MCU expansion card you need to remove the on-board glue logic which consists either of the GAL16V8 (U18) or the six TTL logic devices (U4, U7, U8, U10, U13, U14). Also you should cut the solder jumper JP4 (INIT) as we will now create INIT for the DC319 via the CPLD to make the initialization consistent with PDP-11 logic that generates a bus reset (BINIT) derived from the GPWRITES issued by the DCJ11.

First Experiment - New Glue Logic

First we will replace the glue logic, provide power-up configuration, decode some GPWRITE codes and generate ABORT.

The glue logic in the GAL16V8 provided the following singals CE, IO, OE, WEL, WEH, CONT MISS and as well GPREAD. GPREAD is not available on the expansion slot therefore we generate the power-up configuration in the CPLD.

/*
	Latch the IO address
 */

[A12..0].d    = [DAL12..0].io;
[A12..0].ck   =  ALE;

/*
	Replace on-board glue-logic, e.g. GAL16V8 or the six TTL logic devices
 */
OE            =  LAIO3 &  LAIO2 & !LAIO1 & !LAIO0          &  BUFCTL
              #  LAIO3 & !LAIO2                            &  BUFCTL;
          
CE            = !LBS1  & !LBS0;

IO            =  LBS1  & !LBS0  & IOADDR:['o'17756x];

WEL           = !LAIO3 & !LAIO2 & !LAIO1                   & !BUFCTL &  SCTL
              # !LAIO3 & !LAIO2 &  LAIO1          & !A0    & !BUFCTL &  SCTL;

WEU           = !LAIO3 & !LAIO2 & !LAIO1                   & !BUFCTL &  SCTL
              # !LAIO3 & !LAIO2 &  LAIO1          &  A0    & !BUFCTL &  SCTL;

/*
	Modify !CONT to stretch the CPU cycles for writes to external
	IO registers so that the write impulse for the DC319 or CDP6402
	is increased to match the requiremenets even for clock rates 
	above 10MHz. By delaying CONT with SCTL for writes to external
	IO registers the write pulse will be increased from 1 to 3 
	clock cycles. 

	For memory access we also have to assert CONT as read-modify-write
	memory cycles use a stretched read cycle.
 */
CONT          = !LBS1 & !LBS0 &  LAIO3
              # !LBS1 & !LBS0 & !LAIO3 &  SCTL
              # !LBS1 &  LBS0
              #  LBS1 & !LBS0          &  SCTL
              #  LBS1 &  LBS0;

Power-up configuration is now generated by the CPLD as well. As we are connected to the data bus we now can generate a full 16-bit power-up code.


/*
	Power-up configuration

	As GPREAD is not available at the expansion slot we need to provide
	the power-up configuration via the CPLD. 	

	+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
	|B15|B14|B12|B12| 0 | 0 | 0 |FPA|mod|mod|mod|mod|HLT|PU |PU |POK|
	+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
	\______________/              | \_______________/ | \_______/ |
	        |                     |           |       |     |     |
	        v      		      |           |       |     |     |
	Boot address   	              |           |       |     |     |
	FPA Present <-----------------+           |       |     |     |
	Module <----------------------------------+       |     |     |
	Halt option (0=ODT, 1=Trap 4)<--------------------+     |     |
	Power Up mode <-----------------------------------------+     |
	Power OK <----------------------------------------------------+

	Power Up Mode	Description
	Bit2	Bit1
	 0	 0	PC at 24, PS at 26
	 0	 1	ODT
	 1	 0	PC=173000, PS=340
	 1	 1	User Bootstrap, =340

 */
DAL.oe        =  LAIO:[AIOGPREAD] &  BUFCTL;
DAL           =  LAIO:[AIOGPREAD] & 'b'0000000000000011;

INIT for devices is now generated by the DCJ11. For this we need to decode the GPWRITE coes that assert and de-assert the bus reset signal.

/*
	Decode GPWRITE
	
	Here we use STRB to latch the GPWRITE code, normally you could use
	AIO and address and latch the decoded value using ALE. However the
	expansion slot does only provide LAIO which are latched with ALE so
	we cannot use ALE. STRB on the other side is asserted after ALE. 
	Also STRB has the advantage that it is active during the full CPU
	cycle not like ALE which is de-asserted in the middle of the CPU
	cycle. 

	INIT using .ar and .ap
 */
INIT.ck       = 'b'0;
INIT.d        = 'b'0;
INIT.ap       =  LAIO:[AIOGPWRITE] & GPADDR:['o'014] &  STRB;
INIT.ar       =  LAIO:[AIOGPWRITE] & GPADDR:['o'214] &  STRB;

One feature I have added is a LED, which will be first used to show if the DCJ11 is running ODT. The DCJ11 always issues a special GPWRITE code when entering or leaving ODT. This is a nice feature and is as well implemented on many DCJ11 based CPU boards.

/*
	ODT using .ck and .d 
 */
ODT.ck        =  LAIO:[AIOGPWRITE] & GPADDR:['o'234] &  STRB
              #  LAIO:[AIOGPWRITE] & GPADDR:['o'034] &  STRB;
ODT.d         =  A7;

MISS will be asserted for all memory access to invalid memory, i.e. wenn NXM is asserted during memory read or writes. This will cause the current CPU cycle to be stretched and will give us the opportunity to assert ABORT in the stretched part of the CPU cycle

MISS          = !LBS1 & !LBS0 &  NXM;

ABORT signals to the DCJ11 that a non-existing memory address or device register address has been accessed and will cause the DCJ11 to abort the CPU cycle and normally will trap through vector 010. Or in ODT will show the ? when opening the location. The signal must be asserted only during the stretched part of the CPU cycle here we use SCTL to assert ABORT as recommended in the datasheet. As noted in the comment, we need to be very specific about the cycles we need to abort.

/*
	When not implementing a time-out we need to take into account, that
	we must assert ABORT for Bank 0 only in case of read and write
	cycles. E.G. no ABORT for GPWRITES, that are also signalled with
	Bank 0, this is fatal. And the same is true for Bank 1 as interrupt
	acknowledge cycles use Bank 1. So we will very specific which cycles
	will be aborted.

 */
ABORT         = !LBS1 & !LBS0 & LAIO:[AIOINST]   &  NXM &  SCTL
              # !LBS1 & !LBS0 & LAIO:[AIOREAD]   &  NXM &  SCTL
              # !LBS1 & !LBS0 & LAIO:[AIOWRITE]  &  NXM &  SCTL
              #  LBS1 & !LBS0 & LAIO:[AIOINST]   &  NXM &  SCTL & !IO & !MCUIO
              #  LBS1 & !LBS0 & LAIO:[AIOREAD]   &  NXM &  SCTL & !IO & !MCUIO
              #  LBS1 & !LBS0 & LAIO:[AIOWRITE]  &  NXM &  SCTL & !IO & !MCUIO;

When programming the CPLD with the above equations you should now be greated by the ODT prompt and the LED should be lit when hitting the reset button.

Now you can try to run a program and the LED should turn of when you hit the G key. And turn back on when you hit the reset button.

@0/175564 777
f@0g
000000
@

First we check if ABORT is correctly generated

@0/000777 
00000002/177560 
00000004/052501 
00000006/052525 
00000010/052525 
00000012/012725 
00000014/052525 

@1000/125252 12737
00001002/125252 100000
00001004/125252 2000
00001006/135052 774
00001010/110212 0
00001012/001252 
@777776/000200 
01000000/?
@17777740/000002
@17777752/000000 
@17773000/?
@1000/012737 
00001002/100000 
00001004/002000 
00001006/000774 
00001010/000000 
@

Second we run the small program we entered above at address 1000 which writes the same value to address 2000 in a loop. This allows us to capture the bus cycles with a logic analyzer. There we should see a couple of non-stretched CPU cycles with one stretched write cycle.

Downloads

During the development of the CPLD design file and the MCU firmware I have gone through various cycles of enhancing the CPLD capabilities and the MCU firmware.

In the following archive I have collected all five stages of the CPLD design files and the corresponding JEDEC file. I included all stages primarely for documentation reasons. You either can selectively use any of the stages or you can go straight to the last generation.

CPLD Design Files and JEDEC

The microcontroller firmware is just the newest version. Note that this is still beta and though it fullfills the purpose of booting RT-11 from TU-58 it still needs some work, therefore you should regularly look for new versions. Until the code is reasonably mature I will publish the source code, but for the moment I make only the HEX file available

AVR Firmware

The KiCad Project is a slightly modified version of the PCB that I have ordered. It corrects the wrong connection of the pin headers for SLUA and SLUB and has some minor changes to the routing. Besides that it is functionally the same board as presented.

MCU IO Card