3 chip VZ200 project


This page will document my efforts to build a working VZ200 in hardware using a combination of new and old technology

What is a VZ200?

The VZ200 is an early 1980s home computer. Out of the box it came with 8k RAM, 16K ROM, Z80 CPU, Motorola 6847 graphics chip, rubber keyboard and a simple 2 bit piezo speaker.
It was designed as a low cost entry level computer - better than a ZX81 but not as good as a spectrum. Similar machines of the time were the Acorn Atom and Tandy MC-10.

The VZ300 appeared in 1985, which was fundamentally the same as a VZ200 but with more memory and a better keyboard. The picture below is some of my collection.


 
Opening the case of a VZ200 revealled a myriad of chips, resistors and capacitors. The reason for the high chip count is due to the 1980s technology - memory was expensive.
In the VZ the internal RAM was built up using 2k RAM chips. For a 16k VZ300, that's 8 ICs right there. Then you have the 2k graphics memory, an 8 bit latch, and 16k ROM. Each of these
chips requires supporting circuitry, and additional ICs for address decoding between the Z80 and 6847.

Below is a picture of the VZ300 internals.



This project is an attempt to build a working VZ in hardware with just 3 chips:

1. Motorola 6847 - The original graphics chip used in the VZ computers

2. 7404 hex inverter - used alongside a 3.58mhz crystal to provide the clock signal for the M6847

3. Teensy 3.5 microcontroller. This is a modern, powerful, programmable 50 pin IC. This will simulate the Z80 CPU, provide a 64k address space, bootstrap the VZ ROM, interface to the  M6847 and handle all the address decoding logic. It is essentially a VZ emulator on a chip that interfaces to a real display chip. The teensy will replace all but two of the ICs above!

How it will work

- The teensy will contain the original VZ ROM on the internal micro sd card - the same ROM file used by the VZEM emulator
- The teensy will contain the Z80 emulation code in its sketch memory, with supporting functions for VZ specific hardware
- On powerup, the teensy will allocate a 64K chunk of RAM, load the VZ ROM into low memory, and start the Z80 emulation. The clock will start running the M6847  
- The Z80 emulation code will run for 71590 T-states, which is the number of cpu cycles for a 3.5795mhz Z80 running for 20ms
- The teensy will wait for the next FS signal from the M6847, which signifies the end of a frame
- At the same time the Z80 emulation code is running, the teensy is decoding the address lines of the M6847 and returning bytes of data according to the VZ memory map
- The "VZ latch" will be internal to the emulation code, with pins from the teensy wired to the M6847 mode control pins to set display mode/background colour

Initial version will just use the "Y" output of the M6847 to drive a monochrome NTSC display. If I get this far, future experiments may include:

- MC1372 modulator chip to drive a color display
- LCD display screen with some pushbuttons to map disk & cassette images
- A real Z80, with the teensy just serving the ROM, RAM and address decoding. This qualifies as a "real" VZ, rather than an emulator/hardware hybrid

Progress

25th March 2017

Thanks to some help from Gerardus I believe I have a working clock generator. The circuit is based on the below design, taken from http://www.andreadrian.de/Z80_blinkenlights/index.html



I then inverted the output again and after some experimentation used a 1.2k resistor to smooth out the edges.

This is the clock generator circuit on a breadboard, next to the M6847.


And this is the resulting signal captured on my scope. The pulse width is appx 150ns with rise and fall times of appx 50ns.


 
What next

The next phase of the project will be to build a test circuit interfacing the teensy to the M6847. The two transistor circuit below will be added to the "video card" breadboard to see if it can produce a working display.
Then the Z80/VZ200 emulation code will be loaded into the teensy.


http://devster.monkeeh.com/files/vidamp.png


Update - 29th March 2017


The below pic shows the M6847 hooked up to the teensy. The white wire is the clock signal. The orange wire is the horizontal synch pin, the blue wire the field synch pin



Looking at the 6847 datasheet, there are 32 lines left in the frame until the end of the vertical retrace (26 bottom border + 6 retrace)


The following code was loaded into teensy's sketch memory, to count the number of horizontal synchs after the field synch, till the end of frame


#include <SD.h>
#include <SPI.h>  

#define M6847_FS 33   // Field synch pin wired to teensy pin 33
#define M6847_HS 34   // Horizontal synch pin wired to teensy pin 34

const int chipSelect = BUILTIN_SDCARD;

File myFile;

