Zolatron 64: memory expansion

      No Comments on Zolatron 64: memory expansion

Things are continuing apace with the Zolatron 64 6502 homebrew computer. In fact, progress has been so rapid that I haven’t really had much time to talk about it. So here’s a quick refresher – and details of the new memory expansion board.

Serial killer

The 6551 ACIA serial board is dead. Well, it’s not dead, but I’ve stopped using it. As I mentioned in the last update, I now have another serial board, based on the NXP SC28L92 chip. This is a dual UART and so provides two serial ports, plus some other general-purpose input and output pins.

It turns out that the SC28L92 is very easy to program. It’s a trifle more complex that the 6551, but careful reading of the datasheet will have you up and running in no time. If anyone is interested, I’ll write a post on how to use it.

The downside of the SC28L92 is that NXP recently decided to stop making it, and it has become unobtainium. Luckily, alternatives are available. MaxLinear (the artist formerly know as Exar) offers the XR88C92 or XR88C192 and these are both drop-in, pin-compatible replacements. The only differences are that the MaxLinear chips lack the ‘Motorola mode’ and so offer only the Intel mode, which is fine by me. Also, the XR88C92 has 8-byte FIFOs, while the 192 variant matches the SC28L92’s 16-byte buffers.

Parallel dimension

In the previous roundup I mentioned that I’d just received the parallel interface board but hadn’t yet tested it. The good news is that it works exactly as expected and I can happily print text to my Epson MX-80 FT/III dot matrix printer. Which is nice.

Expanded memory

In this shot, the Zumpus ROM is fitted in bank 1.

More exciting is a board I’ve not discussed before. The Zolatron’s memory map has an 8KB section sitting just above the main RAM, which I’d basically set aside with a mental note of ‘do something with this someday’. Well, now that something is done.

I wanted to play around with the concept of banked memory. This is something that the BBC Micro family used to such good effect. So I thought, instead of having, say, just one 8KB memory chip sitting in this location, why not have several?

So this was my cunning plan: I’d take a 128KB RAM chip. This would sit at address $8000. You need address pins A0-A12 to address 8KB of memory. The top four address pins, A13-A16 would be connected to latches. By varying the setting of these latches, the 8KB the machine is addressing at any one time is moved about within the RAM chip’s memory. I’d get 16 of these 8KB banks.

Typing the command XLS shows what’s loaded into the 16 banks. The version of Zumpus in bank 3 is a ROM. Yeah, I moved it.

The trick was how to address the latches. Having become comfortable with CPLD programming, I decided I’d use an ATF1502AS CPLD to decode for the $8000 address, decode an address for the latches and provide the latches themselves. I needed to feed it with address lines A5-A15, the bottom four data lines (D0-D3) to provide a value in the range 0-15, plus the clock signal and the R/W signal from the CPU.

The CPLD makes the four internal latches active when it sees the address $BFE0 (this is in the I/O section of the Zolatron’s memory map). When it sees that address, it looks at the values of the data lines D0-D3 and sets the corresponding latches. When the computer is no longer addressing $BFE0, these values are latched in. The upshot is that all that is needed to select a bank in the range 0-15 is to write that value to $BFE0. For example, to select bank 5:

; Select bank 5
  lda #5
  sta $BFE0

Yup. that’s it. Now, bank 5 is at address $8000.

By the time I’d got that far, I figured I might as well make things a little more complicated.

For banks 0-3, it’s possible to select a ROM socket in place of the RAM. This was simple enough – I used some jumpers to select between ROM or RAM.

The weird thing is, I got the first spin of the board back and it worked. Just like that. That almost never happens.

(The PCB does say it’s rev A2, but A1 was actually a completely different board that attempted to use Flash RAM. I knew that wasn’t going to work even before the PCBs arrived. Don’t know why I didn’t start again with the label A1, but there you go.)

Here’s the schematic for the board.

And here’s the CPUL code for the CPLD.

Name     EXTMEMDECODE ;
PartNo   00 ;
Date     03/07/2022 ;
Revision 01 ;
Designer SMD ;
Company  Machina Speculatrix ;
Assembly ;
Location ;
Device   f1502ispplcc44 ;

/*
This provides decoding for extended memory on the Zolatron 64.

The memory sits at address $8000. The decoding allows us to select one of 16
8K banks at this address.

The bank is selected by writing the value 0-15 to the address $BFE0. This
CPLD provides the decoding for that address as well as a register (BSEL) of four
D flip-flops that hold the selected value.

This register connects to address lines A13-A16 of the RAM, thus
selecting the effective address of the bank.

The BSEL register is also used to select among five chip enable signals -
four for the RAM chips and one for the RAM. If the BSEL value is 0-3
then the appropriate CHIP_EN line 0-3 is selected. If BSEL is 4-15 then
CHIP_EN4 is selected.

On the board itself, four jumpers individually select whether CHIP_EN lines
0-3 go to their respective ROMs or to the RAM.

NB: The build script has been modified to make the chip enable outputs
open-collector.
*/

