145 lines
4.0 KiB
C
145 lines
4.0 KiB
C
#include <Z/constants/pointer.h> /* Z_NULL */
|
|
#include <Z80.h>
|
|
#include <string.h>
|
|
|
|
#define CYCLES_PER_FRAME 69888
|
|
#define CYCLES_AT_INT 24
|
|
#define CYCLES_PER_INT 32
|
|
#define ROM_SIZE 0x8000 /* 32 KiB */
|
|
#define MEMORY_SIZE 0x8000 /* 32 KiB */
|
|
|
|
typedef struct {
|
|
void* context;
|
|
zuint8 (* read)(void *context);
|
|
void (* write)(void *context, zuint8 value);
|
|
zuint16 assigned_port;
|
|
} Device;
|
|
|
|
typedef struct {
|
|
zusize cycles;
|
|
zuint8 memory[65536];
|
|
Z80 cpu;
|
|
Device* devices;
|
|
zusize device_count;
|
|
} Machine;
|
|
|
|
|
|
Device *machine_find_device(Machine *self, zuint16 port)
|
|
{
|
|
zusize index = 0;
|
|
|
|
for (; index < self->device_count; index++)
|
|
if (self->devices[index].assigned_port == port)
|
|
return &self->devices[index];
|
|
|
|
return Z_NULL;
|
|
}
|
|
|
|
|
|
static zuint8 machine_cpu_read(Machine *self, zuint16 address)
|
|
{
|
|
return address < MEMORY_SIZE ? self->memory[address] : 0xFF;
|
|
}
|
|
|
|
|
|
static void machine_cpu_write(Machine *self, zuint16 address, zuint8 value)
|
|
{
|
|
if (address >= ROM_SIZE && address < MEMORY_SIZE)
|
|
self->memory[address] = value;
|
|
}
|
|
|
|
|
|
static zuint8 machine_cpu_in(Machine *self, zuint16 port)
|
|
{
|
|
Device *device = machine_find_device(self, port);
|
|
|
|
return device != Z_NULL ? device->read(device->context) : 0xFF;
|
|
}
|
|
|
|
|
|
static void machine_cpu_out(Machine *self, zuint16 port, zuint8 value)
|
|
{
|
|
Device *device = machine_find_device(self, port);
|
|
|
|
if (device != Z_NULL) device->write(device->context, value);
|
|
}
|
|
|
|
|
|
void machine_initialize(Machine *self)
|
|
{
|
|
self->cpu.context = self;
|
|
self->cpu.fetch_opcode =
|
|
self->cpu.fetch =
|
|
self->cpu.nop =
|
|
self->cpu.read = (Z80Read )machine_cpu_read;
|
|
self->cpu.write = (Z80Write)machine_cpu_write;
|
|
self->cpu.in = (Z80Read )machine_cpu_in;
|
|
self->cpu.out = (Z80Write)machine_cpu_out;
|
|
self->cpu.halt = Z_NULL;
|
|
self->cpu.nmia = Z_NULL;
|
|
self->cpu.inta = Z_NULL;
|
|
self->cpu.int_fetch = Z_NULL;
|
|
self->cpu.ld_i_a = Z_NULL;
|
|
self->cpu.ld_r_a = Z_NULL;
|
|
self->cpu.reti = Z_NULL;
|
|
self->cpu.retn = Z_NULL;
|
|
self->cpu.hook = Z_NULL;
|
|
self->cpu.illegal = Z_NULL;
|
|
self->cpu.options = Z80_MODEL_ZILOG_NMOS;
|
|
|
|
/* Create and initialize devices... */
|
|
}
|
|
|
|
|
|
void machine_power(Machine *self, zbool state)
|
|
{
|
|
if (state)
|
|
{
|
|
self->cycles = 0;
|
|
memset(self->memory, 0, 65536);
|
|
}
|
|
|
|
z80_power(&self->cpu, state);
|
|
}
|
|
|
|
|
|
void machine_reset(Machine *self)
|
|
{
|
|
z80_instant_reset(&self->cpu);
|
|
}
|
|
|
|
|
|
void machine_run_frame(Machine *self)
|
|
{
|
|
/* CPU cycles before the INT signal */
|
|
self->cycles += z80_execute(&self->cpu, CYCLES_AT_INT - self->cycles);
|
|
|
|
/* CPU cycles during the INT signal */
|
|
z80_int(&self->cpu, Z_TRUE);
|
|
self->cycles += z80_run(&self->cpu, (CYCLES_AT_INT + CYCLES_PER_INT) - self->cycles);
|
|
z80_int(&self->cpu, Z_FALSE);
|
|
|
|
/* CPU cycles after the INT signal */
|
|
self->cycles += z80_execute(&self->cpu, CYCLES_PER_FRAME - self->cycles);
|
|
|
|
self->cycles -= CYCLES_PER_FRAME;
|
|
}
|
|
|
|
int main() {
|
|
// Setup virtual Pat80 computer
|
|
Z80 pat80Cpu = {};
|
|
Device pat80Devices[] = {};
|
|
zuint8 pat80Memory[65536] = {0};
|
|
|
|
Machine pat80 = {
|
|
/*zusize*/ .cycles = 0,
|
|
/*zuint8*/ .memory = *pat80Memory,
|
|
/*Z80*/ .cpu = pat80Cpu,
|
|
/*Device**/ .devices = pat80Devices,
|
|
/*zusize*/ .device_count = 255
|
|
};
|
|
|
|
machine_initialize(&pat80);
|
|
machine_power(&pat80, Z_TRUE);
|
|
machine_reset(&pat80);
|
|
} |