Kjetil's Information Center: A Blog About My Projects

Arduino Z80 CPU Tester

Here is a way to test Z80 CPUs that I created. I got the idea after seeing something about an Arduino being used as some sort of logic analyzer. For this I have used the Arduino Mega 2560 since this has a lot of digital I/O pins available.

It is a simple Arduino sketch, that uses the built-in USB CDC serial interface to communicate. It will respond to certain commands and on every cycle dump the status of the pins, which will look something like this:

  |------\_/------|
0 | A11       A10 | 0
0 | A12        A9 | 0
0 | A13        A8 | 0
0 | A14        A7 | 0
0 | A15        A6 | 0
1 | CLK        A5 | 0
0 | D4         A4 | 0
1 | D3         A3 | 0
0 | D5         A2 | 1
0 | D6         A1 | 0
- | +5V        A0 | 1
1 | D2        GND | -
0 | D7      ~RFSH | -
1 | D0        ~M1 | -
1 | D1     ~RESET | 1
- | ~INT   ~BUSRQ | -
- | ~NMI    ~WAIT | -
- | ~HALT  ~BUSAK | -
- | ~MREQ     ~WR | 1
- | ~IORQ     ~RD | 1
  |---------------|
Address: 0x5 Data: 0xF
          


The commands available in this version is 'c' to toogle the CLK clock pin, 'r' to toggle the RESET pin and 0 through 7 to toggle the data bit pins. It is possible to easily expand on this, but these are the minimum pins required to make the sketch program useful. A simple test that can be done with the Z80 is to put 0xC3 on the data bit pins, and then just toggle the clock over and over. This will cause it to read the opcodes 0xC3 0xC3 0xC3, meaning an absolute jump to address 0xC3C3 which will get reflected back on the address pins.

There is no circuit diagram, instead use the #define in the Arduino sketch to determine the connections. In addition to the signals defined there, +5V and GND is also needed of course, gotten from the Arduino as well.

Here is the sketch:

#define PIN_A0     11
#define PIN_A1     12
#define PIN_A2     10
#define PIN_A3     61
#define PIN_A4     60
#define PIN_A5     59
#define PIN_A6     58
#define PIN_A7     57
#define PIN_A8     56
#define PIN_A9     55
#define PIN_A10    54
#define PIN_A11    62
#define PIN_A12    63
#define PIN_A13    64
#define PIN_A14    65
#define PIN_A15    66
#define PIN_D0     17
#define PIN_D1     16
#define PIN_D2     19
#define PIN_D3     69
#define PIN_D4     68
#define PIN_D5     21
#define PIN_D6     20
#define PIN_D7     18
#define PIN_CLK    67
#define PIN_RESET  8 
#define PIN_WR     4 
#define PIN_RD     3 

void setup() {
  Serial.begin(115200);
  
  pinMode(LED_BUILTIN, OUTPUT);

  pinMode(PIN_A0, INPUT);
  pinMode(PIN_A1, INPUT);
  pinMode(PIN_A2, INPUT);
  pinMode(PIN_A3, INPUT);
  pinMode(PIN_A4, INPUT);
  pinMode(PIN_A5, INPUT);
  pinMode(PIN_A6, INPUT);
  pinMode(PIN_A7, INPUT);
  pinMode(PIN_A8, INPUT);
  pinMode(PIN_A9, INPUT);
  pinMode(PIN_A10, INPUT);
  pinMode(PIN_A11, INPUT);
  pinMode(PIN_A12, INPUT);
  pinMode(PIN_A13, INPUT);
  pinMode(PIN_A14, INPUT);
  pinMode(PIN_A15, INPUT);
  pinMode(PIN_D0, OUTPUT);
  pinMode(PIN_D1, OUTPUT);
  pinMode(PIN_D2, OUTPUT);
  pinMode(PIN_D3, OUTPUT);
  pinMode(PIN_D4, OUTPUT);
  pinMode(PIN_D5, OUTPUT);
  pinMode(PIN_D6, OUTPUT);
  pinMode(PIN_D7, OUTPUT);
  pinMode(PIN_CLK, OUTPUT);
  pinMode(PIN_RESET, OUTPUT);
  pinMode(PIN_WR, INPUT);
  pinMode(PIN_RD, INPUT);
}