/* --------------- INPUTS --------------------------------------------------- */
PIN 43 = CLK;                            /* PHI2 clock */
PIN 41 = RWB;                            /* Read!Write signal from CPU */
PIN [8,6,5,4] = [D3..0] ;                /* Data bus to select mem bank */
PIN [24,21..16,14,12,11,9] = [A15..5];   /* Address bus */

/* --------------- OUTPUTS -------------------------------------------------- */
PIN [33,34,36,37] = [BSEL3..0] ; /* Bank select register */
PIN [39,27,28,40,31] = ![CHIP_EN4..0]; /* Chip enable reg - active low */

PINNODE = [CHIP_SEL4..0]; /* Internal chip select register */
PINNODE = BSEL_EN; /* Enable latching for bank select */

/* --------------- BANK SELECTION ------------------------------------------- */
/* BSEL_EN is selected when the address set is $BFE0. This is the case when
we're writing a value to select the memory bank. */

BSEL_EN = A15 & !A14 & [A13..5]:& ; /* Decodes for 32-bit block at $BFE0 */

/* The four D flip-flops in the BSEL register have their clocks enabled.
The flip-flop is set to the appropriate value when CLK transitions low - ie, on
the falling edge. The flip-flop is also enabled only when RWB is low (ie doing
write operations) BSEL_EN is active.

The flip-flops will set according to the inputs on D0-D3.
When the clock goes high again, these values are latched. When we no longer
have $BFE0 as the address, the values will remain latched.

These four flip-flops are connected to A13-A16 on the RAM chip. They're
not attached to the address bus - so they don't interfere with anything else.
*/
BSEL3.d = D3; /* Value from data bus */
BSEL3.ck = !CLK; /* Act on falling edge of clock */
BSEL3.ce = !RWB & BSEL_EN; /* Only during writes & with $BFE0 selected */
BSEL2.d = D2;
BSEL2.ck = !CLK;
BSEL2.ce = !RWB & BSEL_EN;
BSEL1.d = D1;
BSEL1.ck = !CLK;
BSEL1.ce = !RWB & BSEL_EN;
BSEL0.d = D0;
BSEL0.ck = !CLK;
BSEL0.ce = !RWB & BSEL_EN;

/* --------------- CHIP ENABLE ---------------------------------------------- */

/* Match the CHIP_SEL internal register settings to the current value of the
BSEL register. */
FIELD BANK = [BSEL3..0];
FIELD CHIPSL = [CHIP_SEL4..0];          /* 4 = RAM, 3..0 = ROM/RAM */
TABLE BANK => CHIPSL {
'b'0000 => 'b'00001 ;                   /* CHIP_EN0 - BANK 0 RAM/ROM */
'b'0001 => 'b'00010 ;                   /* CHIP_EN1 - BANK 1 RAM/ROM */
'b'0010 => 'b'00100 ;                   /* CHIP_EN2 - BANK 2 RAM/ROM */
'b'0011 => 'b'01000 ;                   /* CHIP_EN3 - BANK 3 RAM/ROM */
'b'01XX => 'b'10000 ;                   /* CHIP_EN4 - BANKS 4-15 RAM */
'b'1XXX => 'b'10000 ;                   /*  "    "      "     " */
}

/* Set the appropriate chip enable signal when address $8000 is selected. */
CHIP_EN0 = A15 & !A14 & !A13 & CHIP_SEL0; /* ROM/RAM Bank 0 */
CHIP_EN1 = A15 & !A14 & !A13 & CHIP_SEL1; /* ROM/RAM Bank 1 */
CHIP_EN2 = A15 & !A14 & !A13 & CHIP_SEL2; /* ROM/RAM Bank 2 */
CHIP_EN3 = A15 & !A14 & !A13 & CHIP_SEL3; /* ROM/RAM Bank 3 */
CHIP_EN4 = A15 & !A14 & !A13 & CHIP_SEL4; /* RAM Banks 4-15 */ 

The comments mention a build script that has been adapted to make the latch outputs open collector. In the end I didn’t needed this because I’d added diodes. But, for the record, the bit in the script that does this is:

find1502 -i %~dp0\%~n0.tt2 -CUPL -dev %DEV% -str JTAG ON -str open_collector = CHIP_EN0 CHIP_EN1 CHIP_EN2 CHIP_EN3 CHIP_EN4 logic_doubling off

As usual, you can find the latest version of the code, and the full script, at the GitHub repo.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.