void setup()
{
  if (!SD.begin(chipSelect))
  {
    return;
  }

  myFile = SD.open("3chipvz.txt", FILE_WRITE);
  if (myFile)
  {
    myFile.println("*** 3CHIPVZ ***");
    myFile.println("Initialising...");
  }
  pinMode(M6847_FS, INPUT);                                  
  pinMode(M6847_HS, INPUT);                                  
  int horizontalSynchs = 0;

  while (digitalRead(M6847_FS) == LOW);      // we could be starting in the retrace period, eg FS low, so wait for start of display
  while (digitalRead(M6847_FS) == HIGH);     // now in main display
 
  // starting point - the FS has just gone low again. Start counting horizontal synchs until start of display

  while (digitalRead(M6847_FS) == LOW)
  {
      while (digitalRead(M6847_HS) == LOW);        // wait for HS to complete
      while (digitalRead(M6847_HS) == HIGH);       // drawing scanline
      horizontalSynchs++;                          // just hit HS low - increment count
  }

  myFile.print("HS count: ");
  myFile.println(horizontalSynchs);
  myFile.close();
}

void loop()
{
  // nothing happens after setup
}

Once power was applied to the circuit, this was the resulting output on the SD card

*** 3CHIPVZ ***
Initialising...
HS count: 32

Which proves the M6847 is accepting the clock signal and producing horizontal and frame synch pulses, which the microcontroller can read.


Update - 2nd April 2017


Wired up the address and data bus of the M6847 to the teensy. For the "address" lines, the data pins on the teensy were configured as input.  The "data" lines, writing data back to the M6847 were configured as output.
Pins 0-12 are used for the address lines, which fits neatly on the pinout diagram below. Pin 0 is the most significant bit, wired to pin DA12 (pin 21) on the M6847

Pins 25-32 are the 8 data lines to return data back to the M6847 with pin 25 the most significant bit.


These are the functions defined in the teensy to decode the address lines and return data back to the M6847.

unsigned int M6847_readAddress()
{
    int addressBus = 0;
    addressBus |= ((digitalRead(12)==HIGH)?1:0)<<0;
    addressBus |= ((digitalRead(11)==HIGH)?1:0)<<1;
    addressBus |= ((digitalRead(10)==HIGH)?1:0)<<2;
    addressBus |= ((digitalRead(9)==HIGH)?1:0)<<3;
    addressBus |= ((digitalRead(8)==HIGH)?1:0)<<4;
    addressBus |= ((digitalRead(7)==HIGH)?1:0)<<5;
    addressBus |= ((digitalRead(6)==HIGH)?1:0)<<6;
    addressBus |= ((digitalRead(5)==HIGH)?1:0)<<7;
    addressBus |= ((digitalRead(4)==HIGH)?1:0)<<8;
    addressBus |= ((digitalRead(3)==HIGH)?1:0)<<9;
    addressBus |= ((digitalRead(2)==HIGH)?1:0)<<10;
    addressBus |= ((digitalRead(1)==HIGH)?1:0)<<11;
    addressBus |= ((digitalRead(0)==HIGH)?1:0)<<12;

  return addressBus;

}

void M6847_writeData(byte data)
{
  digitalWrite(32, (data & 0x01) >> 0);
  digitalWrite(31, (data & 0x02) >> 1);
  digitalWrite(30, (data & 0x04) >> 2);
  digitalWrite(29, (data & 0x08) >> 3);
  digitalWrite(28, (data & 0x10) >> 4);
  digitalWrite(27, (data & 0x20) >> 5);
  digitalWrite(26, (data & 0x40) >> 6);
  digitalWrite(25, (data & 0x80) >> 7); 
}

Another test program was loaded into the teensy to set the video memory to 0x41 - the ascii "A" character.

  for (int i=0; i < 6144; i++)
  {
    M6847_MEM[i] = 0x41;
  }


The "loop" function, which loops forever while the power is on, just reads lines from the address bus (0x0000-0x17FF) and returns data from the byte array defined for the screen memory.
The last digitalWrite command just lights up the LED permanently, which tells me the microcontroller is in its main loop.

void loop()
{
    addr_bus = M6847_readAddress();
    data = M6847_MEM[addr_bus];
    M6847_writeData(data);

    digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
}

The two-transistor circuit was rigged up on a separate piece of breadboard.

The picture below shows the initial state - using jumper wire it gets messy quickly, but this was just to test the pins. The final prototype will use cut to length wire.  Note the micro sd card plugged in to the teensy. At the moment this is used to log tests, this will eventually be used to load the VZ rom on startup, and hold all the floppy disk and cassette images.



This is the resulting picture displayed on a cheap polaroid lcd tv. There is a blue tinge to the characters. Not sure if the tv can handle an ntsc signal properly



And this is the same result displayed on my old commodore 1084 monitor. The picture is near perfect - quite sharp to look at.



Next iteration will split the teensy onto a separate breadboard, and the composite video out circuit will be incorporated onto the board with the clock and M6847. I'll change the rca plug into an rca socket, to allow use of a standard yellow video rca cable.
I might buy a single large breadboard to fit the entire prototype on one piece