void dump() {
  uint16_t bus;

  Serial.println("  |------\\_/------|  ");

  Serial.print(digitalRead(PIN_A11), DEC);
  Serial.print(" | A11       A10 | ");
  Serial.println(digitalRead(PIN_A10), DEC);

  Serial.print(digitalRead(PIN_A12), DEC);
  Serial.print(" | A12        A9 | ");
  Serial.println(digitalRead(PIN_A9), DEC);

  Serial.print(digitalRead(PIN_A13), DEC);
  Serial.print(" | A13        A8 | ");
  Serial.println(digitalRead(PIN_A8), DEC);

  Serial.print(digitalRead(PIN_A14), DEC);
  Serial.print(" | A14        A7 | ");
  Serial.println(digitalRead(PIN_A7), DEC);

  Serial.print(digitalRead(PIN_A15), DEC);
  Serial.print(" | A15        A6 | ");
  Serial.println(digitalRead(PIN_A6), DEC);

  Serial.print(digitalRead(PIN_CLK), DEC);
  Serial.print(" | CLK        A5 | ");
  Serial.println(digitalRead(PIN_A5), DEC);

  Serial.print(digitalRead(PIN_D4), DEC);
  Serial.print(" | D4         A4 | ");
  Serial.println(digitalRead(PIN_A4), DEC);

  Serial.print(digitalRead(PIN_D3), DEC);
  Serial.print(" | D3         A3 | ");
  Serial.println(digitalRead(PIN_A3), DEC);

  Serial.print(digitalRead(PIN_D5), DEC);
  Serial.print(" | D5         A2 | ");
  Serial.println(digitalRead(PIN_A2), DEC);

  Serial.print(digitalRead(PIN_D6), DEC);
  Serial.print(" | D6         A1 | ");
  Serial.println(digitalRead(PIN_A1), DEC);

  Serial.print("- | +5V        A0 | ");
  Serial.println(digitalRead(PIN_A0), DEC);

  Serial.print(digitalRead(PIN_D2), DEC);
  Serial.println(" | D2        GND | -");

  Serial.print(digitalRead(PIN_D7), DEC);
  Serial.println(" | D7      ~RFSH | -");

  Serial.print(digitalRead(PIN_D0), DEC);
  Serial.println(" | D0        ~M1 | -");

  Serial.print(digitalRead(PIN_D1), DEC);
  Serial.print(" | D1     ~RESET | ");
  Serial.println(digitalRead(PIN_RESET), DEC);

  Serial.println("- | ~INT   ~BUSRQ | -");
  Serial.println("- | ~NMI    ~WAIT | -");
  Serial.println("- | ~HALT  ~BUSAK | -");

  Serial.print("- | ~MREQ     ~WR | ");
  Serial.println(digitalRead(PIN_WR), DEC);

  Serial.print("- | ~IORQ     ~RD | ");
  Serial.println(digitalRead(PIN_RD), DEC);

  Serial.println("  |---------------|  ");

  bus = digitalRead(PIN_A15);
  bus <<= 1;
  bus += digitalRead(PIN_A14);
  bus <<= 1;
  bus += digitalRead(PIN_A13);
  bus <<= 1;
  bus += digitalRead(PIN_A12);
  bus <<= 1;
  bus += digitalRead(PIN_A11);
  bus <<= 1;
  bus += digitalRead(PIN_A10);
  bus <<= 1;
  bus += digitalRead(PIN_A9);
  bus <<= 1;
  bus += digitalRead(PIN_A8);
  bus <<= 1;
  bus += digitalRead(PIN_A7);
  bus <<= 1;
  bus += digitalRead(PIN_A6);
  bus <<= 1;
  bus += digitalRead(PIN_A5);
  bus <<= 1;
  bus += digitalRead(PIN_A4);
  bus <<= 1;
  bus += digitalRead(PIN_A3);
  bus <<= 1;
  bus += digitalRead(PIN_A2);
  bus <<= 1;
  bus += digitalRead(PIN_A1);
  bus <<= 1;
  bus += digitalRead(PIN_A0);
  Serial.print("Address: 0x");
  Serial.print(bus, HEX);
  Serial.print(" ");

  bus = digitalRead(PIN_D7);
  bus <<= 1;
  bus += digitalRead(PIN_D6);
  bus <<= 1;
  bus += digitalRead(PIN_D5);
  bus <<= 1;
  bus += digitalRead(PIN_D4);
  bus <<= 1;
  bus += digitalRead(PIN_D3);
  bus <<= 1;
  bus += digitalRead(PIN_D2);
  bus <<= 1;
  bus += digitalRead(PIN_D1);
  bus <<= 1;
  bus += digitalRead(PIN_D0);
  Serial.print("Data: 0x");
  Serial.println(bus, HEX);
}

void loop() {
  if (Serial.available() > 0) {
    switch (Serial.read()) {
    case 'r':
      digitalWrite(PIN_RESET, digitalRead(PIN_RESET) ? 0 : 1);
      break;

    case 'c':
      digitalWrite(PIN_CLK, digitalRead(PIN_CLK) ? 0 : 1);
      break;

    case '0':
      digitalWrite(PIN_D0, digitalRead(PIN_D0) ? 0 : 1);
      break;

    case '1':
      digitalWrite(PIN_D1, digitalRead(PIN_D1) ? 0 : 1);
      break;

    case '2':
      digitalWrite(PIN_D2, digitalRead(PIN_D2) ? 0 : 1);
      break;

    case '3':
      digitalWrite(PIN_D3, digitalRead(PIN_D3) ? 0 : 1);
      break;

    case '4':
      digitalWrite(PIN_D4, digitalRead(PIN_D4) ? 0 : 1);
      break;

    case '5':
      digitalWrite(PIN_D5, digitalRead(PIN_D5) ? 0 : 1);
      break;

    case '6':
      digitalWrite(PIN_D6, digitalRead(PIN_D6) ? 0 : 1);
      break;

    case '7':
      digitalWrite(PIN_D7, digitalRead(PIN_D7) ? 0 : 1);
      break;
      
    default:
      break;
    }
    dump();
  }

  digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) ? 0 : 1);
  delay(100);
}
          

The LED blinking is used as a indicator to see that the sketch program is actually running.

Here is a photo of the setup:

Arduino Z80 Tester


Topic: Scripts and Code, by Kjetil @ 27/11-2021, Article Link