|
|
0.32
/*****************************************************************************/
/* Generator - Sega Genesis emulation - (c) James Ponder 1997-1998 */
/*****************************************************************************/
/* */
/* z80.c */
/* */
/*****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "generator.h"
#include "cpuz80.h"
#include "cpu68k.h"
#include "memz80.h"
#include "ui.h"
#define BIG_ENDIAN
#include "z80/mz80.h"
#include "z80/cmz80.h"
UINT8 cpuz80_read_actual(UINT32 addr, struct MemoryReadByte *me);
void cpuz80_write_actual(UINT32 addr, UINT8 data, struct MemoryWriteByte *me);
UINT16 cpuz80_ioread_actual(UINT16 addr, struct z80PortRead *me);
void cpuz80_iowrite_actual(UINT16 addr, UINT8 data, struct z80PortWrite *me);
UINT8 cpuz80c_read_actual(UINT32 addr, struct MemoryReadByte *me);
void cpuz80c_write_actual(UINT32 addr, UINT8 data, struct MemoryWriteByte *me);
UINT16 cpuz80c_ioread_actual(UINT16 addr, struct z80PortRead *me);
void cpuz80c_iowrite_actual(UINT16 addr, UINT8 data, struct z80PortWrite *me);
/*** variables externed ***/
uint8 *cpuz80_ram = NULL;
uint32 cpuz80_bank = 0;
unsigned int cpuz80_active = 0;
/*** global variables ***/
static unsigned int cpuz80_lastsync = 0;
static unsigned int cpuz80_resetting = 0;
static CONTEXTMZ80 cpuz80_z80;
static CONTEXTCMZ80 cpuz80c_z80;
struct {
uint32 addr;
uint8 data;
} reads[256];
uint32 readpointer_head = 0;
uint32 readpointer_tail = 0;
struct {
uint32 addr;
uint8 data;
} writes[256];
uint32 writepointer_head = 0;
uint32 writepointer_tail = 0;
static struct MemoryReadByte cpuz80_read[] = {
{ 0x0000, 0xFFFF, cpuz80_read_actual, NULL },
{ -1, -1, NULL, NULL }
};
static struct MemoryWriteByte cpuz80_write[] = {
{ 0x0000, 0xFFFF, cpuz80_write_actual, NULL },
{ -1, -1, NULL, NULL }
};
static struct z80PortRead cpuz80_ioread[] = {
{ 0x0000, 0x00FF, cpuz80_ioread_actual, NULL },
{ -1, -1, NULL, NULL }
};
static struct z80PortWrite cpuz80_iowrite[] = {
{ 0x0000, 0x00FF, cpuz80_iowrite_actual, NULL },
{ -1, -1, NULL, NULL }
};
static struct MemoryReadByte cpuz80c_read[] = {
{ 0x0000, 0xFFFF, cpuz80c_read_actual, NULL },
{ -1, -1, NULL, NULL }
};
static struct MemoryWriteByte cpuz80c_write[] = {
{ 0x0000, 0xFFFF, cpuz80c_write_actual, NULL },
{ -1, -1, NULL, NULL }
};
static struct z80PortRead cpuz80c_ioread[] = {
{ 0x0000, 0x00FF, cpuz80c_ioread_actual, NULL },
{ -1, -1, NULL, NULL }
};
static struct z80PortWrite cpuz80c_iowrite[] = {
{ 0x0000, 0x00FF, cpuz80c_iowrite_actual, NULL },
{ -1, -1, NULL, NULL }
};
UINT8 cpuz80_read_actual(UINT32 addr, struct MemoryReadByte *me)
{
uint8 data;
(void)me;
if (((readpointer_head+1)%256) == readpointer_tail)
ui_err("read overrun during REAL read to %08X (p=%d)",
addr, readpointer_head);
data = memz80_fetchbyte((uint32)addr);
LOG_CRITICAL(("REAL read to %08X = %02X (p=%d)", addr, data,
readpointer_head));
reads[readpointer_head].addr = addr;
reads[readpointer_head].data = data;
if (++readpointer_head >= 256)
readpointer_head = 0;
return data;
}
void cpuz80_write_actual(UINT32 addr, UINT8 data, struct MemoryWriteByte *me)
{
(void)me;
LOG_CRITICAL(("REAL write to %08X of %02X (p=%d)", addr, data,
writepointer_head));
if (((writepointer_head+1)%256) == writepointer_tail)
ui_err("write overrun");
writes[writepointer_head].addr = addr;
writes[writepointer_head].data = data;
if (++writepointer_head >= 256)
writepointer_head = 0;
memz80_storebyte((uint32)addr, (uint8)data);
}
UINT16 cpuz80_ioread_actual(UINT16 addr, struct z80PortRead *me)
{
(void)me;
return cpuz80_portread((uint16)addr);
}
void cpuz80_iowrite_actual(UINT16 addr, UINT8 data, struct z80PortWrite *me)
{
(void)me;
cpuz80_portwrite((uint16)addr, (uint8)data);
}
UINT8 cpuz80c_read_actual(UINT32 addr, struct MemoryReadByte *me)
{
uint8 data;
(void)me;
if (readpointer_tail == readpointer_head)
ui_err("read underrun");
if (reads[readpointer_tail].addr != addr)
ui_err("read address mismatch");
data = reads[readpointer_tail].data;
LOG_CRITICAL(("FAKE read to %08X = %02X", addr, data));
readpointer_tail = (readpointer_tail+1) % 256;
return data;
}
void cpuz80c_write_actual(UINT32 addr, UINT8 data, struct MemoryWriteByte *me)
{
(void)me;
LOG_CRITICAL(("FAKE write to %08X of %02X (p=%d)", addr, data,
writepointer_tail));
if (writepointer_tail == writepointer_head) {
LOG_CRITICAL(("write underrun"));
return;
}
if (writes[writepointer_tail].addr != addr &&
writes[writepointer_tail].data != data)
ui_err("write address AND data mismatch");
if (writes[writepointer_tail].addr != addr)
ui_err("write address mismatch");
if (writes[writepointer_tail].data != data)
ui_err("write data mismatch");
writepointer_tail = (writepointer_tail+1) % 256;
}
UINT16 cpuz80c_ioread_actual(UINT16 addr, struct z80PortRead *me)
{
(void)me;
ui_err("ioread");
return 0;
}
void cpuz80c_iowrite_actual(UINT16 addr, UINT8 data, struct z80PortWrite *me)
{
(void)me;
ui_err("iowrite");
}
/*** cpuz80_init - initialise this sub-unit ***/
int cpuz80_init(void)
{
cmz80init();
cpuz80_reset();
return 0;
}
/*** cpuz80_reset - reset z80 sub-unit ***/
void cpuz80_reset(void)
{
if (!cpuz80_ram) {
if ((cpuz80_ram = malloc(LEN_SRAM)) == NULL) {
fprintf(stderr, "Out of memory\n");
exit(1);
}
}
memset(cpuz80_ram, 0, LEN_SRAM);
cpuz80_resetcpu();
cpuz80_bank = 0;
cpuz80_active = 0;
cpuz80_lastsync = 0;
cpuz80_resetting = 0;
/* mz80GetContext(&cpuz80_z80); */
memset(&cpuz80_z80, 0, sizeof(cpuz80_z80));
cpuz80_z80.z80Base = cpuz80_ram;
cpuz80_z80.z80MemRead = cpuz80_read;
cpuz80_z80.z80MemWrite = cpuz80_write;
cpuz80_z80.z80IoRead = cpuz80_ioread;
cpuz80_z80.z80IoWrite = cpuz80_iowrite;
mz80SetContext(&cpuz80_z80);
mz80reset();
;
memset(&cpuz80c_z80, 0, sizeof(cpuz80c_z80));
cpuz80c_z80.z80Base = cpuz80_ram;
cpuz80c_z80.z80MemRead = cpuz80c_read;
cpuz80c_z80.z80MemWrite = cpuz80c_write;
cpuz80c_z80.z80IoRead = cpuz80c_ioread;
cpuz80c_z80.z80IoWrite = cpuz80c_iowrite;
cmz80SetContext(&cpuz80c_z80);
cmz80reset();
}
/*** cpuz80_resetcpu - reset z80 cpu ***/
void cpuz80_resetcpu(void)
{
mz80reset();
cmz80reset();
cpuz80_resetting = 1; /* suspends execution */
}
/*** cpuz80_unresetcpu - unreset z80 cpu ***/
void cpuz80_unresetcpu(void)
{
cpuz80_resetting = 0; /* un-suspends execution */
}
/*** cpuz80_bankwrite - data is being written to latch ***/
void cpuz80_bankwrite(uint8 data)
{
cpuz80_bank = (((cpuz80_bank >> 1) | ((data & 1) <<23)) & 0xff8000);
/*
if (gen_debug)
printf("BANK WRITE: %d --> %08X\n", data, cpuz80_bank);
*/
}
/*** cpuz80_stop - stop the processor ***/
void cpuz80_stop(void)
{
cpuz80_sync();
cpuz80_active = 0;
}
/*** cpuz80_start - start the processor ***/
void cpuz80_start(void)
{
cpuz80_sync();
cpuz80_active = 1;
}
/*** cpuz80_endfield - reset counters ***/
void cpuz80_endfield(void)
{
cpuz80_lastsync = 0;
}
/*** cpuz80_sync - synchronise ***/
void cpuz80_sync(void)
{
int cpu68k_wanted = cpu68k_clocks - cpuz80_lastsync;
int wanted = (cpu68k_wanted<0?0:cpu68k_wanted)*7/16;
int achieved, achieved_c;
uint32 oldpc;
if (cpuz80_active && !cpuz80_resetting) {
/* ui_log(LOG_USER, "executing %d z80 clocks @ %X", wanted,
cpuz80_z80.z80pc); */
printf("context: s=%08X c=%08X\n", &cpuz80_z80, &cpuz80c_z80);
printf("pc invalid: %08X %08X\n", &cpuz80_z80.z80pc, &cpuz80c_z80.z80pc);
mz80GetContext(&cpuz80_z80);
cmz80GetContext(&cpuz80c_z80);
printf("pc start: %08X %08X\n", cpuz80_z80.z80pc, cpuz80c_z80.z80pc);
printf("opcodes: %02x(%02x) %02x(%02x)\n", cpuz80_ram[cpuz80_z80.z80pc],
cpuz80_ram[cpuz80_z80.z80pc+1],
cpuz80_ram[cpuz80c_z80.z80pc],
cpuz80_ram[cpuz80c_z80.z80pc+1]);
if (cpuz80_z80.z80pc != cpuz80c_z80.z80pc) {
ui_err("sPC = %08X / cPC = %08X mismatch on entry",
cpuz80_z80.z80pc, cpuz80c_z80.z80pc);
}
printf("Pending ints: s = %X c = %X\n",
cpuz80_z80.z80intPending, cpuz80c_z80.z80intPending);
printf("DE on entry: s=%X c=%X\n", cpuz80_z80.z80de.de,
cpuz80c_z80.z80de.de);
oldpc = cpuz80_z80.z80pc;
printf("Attempting to execute %d clocks...\n", wanted);
mz80exec(wanted); /* wanted */
cmz80exec(wanted);
achieved = mz80GetElapsedTicks(1);
achieved_c = cmz80GetElapsedTicks(1);
mz80GetContext(&cpuz80_z80);
cmz80GetContext(&cpuz80c_z80);
LOG_CRITICAL(("achieved s=%d c=%d", achieved, achieved_c));
printf("pc end: %08X %08X\n", cpuz80_z80.z80pc, cpuz80c_z80.z80pc);
printf("Exit pending ints: s = %X c = %X\n",
cpuz80_z80.z80intPending, cpuz80c_z80.z80intPending);
if (cpuz80_z80.z80af.af != cpuz80c_z80.z80af.af)
ui_err("AF differs: s=%X c=%X", cpuz80_z80.z80af.af,
cpuz80c_z80.z80af.af);
if (cpuz80_z80.z80bc.bc != cpuz80c_z80.z80bc.bc)
ui_err("BC differs: s=%X c=%X", cpuz80_z80.z80bc.bc,
cpuz80c_z80.z80bc.bc);
if (cpuz80_z80.z80de.de != cpuz80c_z80.z80de.de)
ui_err("DE differs: s=%X c=%X", cpuz80_z80.z80de.de,
cpuz80c_z80.z80de.de);
if (cpuz80_z80.z80hl.hl != cpuz80c_z80.z80hl.hl)
ui_err("HL differs: s=%X c=%X", cpuz80_z80.z80hl.hl,
cpuz80c_z80.z80hl.hl);
if (cpuz80_z80.z80ix.ix != cpuz80c_z80.z80ix.ix)
ui_err("IX differs: s=%X c=%X", cpuz80_z80.z80ix.ix,
cpuz80c_z80.z80ix.ix);
if (cpuz80_z80.z80iy.iy != cpuz80c_z80.z80iy.iy)
ui_err("IY differs: s=%X c=%X", cpuz80_z80.z80iy.iy,
cpuz80c_z80.z80iy.iy);
if (cpuz80_z80.z80pc != cpuz80c_z80.z80pc) {
ui_err("sPC = %08X / cPC = %08X mismatch on exit",
cpuz80_z80.z80pc, cpuz80c_z80.z80pc);
}
if (cpuz80_z80.z80intPending != cpuz80c_z80.z80intPending) {
/*
ui_err("sIntPending = %X / cIntPending = %X\n",
cpuz80_z80.z80intPending, cpuz80c_z80.z80intPending);
*/
}
if (achieved != achieved_c) {
LOG_CRITICAL(("oldpc=%08X newpc=%08X", oldpc, cpuz80_z80.z80pc));
ui_err("achieved clocks mismatch: s=%d c=%d", achieved, achieved_c);
}
/* this if/else statement below, I'm not entirely sure this is a good
idea, perhaps just doing cpuz80_lastsync = cpu68k_clocks; always is
better? hmm. */
if (achieved > wanted) {
cpuz80_lastsync = cpu68k_clocks;
} else {
cpuz80_lastsync = cpuz80_lastsync + achieved*16/7;
}
} else {
cpuz80_lastsync = cpu68k_clocks;
}
}
/*** cpuz80_interrupt - cause an interrupt on the z80 */
void cpuz80_interrupt(void)
{
if (!cpuz80_resetting) {
LOG_CRITICAL(("interrupt!!!!!!!!!!!!!"));
mz80int(0);
cmz80int(0);
}
}
/*** cpuz80_portread - port read from z80 */
uint8 cpuz80_portread(uint8 port)
{
LOG_VERBOSE(("[Z80] Port read to %X", port));
return 0;
}
/*** cpuz80_portwrite - z80 write to port */
void cpuz80_portwrite(uint8 port, uint8 value)
{
LOG_VERBOSE(("[Z80] Port write to %X of %X", port, value));
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.