Programming interface using a Beagle Bone Black or Raspberry PI (I use a PI Zero W)
I called the program Z80 Host, because it hosts the data for the Z80. or maybe better to call it a Z80 IDE (Integrated Development Environment). or maybe IDF (Integrated Development Interface)
Here is the code for sending Data to the Z-80's RAM for rapid code testing, really beats burning EPROMS and Erasing them.
This code requires the i2c library on the MCP23017P page.
To-do: Better error handling, file loading, target device loading, console control?
/* z80host.c v0.1 by Eric Stringer eric.stringer@gmail.com */
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include "i2c-dev.h"
#include "mcp23017.h"
#include "z80host.h"
#include "host.h"
#include "i2c_util.h"
FILE *fileptr;
char *buffer;
long filelen;
void main()
{
int file, size, delay;
int adapter_nr = 1; /* probably dynamically determined */
char filename[20];
int addr = 0x21; /* address of I2C device */
__u8 reg; /* Device register to access */
__u8 res, out;
char buf[56],k[32];
int x;
file = Open_i2c_bus(adapter_nr);
init_ports_reset( file );
/*set data code */
write_program_ram( file );
init_ports_reset( file );
Z80_reset(file);
printf("Write done!\n");
close(file);
}
int Z80_reset(int file )
{
int x, delay;
/* set Reset pin low for 3 Clock cycles */
Write_i2c_port_bit( file, 0x21, 0x01, 5, 0); // Turn on Reset line
Write_i2c_port_bit( file, 0x21, 0x13, 5, 0); /* Reset pin low */
for(delay=0; delay < 200; delay++);
Write_i2c_port_bit( file, 0x21, 0x13, 5, 1); /* Reset pin high */
Write_i2c_port_bit( file, 0x21, 0x01, 5, 1); // Turn off Reset line
printf("Reset done!\n");
}
int init_ports( int file )
{
int x;
printf("init ports\n");
for(x=0; x < 18; x=x+3)
{
Write_i2c_port( file, Z80_host_port_config[x], Z80_host_port_config[x+1], Z80_host_port_config[x+2] );
}
/*Set INT, NMI, BUSREQ, WAIT, RESET high */
Write_i2c_port_bit( file, 0x21, 0x13, 3, 1);
Write_i2c_port_bit( file, 0x21, 0x13, 4, 1);
Write_i2c_port_bit( file, 0x21, 0x13, 5, 1);
Write_i2c_port_bit( file, 0x22, 0x12, 3, 1);
Write_i2c_port_bit( file, 0x22, 0x12, 4, 1);
Write_i2c_port_bit( file, 0x22, 0x12, 5, 1);
printf("init ports done!\n");
}
int init_ports_read( int file )
{
int x;
printf("init ports read mode\n");
for(x=0; x < 18; x=x+3)
{
Write_i2c_port( file, Z80_host_port_config_read_bus[x], Z80_host_port_config_read_bus[x+1], Z80_host_port_config_read_bus[x+2] );
}
/*Set INT, NMI, BUSREQ, WAIT, RESET high */
Write_i2c_port_bit( file, 0x21, 0x13, 3, 1);
Write_i2c_port_bit( file, 0x21, 0x13, 4, 1);
Write_i2c_port_bit( file, 0x21, 0x13, 5, 1);
Write_i2c_port_bit( file, 0x22, 0x12, 3, 1);
Write_i2c_port_bit( file, 0x22, 0x12, 4, 1);
Write_i2c_port_bit( file, 0x22, 0x12, 5, 1);
printf("init ports done!\n");
}
int init_ports_write( int file )
{
int x;
printf("init ports read mode\n");
for(x=0; x < 18; x=x+3)
{
Write_i2c_port( file, Z80_host_port_config_write_bus[x], Z80_host_port_config_write_bus[x+1], Z80_host_port_config_write_bus[x+2] );
}
/*Set INT, NMI, BUSREQ, WAIT, RESET high */
Write_i2c_port_bit( file, 0x21, 0x13, 3, 1);
Write_i2c_port_bit( file, 0x21, 0x13, 4, 1);
Write_i2c_port_bit( file, 0x21, 0x13, 5, 1);
Write_i2c_port_bit( file, 0x22, 0x12, 3, 1);
Write_i2c_port_bit( file, 0x22, 0x12, 4, 1);
Write_i2c_port_bit( file, 0x22, 0x12, 5, 1);
printf("init ports done!\n");
}
int init_ports_reset( int file )
{
int x;
printf("init ports reset\n");
for(x=0; x < 18; x=x+3)
{
Write_i2c_port( file, Z80_host_port_config_reset[x], Z80_host_port_config_reset[x+1], Z80_host_port_config_reset[x+2] );
}
printf("reset ports done!\n");
}
int write_program_ram(int file)
{
int i,la, ha, delay;
char k[32];
Write_i2c_port_bit( file, 0x21, 0x01, 2, 1); // Bus act
Write_i2c_port_bit( file, 0x21, 0x01, 4, 0); // Bus Request
Write_i2c_port_bit( file, 0x21, 0x13, 4, 0); // Bus Request
// Clock until Z80 releases bus
printf("Waiting for Z80 to release bus \n");
while(BUSACK_o != 0 )
{
read_bus_state( file );
// Write_i2c_port_bit( file, 0x22, 0x12, 5, 0);
// for(delay=0; delay < 200; delay++);
// Write_i2c_port_bit( file, 0x22, 0x12, 5, 1);
// for(delay=0; delay < 200; delay++);
}
printf("Bus ack %2x \n", BUSACK_o);
fileptr = fopen("main.bin", "rb"); // Open the file in binary mode
if (fileptr == NULL) printf("Error opening bin file\n");
fseek(fileptr, 0, SEEK_END); // Jump to the end of the file
filelen = ftell(fileptr); // Get the current byte offset in the file
rewind(fileptr); // Jump back to the beginning of the file
buffer = (char *)malloc(filelen+1); // Enough memory for file + \0
fread(buffer, filelen, 1, fileptr); // Read in the entire file
fclose(fileptr); // Close the file
Write_i2c_port( file, 0x20, 0x00, 0b00000000);
Write_i2c_port( file, 0x20, 0x01, 0b00000000);
Write_i2c_port( file, 0x21, 0x00, 0b00000000);
Write_i2c_port_bit( file, 0x22, 0x00, 0, 0); // ioreq
Write_i2c_port_bit( file, 0x22, 0x12, 0x00, 1); // ioreq
Write_i2c_port_bit( file, 0x22, 0x00, 1, 0); // Mreq
Write_i2c_port_bit( file, 0x21, 0x01, 1, 0); // WR
Write_i2c_port_bit( file, 0x21, 0x01, 0, 0); // RD
Write_i2c_port_bit( file, 0x21, 0x13, 1, 1); // WR
Write_i2c_port_bit( file, 0x21, 0x13, 0, 1); // RD
la = 0;
ha = 0;
Write_i2c_port_bit( file, 0x22, 0x12, 0x01, 0); // Mreq
for( i=0; i<filelen; i++)
{
// Write data
Write_i2c_port( file, 0x21, 0x12, (unsigned char)buffer[i]);
Write_i2c_port( file, 0x20, 0x13, ha);
Write_i2c_port( file, 0x20, 0x12, la);
//printf("Press Enter to cont. \n");
//fgets(k,31,stdin);
for(delay=0; delay < 200; delay++);
Write_i2c_port_bit( file, 0x21, 0x13, 1, 0); // WR
for(delay=0; delay < 200; delay++);
Write_i2c_port_bit( file, 0x21, 0x13, 1, 1); // WR
la++;
if (la > 0xff )
{
la = 0;
ha++;
};
read_bus_state( file );
printf("loading ram ");
printf("Address_bus =%2x%2x Data_bus =%2x \n ", Z80_address_bus_b, Z80_address_bus_a, (unsigned char)buffer[i] );
}
Write_i2c_port_bit( file, 0x21, 0x13, 1, 1); // WR
Write_i2c_port( file, 0x21, 0x00, 0b11111111);
la = 0;
ha = 0;
Write_i2c_port_bit( file, 0x22, 0x12, 0x01, 0); // Mreq
for( i=0; i<filelen; i++)
{
Write_i2c_port( file, 0x20, 0x13, ha);
Write_i2c_port( file, 0x20, 0x12, la);
for(delay=0; delay < 200; delay++);
Write_i2c_port_bit( file, 0x21, 0x13, 0, 0); // RD
for(delay=0; delay < 200; delay++);
read_bus_state( file );
printf("read back ram ");
printf("Address_bus =%2x%2x Data_bus =%2x \n", Z80_address_bus_b, Z80_address_bus_a, Z80_data_bus );
if (buffer[i] != Z80_data_bus)
{
printf("Read back error Data_bus =%2x != %2x \n", Z80_data_bus, buffer[i] );
};
Write_i2c_port_bit( file, 0x21, 0x13, 0, 1); // RD
la++;
if (la > 0xff )
{
la = 0;
ha++;
};
}
Write_i2c_port( file, 0x20, 0x00, 0b11111111);
Write_i2c_port( file, 0x20, 0x01, 0b11111111);
Write_i2c_port( file, 0x21, 0x00, 0b11111111);
Write_i2c_port_bit( file, 0x21, 0x13, 4, 1); // Bus Request
Write_i2c_port_bit( file, 0x21, 0x01, 1, 1); // WR
Write_i2c_port_bit( file, 0x21, 0x01, 0, 1); // RD
Write_i2c_port_bit( file, 0x22, 0x00, 0x01, 1); // Mreq
}
int read_bus_state( int file )
{
char low_byte, high_byte;
int address_temp;
/* Read Address Bus */
Z80_address_bus_a = Read_i2c_port( file, 0x20, 0x12);
Z80_address_bus_b = Read_i2c_port( file, 0x20, 0x13);
Z80_data_bus = Read_i2c_port( file, 0x21, 0x12);
Z80_control_bus_a = Read_i2c_port( file, 0x21, 0x13);
Z80_control_bus_b = Read_i2c_port( file, 0x22, 0x12);
M1_o = (Z80_control_bus_a & Bit_mask6) != 0;
MREQ_o = (Z80_control_bus_b & Bit_mask1) != 0;
RD_o = (Z80_control_bus_a & Bit_mask0) != 0;
WR_o = (Z80_control_bus_a & Bit_mask1) != 0;
RFSH_o = (Z80_control_bus_a & Bit_mask7) != 0;
HALT_o = (Z80_control_bus_b & Bit_mask2) != 0;
WAIT_i = (Z80_control_bus_a & Bit_mask3) != 0;
INT_i = (Z80_control_bus_b & Bit_mask4) != 0;
NMI_i = (Z80_control_bus_b & Bit_mask3) != 0;
RESET_i = (Z80_control_bus_a & Bit_mask5) != 0;
BUSREQ_i = (Z80_control_bus_a & Bit_mask4) != 0;
BUSACK_o = (Z80_control_bus_a & Bit_mask2) != 0;
CLK_i = (Z80_control_bus_b & Bit_mask5) != 0;
IOREQ_o = (Z80_control_bus_b & Bit_mask0) != 0;
}
/* host.h v0.1 by Eric Stringer eric.stringer@gmail.com */
/* define logic mask */
#define Bit_mask0 0b00000001
#define Bit_mask1 0b00000010
#define Bit_mask2 0b00000100
#define Bit_mask3 0b00001000
#define Bit_mask4 0b00010000
#define Bit_mask5 0b00100000
#define Bit_mask6 0b01000000
#define Bit_mask7 0b10000000