Close

PAL and TTL hybrid version

A project log for ZX80/ZX81 remakes

“Sinclair video generation is like a dog's walking on his hind legs. It is not done well; but you are surprised to find it done at all.”

keithKeith 09/02/2023 at 18:060 Comments

2023-09-02

This is the approach I have decided upon.

This has the following advantages

The memory map should look like this:

/*
RAM onboard:
     a a a a a a a a
     1 1 1 1 1 1
     5 4 3 2 1 0 9 8

00h,02h   0 0 0 0 0 0 x 0     ZX81 RAM patches at 00XXh and 02XXh
0x20      0 0 1 0 0 x x x     G007 RAM (2k space)
0x30      0 0 1 1 0 x x x     Spare RAM

ROM unified:

0x0c      0 0 0 0 1 1 0 0     ZX81 ROM patch
0x28      0 0 1 0 1 x x x     G007 ROM (2k space)
0x38      0 0 1 1 1 x x x     Spare ROM

RAM expansion:

0x40      0 1 0 x x x x x     RAM expansion (8k)
0x40      0 1 x x x x x x     RAM expansion (16k)
0x80      1 x x x x x x x     RAM expansion (above 32k)

Intermediate terms:
*/

RAM_patches            = !a15 & !a14 & !a13 & !a12 & !a11 & !a10 & !a8 ;

ROM_8k_at_0000h        = !a15 & !a14 & !a13 ;

RAM_2k_at_2000h        = !a15 & !a14 &  a13 & !a12 & !a11 ;
ROM_2k_at_2800h        = !a15 & !a14 &  a13 & !a12 &  a11 ;
RAM_2k_at_3000h        = !a15 & !a14 &  a13 &  a12 & !a11 ;
ROM_2k_at_3800h        = !a15 & !a14 &  a13 &  a12 &  a11 ;

/*
The terms above simplify if you wish to minimise logic:
*/

RAM_at_2000h_and_3000h    = !a15 & !a14 &  a13 &        !a11 ;
ROM_at_2800h_and_3800h    = !a15 & !a14 &  a13 &         a11 ;

/*
However I shall leave them unsimplified so they can be modified more easily:
*/

/*
Drive pins:
*/

RAM_expansion        = mreq & a15        // at 8000h, above 32 
            + mreq & a14        // at 4000h or C000h

RAM_onboard        = mreq & RAM_2k_at_2000h
            + mreq & RAM_2k_at_3000h;

/*
NB if onboard RAM is 8K or less, then RAM at 
00XX and 02XX are aliased at
20XX and 22XX respectively.
If you have more, then they are not,
and the higher addresses are free for your use.
*/

ROM_unified    = mreq & ROM_8k_at_0000h & !(RAM_patches)
        + mreq & ROM_2k_at_2800h
        + mreq & ROM_2k_at_3800h ;

/*
NB the logic above will probably expand to something like:
*/

ROM_unified_alt =
    + mreq & ROM_8k_at_0000h &    a11        // 1000h
    + mreq & ROM_8k_at_0000h &    a10        // 0800h, 1800h
    + mreq & ROM_8k_at_0000h &    a8;        // 0400h, 0600h, 1400h, 1600h

/*
So the memory address decoder uses 9 inputs and 3 outputs

in:    A15...8
    !mreq 

out:    ROM_unified
    RAM_onboard
    RAM_expansion

That leaves 10 pins, up to 7 outputs and 3 inputs or 1 output and 9 inputs.
*/

memory_refresh    = mreq & rfsh;    /* clocks a D-type latch to set text or high-res mode */

pixel_latch    = graphics_mode & mreq & cpu_clk ;
pixel_output    = graphics_mode & rfsh ;
force_nop_2    = graphics_mode & m1 & A15 ;
_rd        = rd & a15
        + rd & a14
        + rd & something ;

u9a_latch_d    = mreq & _rd & force_nop_2 ;

u9a_latch.d    = u9a_latch_d;
u9a_latch.ar    = u9a_latch_d;

d7        = _d7 ;
d6        = _d6 ;

d7.oe        = _rd ;
d6.oe        = _rd ;


_d7        = d7 ;
_d6        = d6 ;

_d7.oe        = u9a_latch ;
_d6.oe        = u9a_latch ;

I suspect the RAM patches may not need to be RAM, but I want to keep it working as near to the original for compatibility reasons.

2023-09-07

Spent a long time thinking.

I think I can get the memory decoder working in a way compatible with the G007 board.

Ian Bradbury's design uses an ATV750 which is like two 22V10 chips in one package, and each output macrocell can have its own clock and set/reset signals.
His logic makes much use of the latter, which is useful because the ZX80 circuit also has multiple clocks and set/reset signals. For that reason I am currently keeping the 74HC74 D-type latches.

The HSYNC logic of the ATV750 will not fit in a 22V10, so I decided to use a 74HC393 counter and a 22V10.

At this point I wonder if I am actually saving much by using PAL chips, but I am saving many chips and even more if I integrate the pixel graphics board as well.

Andy Rea's ULA replacement design is interesting. There is no /RFSH signal to the ULA so obviously this has to be recreated inside. Andy uses a 3-bit counter that is reset by the /M1 signal and clocked by twice the CPU clock. We know when refresh occurs after /M1, and thus when to force a NOP instruction on the bus.

It seems there are several ways to implement the ZX81 logic.

2023-09-08

Had  look at my genuine original ZX81 board to see why it was not working.
I printed out the circuit and went to work with a meter and highlighter pens.
I noticed that some of the data lines do not connect between the RAM and the ROM.

Either my meter is faulty or many connections are faulty. 
Have the solder joints started going dry from age?

With this many faults, I'm considering buying a replacement because this will be cheaper in the value of my time.

Meanwhile, I shall set it aside and proceed with using the ZX80 board, which is at least running ZX81 BASIC.

I suspect I was in the middle of modding my boards to use a single ROM, and didn't leave it in a working condition.

2023-09-10

Installed WinCUPL on an old Intel i3 laptop. It is slow, but maybe upgrading it to an SSD might fix that. Right now, compiling small GAL chips is not a processor-intensive task. 

I started it compiling logic so I shall be able to try some experiments soon.

Discussions