kopia lustrzana https://github.com/Jean-MarcHarvengt/MCUME
changed z80 emulator to the cycle-stepped one
rodzic
88ef857bca
commit
a2553293f9
|
@ -11,8 +11,10 @@ extern "C" {
|
|||
#include "emuapi.h"
|
||||
#include "platform_config.h"
|
||||
}
|
||||
#include "processor/Z80.h"
|
||||
#include "processor/Tables.h"
|
||||
#ifndef CHIPS_IMPL
|
||||
#define CHIPS_IMPL
|
||||
#endif
|
||||
#include "z80.h"
|
||||
#include "crtc.h"
|
||||
#include "ga.h"
|
||||
#include "roms/rom464.h"
|
||||
|
@ -29,14 +31,58 @@ extern "C" {
|
|||
|
||||
uint8_t RAM[0x10000]; // 64k
|
||||
unsigned char* bitstream = 0; // 16k video ram to be used by PIO.
|
||||
unsigned char* bitstream_init_pos = 0;
|
||||
static Z80 CPU;
|
||||
static z80_t CPU;
|
||||
uint64_t pins;
|
||||
bool interrupt_generated = false;
|
||||
int sline = 0;
|
||||
int cycles_left = 0;
|
||||
bool test_flag = false;
|
||||
|
||||
// Implementations of system-specific emuapi Init, Step etc. functions.
|
||||
// Helper functions
|
||||
|
||||
char read_z80(uint16_t Addr)
|
||||
{
|
||||
if(Addr <= LOWER_ROM_END && ga_config.lower_rom_enable)
|
||||
{
|
||||
// printf("At program counter %x, Z80 read from address %x in OS ROM\n", CPU.PC.W, Addr);
|
||||
return gb_rom_464_0[Addr];
|
||||
}
|
||||
else if(Addr >= UPPER_ROM_BEGIN && ga_config.upper_rom_enable)
|
||||
{
|
||||
// printf("At program counter %x, Z80 read from address %x in BASIC ROM\n", CPU.PC.W, Addr);
|
||||
return gb_rom_464_1[Addr - 0xC000];
|
||||
}
|
||||
else
|
||||
{
|
||||
// printf("At program counter %x, Z80 read from address %x in RAM\n", CPU.PC.W, Addr);
|
||||
return RAM[Addr];
|
||||
}
|
||||
}
|
||||
|
||||
void write_z80(uint16_t Addr, uint8_t Value)
|
||||
{
|
||||
RAM[Addr] = Value;
|
||||
}
|
||||
|
||||
void out_z80(uint16_t Port, uint8_t Value)
|
||||
{
|
||||
if(!(Port & 0x8000)) write_gate_array(Value); // The Gate Array is selected when bit 15 is set to 0.
|
||||
if(!(Port & 0x4000)) write_crt_controller(Port, Value); // The CRTC is selected when bit 14 is set to 0.
|
||||
if(!(Port & 0x2000))
|
||||
{
|
||||
// upper rom bank number. ROM banking needs to be done regardless of CPC model
|
||||
// The Upper ROM Bank Number (in range of 0x00..0xFF) to be mapped to memory at 0xC000..0xFFFF
|
||||
|
||||
// byte req_bank_number = Value & 15;
|
||||
// if(ga_config.upper_rom_enable)
|
||||
// {
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t in_z80(uint16_t Port)
|
||||
{
|
||||
if(!(Port & 0x4000)) return read_crt_controller(Port); // The CRTC is selected when bit 14 is set to 0.
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates initial emulation state (i.e. sets up color palette, clears memory etc.)
|
||||
|
@ -49,9 +95,8 @@ void cpc_Init(void)
|
|||
emu_SetPaletteEntry(firmware_palette[i].R, firmware_palette[i].G, firmware_palette[i].B, i);
|
||||
}
|
||||
if (bitstream == 0) bitstream = (unsigned char *)emu_Malloc(WIDTH*HEIGHT); //*HEIGHT
|
||||
bitstream_init_pos = bitstream;
|
||||
|
||||
ResetZ80(&CPU, CYCLES_PER_FRAME);
|
||||
pins = z80_init(&CPU);
|
||||
memset(RAM, 0, sizeof(RAM));
|
||||
}
|
||||
|
||||
|
@ -60,12 +105,9 @@ void cpc_Init(void)
|
|||
*/
|
||||
void cpc_Start(char* filename)
|
||||
{
|
||||
CPU.PC.W = 0x0000;
|
||||
//CPU.IFF = IFF_IM1;
|
||||
ga_config.lower_rom_enable = true;
|
||||
ga_config.upper_rom_enable = false;
|
||||
ga_config.interrupt_counter = 0;
|
||||
// write_gate_array(0xC0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,24 +115,77 @@ void cpc_Start(char* filename)
|
|||
*/
|
||||
void cpc_Step(void)
|
||||
{
|
||||
for(;!is_hsync_active();)
|
||||
//for(;!is_hsync_active();)
|
||||
//{
|
||||
|
||||
// if not (z80 wait and ga wait) then tick, otherwise stall.
|
||||
// or rather the tick will be a stall if both waits are asserted, i think that's better.
|
||||
bool interrupt_acknowledged = false;
|
||||
if(!(pins&Z80_WAIT && ga_config.wait_signal))
|
||||
{
|
||||
cycles_left = ExecZ80(&CPU, 24); // execute for the duration of 6 NOPs (maximum instruction length)
|
||||
for(int k = 0; k < (24 - cycles_left) / 4; k++)
|
||||
pins = z80_tick(&CPU, pins);
|
||||
if (pins & Z80_MREQ)
|
||||
{
|
||||
crtc_step();
|
||||
interrupt_generated = ga_step();
|
||||
if(interrupt_generated)
|
||||
const uint16_t addr = Z80_GET_ADDR(pins);
|
||||
if (pins & Z80_RD)
|
||||
{
|
||||
// printf("Interrupting!\n");
|
||||
IntZ80(&CPU, INT_RST38);
|
||||
ga_config.interrupt_counter &= 0x1f;
|
||||
uint8_t data = read_z80(addr);
|
||||
Z80_SET_DATA(pins, data);
|
||||
}
|
||||
else if (pins & Z80_WR)
|
||||
{
|
||||
uint8_t data = Z80_GET_DATA(pins);
|
||||
write_z80(addr, data);
|
||||
}
|
||||
}
|
||||
else if (pins & Z80_IORQ)
|
||||
{
|
||||
const uint16_t port = Z80_GET_ADDR(pins);
|
||||
if (pins & Z80_M1)
|
||||
{
|
||||
// an interrupt acknowledge cycle, depending on the emulated system,
|
||||
// put either an instruction byte, or an interrupt vector on the data bus
|
||||
Z80_SET_DATA(pins, 0x0038);
|
||||
interrupt_acknowledged = true;
|
||||
}
|
||||
else if (pins & Z80_RD)
|
||||
{
|
||||
// handle IO input request at port
|
||||
in_z80(port);
|
||||
}
|
||||
else if (pins & Z80_WR)
|
||||
{
|
||||
// handle IO output request at port
|
||||
uint8_t data = Z80_GET_DATA(pins);
|
||||
out_z80(port, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emu_DrawLine8(bitstream, WIDTH, HEIGHT, sline);
|
||||
sline = (sline + 1) % NBLINES;
|
||||
crtc_step();
|
||||
interrupt_generated = ga_step();
|
||||
if(interrupt_generated)
|
||||
{
|
||||
// To request an interrupt, or inject a wait state just set the respective pin
|
||||
// (Z80_INT, Z80_NMI, Z80_WAIT), don't forget to clear the pin again later (the
|
||||
// details on when those pins are set and cleared depend heavily on the
|
||||
// emulated system).
|
||||
|
||||
// request an interrupt from the CPU
|
||||
// TODO how to set the Z80_INT pin?
|
||||
|
||||
}
|
||||
|
||||
if(interrupt_acknowledged)
|
||||
{
|
||||
ga_config.interrupt_counter &= 0x1f;
|
||||
}
|
||||
|
||||
if(is_hsync_active())
|
||||
{
|
||||
sline = (sline + 1) % NBLINES;
|
||||
emu_DrawLine8(bitstream, WIDTH, HEIGHT, sline);
|
||||
}
|
||||
|
||||
if(is_vsync_active())
|
||||
{
|
||||
|
@ -108,70 +203,10 @@ void cpc_Step(void)
|
|||
crtc_step();
|
||||
ga_step();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Input handler.
|
||||
*/
|
||||
void cpc_Input(int bClick)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void draw_vsync()
|
||||
{
|
||||
emu_DrawVsync();
|
||||
}
|
||||
|
||||
// System-specific implementations of the Z80 instructions required by the portable Z80 emulator.
|
||||
|
||||
void OutZ80(word Port, byte Value)
|
||||
{
|
||||
if(!(Port & 0x8000)) write_gate_array(Value); // The Gate Array is selected when bit 15 is set to 0.
|
||||
if(!(Port & 0x4000)) write_crt_controller(Port, Value); // The CRTC is selected when bit 14 is set to 0.
|
||||
if(!(Port & 0x2000))
|
||||
{
|
||||
// upper rom bank number. ROM banking needs to be done regardless of CPC model
|
||||
// The Upper ROM Bank Number (in range of 0x00..0xFF) to be mapped to memory at 0xC000..0xFFFF
|
||||
|
||||
// byte req_bank_number = Value & 15;
|
||||
// if(ga_config.upper_rom_enable)
|
||||
// {
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
byte InZ80(word Port)
|
||||
{
|
||||
if(!(Port & 0x4000)) return read_crt_controller(Port); // The CRTC is selected when bit 14 is set to 0.
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void WrZ80(word Addr, byte Value)
|
||||
{
|
||||
RAM[Addr] = Value;
|
||||
}
|
||||
|
||||
void PatchZ80(Z80 *R)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
byte RdZ80(word Addr)
|
||||
{
|
||||
if(Addr <= LOWER_ROM_END && ga_config.lower_rom_enable)
|
||||
{
|
||||
// printf("At program counter %x, Z80 read from address %x in OS ROM\n", CPU.PC.W, Addr);
|
||||
return gb_rom_464_0[Addr];
|
||||
}
|
||||
else if(Addr >= UPPER_ROM_BEGIN && ga_config.upper_rom_enable)
|
||||
{
|
||||
// printf("At program counter %x, Z80 read from address %x in BASIC ROM\n", CPU.PC.W, Addr);
|
||||
return gb_rom_464_1[Addr - 0xC000];
|
||||
}
|
||||
else
|
||||
{
|
||||
// printf("At program counter %x, Z80 read from address %x in RAM\n", CPU.PC.W, Addr);
|
||||
return RAM[Addr];
|
||||
}
|
||||
}
|
|
@ -28,40 +28,44 @@ uint8_t char_line_count = 0;
|
|||
uint8_t scanline_count = 0;
|
||||
uint8_t vertical_adjust_count = 0;
|
||||
uint16_t memory_start_addr = 0;
|
||||
uint8_t microsec_count_crtc = 0;
|
||||
|
||||
|
||||
void crtc_step()
|
||||
{
|
||||
horizontal_count++;
|
||||
|
||||
if(horizontal_count > registers[0])
|
||||
if(microsec_count_crtc == 3)
|
||||
{
|
||||
// horizontal counter is equal to the Horizontal Total Register.
|
||||
horizontal_count = 0;
|
||||
scanline_count++;
|
||||
}
|
||||
|
||||
if(scanline_count > registers[9])
|
||||
{
|
||||
// The counter for Maximum Raster Address is equal to it.
|
||||
// The height of a character is 8 rasters, so when we reach 8 rasters we increment the char line count.
|
||||
|
||||
scanline_count = 0;
|
||||
char_line_count++;
|
||||
horizontal_count++;
|
||||
|
||||
}
|
||||
if(horizontal_count > registers[0])
|
||||
{
|
||||
// horizontal counter is equal to the Horizontal Total Register.
|
||||
horizontal_count = 0;
|
||||
scanline_count++;
|
||||
}
|
||||
|
||||
if(char_line_count > registers[4])
|
||||
{
|
||||
// The vertical counter reaches the Vertical Total register.
|
||||
char_line_count = 0;
|
||||
}
|
||||
if(scanline_count > registers[9])
|
||||
{
|
||||
// The counter for Maximum Raster Address is equal to it.
|
||||
// The height of a character is 8 rasters, so when we reach 8 rasters we increment the char line count.
|
||||
|
||||
scanline_count = 0;
|
||||
char_line_count++;
|
||||
|
||||
}
|
||||
|
||||
if(char_line_count == 0 && horizontal_count == 0)
|
||||
{
|
||||
memory_start_addr = ((uint16_t) registers[12] << 8) | registers[13];
|
||||
}
|
||||
if(char_line_count > registers[4])
|
||||
{
|
||||
// The vertical counter reaches the Vertical Total register.
|
||||
char_line_count = 0;
|
||||
}
|
||||
|
||||
if(char_line_count == 0 && horizontal_count == 0)
|
||||
{
|
||||
memory_start_addr = ((uint16_t) registers[12] << 8) | registers[13];
|
||||
}
|
||||
}
|
||||
microsec_count_crtc = (microsec_count_crtc + 1) % 4;
|
||||
}
|
||||
|
||||
uint16_t crtc_generate_addr()
|
||||
|
@ -98,7 +102,7 @@ bool is_vsync_active()
|
|||
int8_t char_height = (int8_t) registers[9] + 1;
|
||||
int8_t char_lines_counted = (int8_t) char_line_count - registers[7];
|
||||
return char_height * char_lines_counted + (int8_t) scanline_count >= 0 &&
|
||||
char_height * char_lines_counted + (int8_t) scanline_count <= 16*8;
|
||||
char_height * char_lines_counted + (int8_t) scanline_count <= 16;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "cpc.h"
|
||||
|
||||
struct GAConfig ga_config;
|
||||
uint8_t microsecond_count_ga = 0;
|
||||
|
||||
/**
|
||||
* Some of the colours are duplicates, because select_pen_colour() uses the least significant
|
||||
|
@ -87,7 +88,6 @@ bool update_interrupts()
|
|||
ga_config.interrupt_counter++;
|
||||
ga_config.vsync_delay_count++;
|
||||
|
||||
|
||||
if(ga_config.interrupt_counter == 52)
|
||||
{
|
||||
//printf("Interrupt generated! \n");
|
||||
|
@ -212,23 +212,29 @@ void address_to_pixels()
|
|||
break;
|
||||
}
|
||||
free(pixels);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ga_step()
|
||||
{
|
||||
bool interrupt_generated = update_interrupts();
|
||||
//if(is_within_display())
|
||||
//{
|
||||
address_to_pixels();
|
||||
//}
|
||||
|
||||
ga_config.hsync_active = is_hsync_active();
|
||||
ga_config.vsync_active = is_vsync_active();
|
||||
ga_config.wait_signal = microsecond_count_ga == 2;
|
||||
|
||||
return interrupt_generated;
|
||||
if(microsecond_count_ga == 3)
|
||||
{
|
||||
bool interrupt_generated = update_interrupts();
|
||||
//if(is_within_display())
|
||||
//{
|
||||
address_to_pixels();
|
||||
//}
|
||||
|
||||
ga_config.hsync_active = is_hsync_active();
|
||||
ga_config.vsync_active = is_vsync_active();
|
||||
microsecond_count_ga = (microsecond_count_ga + 1) % 4;
|
||||
return interrupt_generated;
|
||||
}
|
||||
microsecond_count_ga = (microsecond_count_ga + 1) % 4;
|
||||
return false;
|
||||
}
|
||||
|
||||
void select_pen(uint8_t value)
|
||||
|
|
|
@ -30,6 +30,7 @@ struct GAConfig {
|
|||
bool hsync_active = false;
|
||||
bool vsync_active = false;
|
||||
uint8_t ram_banking = 0; // unused in CPC 464
|
||||
bool wait_signal = true;
|
||||
};
|
||||
|
||||
extern struct RGB firmware_palette[27];
|
||||
|
|
|
@ -13,44 +13,44 @@
|
|||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
|
||||
static const byte Cycles[256] =
|
||||
{
|
||||
4,12, 8, 8, 4, 4, 8, 4, 4,12, 8, 8, 4, 4, 8, 4,
|
||||
8,12, 8, 8, 4, 4, 8, 4,12,12, 8, 8, 4, 4, 8, 4,
|
||||
8,12,16, 8, 4, 4, 8, 4, 8,12,16, 8, 4, 4, 8, 4,
|
||||
8,12,16, 8,12,12,12, 4, 8,12,16, 8, 4, 4, 8, 4,
|
||||
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||
8, 8, 8, 8, 8, 8, 4, 8, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||
8,12,12,12,12,12, 8,12, 8,12,12, 0,12,20, 8,12,
|
||||
8,12,12,12,12,12, 8,12, 8, 4,12,12,12, 0, 8,12,
|
||||
8,12,12,20,12,12, 8,12, 8, 4,12, 4,12, 0, 8,12,
|
||||
8,12,12, 4,12,12, 8,12, 8, 8,12, 4,12, 0, 8,12
|
||||
};
|
||||
static const byte Cycles[256] =
|
||||
{
|
||||
4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4,
|
||||
8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4,
|
||||
7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4,
|
||||
7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4,
|
||||
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
|
||||
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
|
||||
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
|
||||
7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4,
|
||||
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
|
||||
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
|
||||
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
|
||||
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
|
||||
5,10,10,10,10,11, 7,11, 5,10,10, 0,10,17, 7,11,
|
||||
5,10,10,11,10,11, 7,11, 5, 4,10,11,10, 0, 7,11,
|
||||
5,10,10,19,10,11, 7,11, 5, 4,10, 4,10, 0, 7,11,
|
||||
5,10,10, 4,10,11, 7,11, 5, 6,10, 4,10, 0, 7,11
|
||||
};
|
||||
|
||||
static const byte CyclesCB[256] =
|
||||
{
|
||||
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
|
||||
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
|
||||
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
|
||||
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
|
||||
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
|
||||
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
|
||||
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
|
||||
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
|
||||
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
|
||||
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
|
||||
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
|
||||
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
|
||||
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
|
||||
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
|
||||
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
|
||||
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
|
||||
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
|
||||
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
|
||||
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
|
||||
8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8
|
||||
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
|
||||
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
|
||||
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
|
||||
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
|
||||
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
|
||||
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
|
||||
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
|
||||
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8
|
||||
};
|
||||
|
||||
static const byte CyclesED[256] =
|
||||
|
@ -59,10 +59,10 @@ static const byte CyclesED[256] =
|
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
12,12,16,20, 8,16, 8, 12,12,12,16,20, 0,16, 0, 12,
|
||||
12,12,16,20, 0, 0, 8, 12,12,12,16,20, 0, 0, 8, 12,
|
||||
12,12,16,20, 0, 0, 0,20,12,12,16,20, 0, 0, 0,20,
|
||||
12, 0,16,20, 0, 0, 0, 0,12,12,16,20, 0, 0, 0, 0,
|
||||
12,12,15,20, 8,14, 8, 9,12,12,15,20, 0,14, 0, 9,
|
||||
12,12,15,20, 0, 0, 8, 9,12,12,15,20, 0, 0, 8, 9,
|
||||
12,12,15,20, 0, 0, 0,18,12,12,15,20, 0, 0, 0,18,
|
||||
12, 0,15,20, 0, 0, 0, 0,12,12,15,20, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16,16,16,16, 0, 0, 0, 0,16,16,16,16, 0, 0, 0, 0,
|
||||
|
@ -75,42 +75,42 @@ static const byte CyclesED[256] =
|
|||
|
||||
static const byte CyclesXX[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0,16, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0,16, 0, 0, 0, 0, 0, 0,
|
||||
0,16,20,12, 12, 12, 12, 0, 0,16,20,12, 12, 12, 12, 0,
|
||||
0, 0, 0, 0,24,24,20, 0, 0,16, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 12, 12,20, 0, 0, 0, 0, 0, 12, 12,20, 0,
|
||||
0, 0, 0, 0, 12, 12,20, 0, 0, 0, 0, 0, 12, 12,20, 0,
|
||||
12, 12, 12, 12, 12, 12,20, 12, 12, 12, 12, 12, 12, 12,20, 12,
|
||||
20,20,20,20,20,20,20,20, 0, 0, 0, 0, 12, 12,20, 0,
|
||||
0, 0, 0, 0, 12, 12,20, 0, 0, 0, 0, 0, 12, 12,20, 0,
|
||||
0, 0, 0, 0, 12, 12,20, 0, 0, 0, 0, 0, 12, 12,20, 0,
|
||||
0, 0, 0, 0, 12, 12,20, 0, 0, 0, 0, 0, 12, 12,20, 0,
|
||||
0, 0, 0, 0, 12, 12,20, 0, 0, 0, 0, 0, 12, 12,20, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0, 0, 0, 0, 0, 0,
|
||||
0,14,20,10, 9, 9, 9, 0, 0,15,20,10, 9, 9, 9, 0,
|
||||
0, 0, 0, 0,23,23,19, 0, 0,15, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0,
|
||||
0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0,
|
||||
9, 9, 9, 9, 9, 9,19, 9, 9, 9, 9, 9, 9, 9,19, 9,
|
||||
19,19,19,19,19,19,19,19, 0, 0, 0, 0, 9, 9,19, 0,
|
||||
0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0,
|
||||
0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0,
|
||||
0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0,
|
||||
0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,16, 0,24, 0,16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0,12, 0, 0, 0, 0, 0, 0
|
||||
0,14, 0,23, 0,15, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0,10, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static const byte CyclesXXCB[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0,24, 0, 0, 0, 0, 0, 0, 0,24, 0,
|
||||
0, 0, 0, 0, 0, 0,24, 0, 0, 0, 0, 0, 0, 0,24, 0,
|
||||
0, 0, 0, 0, 0, 0,24, 0, 0, 0, 0, 0, 0, 0,24, 0,
|
||||
0, 0, 0, 0, 0, 0,24, 0, 0, 0, 0, 0, 0, 0,24, 0,
|
||||
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
|
||||
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
|
||||
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
|
||||
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
0, 0, 0, 0, 0, 0,24, 0, 0, 0, 0, 0, 0, 0,24, 0,
|
||||
0, 0, 0, 0, 0, 0,24, 0, 0, 0, 0, 0, 0, 0,24, 0,
|
||||
0, 0, 0, 0, 0, 0,24, 0, 0, 0, 0, 0, 0, 0,24, 0,
|
||||
0, 0, 0, 0, 0, 0,24, 0, 0, 0, 0, 0, 0, 0,24, 0,
|
||||
0, 0, 0, 0, 0, 0,24, 0, 0, 0, 0, 0, 0, 0,24, 0,
|
||||
0, 0, 0, 0, 0, 0,24, 0, 0, 0, 0, 0, 0, 0,24, 0,
|
||||
0, 0, 0, 0, 0, 0,24, 0, 0, 0, 0, 0, 0, 0,24, 0,
|
||||
0, 0, 0, 0, 0, 0,24, 0, 0, 0, 0, 0, 0, 0,24, 0
|
||||
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
|
||||
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
|
||||
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
|
||||
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
|
||||
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
|
||||
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
|
||||
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
|
||||
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0
|
||||
};
|
||||
|
||||
static const byte ZSTable[256] =
|
||||
|
|
|
@ -495,6 +495,7 @@ void ResetZ80(Z80 *R, register int Cycles)
|
|||
R->ICount = R->IPeriod;
|
||||
R->IRequest = INT_NONE;
|
||||
R->IBackup = 0;
|
||||
R->wait = false;
|
||||
|
||||
JumpZ80(R->PC.W);
|
||||
}
|
||||
|
@ -507,48 +508,55 @@ void ResetZ80(Z80 *R, register int Cycles)
|
|||
#ifdef EXECZ80
|
||||
int ExecZ80(register Z80 *R, register int RunCycles) //
|
||||
{
|
||||
register byte I;
|
||||
register pair J;
|
||||
|
||||
for(R->ICount=RunCycles;;)
|
||||
if(!R->wait)
|
||||
{
|
||||
while(R->ICount>0)
|
||||
register byte I;
|
||||
register pair J;
|
||||
|
||||
for(R->ICount=RunCycles;;)
|
||||
{
|
||||
while(R->ICount>0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
/* Turn tracing on when reached trap address */
|
||||
if(R->PC.W==R->Trap) R->Trace=1;
|
||||
/* Call single-step debugger, exit if requested */
|
||||
if(R->Trace)
|
||||
if(!DebugZ80(R)) return(R->ICount);
|
||||
/* Turn tracing on when reached trap address */
|
||||
if(R->PC.W==R->Trap) R->Trace=1;
|
||||
/* Call single-step debugger, exit if requested */
|
||||
if(R->Trace)
|
||||
if(!DebugZ80(R)) return(R->ICount);
|
||||
#endif
|
||||
|
||||
/* Read opcode and count cycles */
|
||||
I=OpZ80(R->PC.W++);
|
||||
/* Count cycles */
|
||||
R->ICount-=Cycles[I];
|
||||
/* Interpret opcode */
|
||||
switch(I)
|
||||
{
|
||||
/* Read opcode and count cycles */
|
||||
I=OpZ80(R->PC.W++);
|
||||
/* Count cycles */
|
||||
R->ICount-=Cycles[I];
|
||||
/* Interpret opcode */
|
||||
switch(I)
|
||||
{
|
||||
#include "Codes.h"
|
||||
case PFX_CB: CodesCB(R);break;
|
||||
case PFX_ED: CodesED(R);break;
|
||||
case PFX_FD: CodesFD(R);break;
|
||||
case PFX_DD: CodesDD(R);break;
|
||||
case PFX_CB: CodesCB(R);break;
|
||||
case PFX_ED: CodesED(R);break;
|
||||
case PFX_FD: CodesFD(R);break;
|
||||
case PFX_DD: CodesDD(R);break;
|
||||
}
|
||||
|
||||
/* Unless we have come here after EI, exit */
|
||||
if(!(R->IFF&IFF_EI)) return(R->ICount);
|
||||
else
|
||||
{
|
||||
/* Done with AfterEI state */
|
||||
R->IFF=(R->IFF&~IFF_EI)|IFF_1;
|
||||
/* Restore the ICount */
|
||||
R->ICount+=R->IBackup-1;
|
||||
/* Interrupt CPU if needed */
|
||||
if((R->IRequest!=INT_NONE)&&(R->IRequest!=INT_QUIT)) IntZ80(R,R->IRequest);
|
||||
}
|
||||
|
||||
/* Unless we have come here after EI, exit */
|
||||
if(!(R->IFF&IFF_EI)) return(R->ICount);
|
||||
else
|
||||
{
|
||||
/* Done with AfterEI state */
|
||||
R->IFF=(R->IFF&~IFF_EI)|IFF_1;
|
||||
/* Restore the ICount */
|
||||
R->ICount+=R->IBackup-1;
|
||||
/* Interrupt CPU if needed */
|
||||
if((R->IRequest!=INT_NONE)&&(R->IRequest!=INT_QUIT)) IntZ80(R,R->IRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return RunCycles;
|
||||
}
|
||||
}
|
||||
#endif /* EXECZ80 */
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#define Z80_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
#define EXECZ80 // run a few cycles
|
||||
|
@ -101,6 +102,7 @@ typedef struct
|
|||
word Trap; /* Set Trap to address to trace from */
|
||||
byte Trace; /* Set Trace=1 to start tracing */
|
||||
void *User; /* Arbitrary user data (ID,RAM*,etc.) */
|
||||
bool wait;
|
||||
} Z80;
|
||||
|
||||
/** ResetZ80() ***********************************************/
|
||||
|
|
Plik diff jest za duży
Load Diff
Ładowanie…
Reference in New Issue