forked from KolibriOS/kolibrios
ea1a60faa3
git-svn-id: svn://kolibrios.org@9837 a494cfbc-eb01-0410-851d-a64ba20cac60
505 lines
10 KiB
C
505 lines
10 KiB
C
/********************************************************************************/
|
|
/* */
|
|
/* CZ80 (Z80 CPU emulator) version 0.91 */
|
|
/* Compiled with Dev-C++ */
|
|
/* Copyright 2004-2005 Stephane Dallongeville */
|
|
/* */
|
|
/********************************************************************************/
|
|
|
|
//#ifdef CPUZ80_CZ80_CORE
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stddef.h>
|
|
#include "cz80.h"
|
|
|
|
|
|
// include macro file
|
|
//////////////////////
|
|
|
|
#include "cz80.inc"
|
|
|
|
// shared global variable
|
|
//////////////////////////
|
|
|
|
cz80_struc CZ80;
|
|
|
|
static uint8_t SZXY[256]; // zero and sign flags
|
|
static uint8_t SZXYP[256]; // zero, sign and parity flags
|
|
static uint8_t SZXY_BIT[256]; // zero, sign and parity/overflow (=zero) flags for BIT opcode
|
|
static uint8_t SZXYHV_inc[256]; // zero, sign, half carry and overflow flags INC R8
|
|
static uint8_t SZXYHV_dec[256]; // zero, sign, half carry and overflow flags DEC R8
|
|
|
|
// prototype
|
|
/////////////
|
|
|
|
uint8_t FASTCALL Cz80_Read_Dummy(void *ctx, const uint16_t adr);
|
|
void FASTCALL Cz80_Write_Dummy(void *ctx, const uint16_t adr, uint8_t data);
|
|
|
|
uint8_t FASTCALL Cz80_Interrupt_Ack_Dummy(void *ctx, uint8_t param);
|
|
void FASTCALL Cz80_RetI_Dummy(void *ctx);
|
|
|
|
// core main functions
|
|
///////////////////////
|
|
|
|
void Cz80_Init(cz80_struc *cpu)
|
|
{
|
|
unsigned int i, j, p;
|
|
|
|
memset(cpu, 0, sizeof(cz80_struc));
|
|
|
|
// flags tables initialisation
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
SZXY[i] = i & (CZ80_SF | CZ80_YF | CZ80_XF);
|
|
if (!i) SZXY[i] |= CZ80_ZF;
|
|
|
|
SZXY_BIT[i] = i & (CZ80_SF | CZ80_YF | CZ80_XF);
|
|
if (!i) SZXY_BIT[i] |= CZ80_ZF | CZ80_PF;
|
|
|
|
for (j = 0, p = 0; j < 8; j++) if (i & (1 << j)) p++;
|
|
SZXYP[i] = SZXY[i];
|
|
if (!(p & 1)) SZXYP[i] |= CZ80_PF;
|
|
|
|
SZXYHV_inc[i] = SZXY[i];
|
|
if(i == 0x80) SZXYHV_inc[i] |= CZ80_VF;
|
|
if((i & 0x0F) == 0x00) SZXYHV_inc[i] |= CZ80_HF;
|
|
|
|
SZXYHV_dec[i] = SZXY[i] | CZ80_NF;
|
|
if (i == 0x7F) SZXYHV_dec[i] |= CZ80_VF;
|
|
if ((i & 0x0F) == 0x0F) SZXYHV_dec[i] |= CZ80_HF;
|
|
}
|
|
|
|
Cz80_Set_Fetch(cpu, 0x0000, 0xFFFF, NULL);
|
|
|
|
Cz80_Set_ReadB(cpu, Cz80_Read_Dummy);
|
|
Cz80_Set_WriteB(cpu, Cz80_Write_Dummy);
|
|
|
|
cpu->Interrupt_Ack = Cz80_Interrupt_Ack_Dummy;
|
|
cpu->RetI = Cz80_RetI_Dummy;
|
|
}
|
|
|
|
uint8_t Cz80_Reset(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
|
|
memset(CPU, 0, offsetof(cz80_struc, CycleSup));
|
|
|
|
Cz80_Set_PC(CPU, 0);
|
|
zIX = 0xFFFF;
|
|
zIY = 0xFFFF;
|
|
#if CZ80_DEBUG
|
|
zF = CZ80_ZF;
|
|
#else
|
|
zSP = 0xFFFF;
|
|
zFA = 0xFFFF;
|
|
#endif
|
|
|
|
return CPU->Status;
|
|
}
|
|
|
|
/////////////////////////////////
|
|
|
|
#include "cz80exec.inc"
|
|
|
|
/////////////////////////////////
|
|
|
|
void FASTCALL Cz80_Set_IRQ(cz80_struc *cpu, uint8_t vector)
|
|
{
|
|
cpu->IntVect = vector;
|
|
cpu->Status |= CZ80_HAS_INT;
|
|
cpu->CycleSup = cpu->CycleIO;
|
|
cpu->CycleIO = 0;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_NMI(cz80_struc *cpu)
|
|
{
|
|
cpu->Status |= CZ80_HAS_NMI;
|
|
cpu->CycleSup = cpu->CycleIO;
|
|
cpu->CycleIO = 0;
|
|
}
|
|
|
|
void FASTCALL Cz80_Clear_IRQ(cz80_struc *cpu)
|
|
{
|
|
cpu->Status &= ~CZ80_HAS_INT;
|
|
}
|
|
|
|
void FASTCALL Cz80_Clear_NMI(cz80_struc *cpu)
|
|
{
|
|
cpu->Status &= ~CZ80_HAS_NMI;
|
|
}
|
|
|
|
/////////////////////////////////
|
|
|
|
int FASTCALL Cz80_Get_CycleToDo(cz80_struc *cpu)
|
|
{
|
|
if (!(cpu->Status & CZ80_RUNNING)) return -1;
|
|
|
|
return cpu->CycleToDo;
|
|
}
|
|
|
|
int FASTCALL Cz80_Get_CycleRemaining(cz80_struc *cpu)
|
|
{
|
|
if (!(cpu->Status & CZ80_RUNNING)) return -1;
|
|
|
|
return (cpu->CycleIO + cpu->CycleSup);
|
|
}
|
|
|
|
int FASTCALL Cz80_Get_CycleDone(cz80_struc *cpu)
|
|
{
|
|
if (!(cpu->Status & CZ80_RUNNING)) return -1;
|
|
|
|
return (cpu->CycleToDo - (cpu->CycleIO + cpu->CycleSup));
|
|
}
|
|
|
|
void FASTCALL Cz80_Release_Cycle(cz80_struc *cpu)
|
|
{
|
|
if (cpu->Status & CZ80_RUNNING) cpu->CycleIO = cpu->CycleSup = 0;
|
|
}
|
|
|
|
void FASTCALL Cz80_Add_Cycle(cz80_struc *cpu, unsigned int cycle)
|
|
{
|
|
if (cpu->Status & CZ80_RUNNING) cpu->CycleIO -= cycle;
|
|
}
|
|
|
|
// Read / Write dummy functions
|
|
////////////////////////////////
|
|
|
|
uint8_t FASTCALL Cz80_Read_Dummy(void *ctx, const uint16_t adr)
|
|
{
|
|
(void)ctx;
|
|
(void)adr;
|
|
return 0;
|
|
}
|
|
|
|
void FASTCALL Cz80_Write_Dummy(void *ctx, const uint16_t adr, uint8_t data)
|
|
{
|
|
(void)ctx;
|
|
(void)adr;
|
|
(void)data;
|
|
}
|
|
|
|
uint8_t FASTCALL Cz80_Interrupt_Ack_Dummy(void *ctx, uint8_t param)
|
|
{
|
|
(void)ctx;
|
|
(void)param;
|
|
|
|
// return vector
|
|
return -1;
|
|
}
|
|
|
|
void FASTCALL Cz80_RetI_Dummy(void *ctx)
|
|
{
|
|
(void)ctx;
|
|
}
|
|
|
|
|
|
// Read / Write core functions
|
|
///////////////////////////////
|
|
|
|
void Cz80_Set_Ctx(cz80_struc *cpu, void *ctx)
|
|
{
|
|
cpu->ctx = ctx;
|
|
}
|
|
|
|
uint8_t Cz80_Read_Byte(cz80_struc *cpu, uint16_t adr)
|
|
{
|
|
return cpu->Read_Byte(cpu->ctx, adr);
|
|
}
|
|
|
|
uint16_t Cz80_Read_Word(cz80_struc *cpu, uint16_t adr)
|
|
{
|
|
#if CZ80_USE_WORD_HANDLER
|
|
return cpu->Read_Word(cpu->ctx, adr);
|
|
#elif CZ80_LITTLE_ENDIAN
|
|
return (cpu->Read_Byte(cpu->ctx, adr) |
|
|
(cpu->Read_Byte(cpu->ctx, (adr + 1)) << 8));
|
|
#else
|
|
return ((cpu->Read_Byte(cpu->ctx, adr) << 8) |
|
|
cpu->Read_Byte(cpu->ctx, (adr + 1)));
|
|
#endif
|
|
}
|
|
|
|
void Cz80_Write_Byte(cz80_struc *cpu, uint16_t adr, uint8_t data)
|
|
{
|
|
cpu->Write_Byte(cpu->ctx, adr, data);
|
|
}
|
|
|
|
void Cz80_Write_Word(cz80_struc *cpu, uint16_t adr, uint16_t data)
|
|
{
|
|
#if CZ80_USE_WORD_HANDLER
|
|
cpu->Write_Word(cpu->ctx, adr, data);
|
|
#elif CZ80_LITTLE_ENDIAN
|
|
cpu->Write_Byte(cpu->ctx, adr, (data & 0xFF));
|
|
cpu->Write_Byte(cpu->ctx, (adr + 1), (data >> 8));
|
|
#else
|
|
cpu->Write_Byte(cpu->ctx, adr, (data >> 8));
|
|
cpu->Write_Byte(cpu->ctx, (adr + 1), (data & 0xFF));
|
|
#endif
|
|
}
|
|
|
|
// setting core functions
|
|
//////////////////////////
|
|
|
|
void Cz80_Set_Fetch(cz80_struc *cpu, uint16_t low_adr, uint16_t high_adr, void *fetch_adr)
|
|
{
|
|
uint16_t i, j;
|
|
|
|
i = low_adr >> CZ80_FETCH_SFT;
|
|
j = high_adr >> CZ80_FETCH_SFT;
|
|
fetch_adr = (void *)((uintptr_t)fetch_adr - (i << CZ80_FETCH_SFT));
|
|
while (i <= j) cpu->Fetch[i++] = (uint8_t*) fetch_adr;
|
|
}
|
|
|
|
void Cz80_Set_ReadB(cz80_struc *cpu, CZ80_READ *Func)
|
|
{
|
|
cpu->Read_Byte = Func;
|
|
}
|
|
|
|
void Cz80_Set_WriteB(cz80_struc *cpu, CZ80_WRITE *Func)
|
|
{
|
|
cpu->Write_Byte = Func;
|
|
}
|
|
|
|
#if CZ80_USE_WORD_HANDLER
|
|
void Cz80_Set_ReadW(cz80_struc *cpu, CZ80_READ_WORD *Func)
|
|
{
|
|
cpu->Read_Word = Func;
|
|
}
|
|
|
|
void Cz80_Set_WriteW(cz80_struc *cpu, CZ80_WRITE_WORD *Func)
|
|
{
|
|
cpu->Write_Word = Func;
|
|
}
|
|
#endif
|
|
|
|
void Cz80_Set_INPort(cz80_struc *cpu, CZ80_READ *Func)
|
|
{
|
|
cpu->IN_Port = Func;
|
|
}
|
|
|
|
void Cz80_Set_OUTPort(cz80_struc *cpu, CZ80_WRITE *Func)
|
|
{
|
|
cpu->OUT_Port = Func;
|
|
}
|
|
|
|
void Cz80_Set_IRQ_Callback(cz80_struc *cpu, CZ80_INT_CALLBACK *Func)
|
|
{
|
|
cpu->Interrupt_Ack = Func;
|
|
}
|
|
|
|
void Cz80_Set_RETI_Callback(cz80_struc *cpu, CZ80_RETI_CALLBACK *Func)
|
|
{
|
|
cpu->RetI = Func;
|
|
}
|
|
|
|
// externals main functions
|
|
////////////////////////////
|
|
|
|
uint16_t FASTCALL Cz80_Get_BC(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return zBC;
|
|
}
|
|
|
|
uint16_t FASTCALL Cz80_Get_DE(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return zDE;
|
|
}
|
|
|
|
uint16_t FASTCALL Cz80_Get_HL(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return zHL;
|
|
}
|
|
|
|
uint16_t FASTCALL Cz80_Get_AF(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return (zF | (zA << 8));
|
|
}
|
|
|
|
uint16_t FASTCALL Cz80_Get_BC2(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return zBC2;
|
|
}
|
|
|
|
uint16_t FASTCALL Cz80_Get_DE2(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return zDE2;
|
|
}
|
|
|
|
uint16_t FASTCALL Cz80_Get_HL2(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return zHL2;
|
|
}
|
|
|
|
uint16_t FASTCALL Cz80_Get_AF2(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return (zF2 | (zA2 << 8));
|
|
}
|
|
|
|
uint16_t FASTCALL Cz80_Get_IX(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return zIX;
|
|
}
|
|
|
|
uint16_t FASTCALL Cz80_Get_IY(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return zIY;
|
|
}
|
|
|
|
uint16_t FASTCALL Cz80_Get_SP(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return zSP;
|
|
}
|
|
|
|
uint16_t FASTCALL Cz80_Get_PC(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return CPU->PC;
|
|
}
|
|
|
|
uint16_t FASTCALL Cz80_Get_R(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return zR;
|
|
}
|
|
|
|
uint16_t FASTCALL Cz80_Get_IFF(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
uint16_t value = 0;
|
|
|
|
if (zIFF1 & CZ80_IFF) value |= 1;
|
|
if (zIFF2 & CZ80_IFF) value |= 2;
|
|
return value;
|
|
}
|
|
|
|
uint8_t FASTCALL Cz80_Get_IM(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return zIM;
|
|
}
|
|
|
|
uint8_t FASTCALL Cz80_Get_I(cz80_struc *cpu)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
return zI;
|
|
}
|
|
|
|
|
|
void FASTCALL Cz80_Set_BC(cz80_struc *cpu, uint16_t value)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zBC = value;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_DE(cz80_struc *cpu, uint16_t value)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zDE = value;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_HL(cz80_struc *cpu, uint16_t value)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zHL = value;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_AF(cz80_struc *cpu, uint16_t val)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zF = val;
|
|
zA = val >> 8;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_BC2(cz80_struc *cpu, uint16_t value)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zBC2 = value;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_DE2(cz80_struc *cpu, uint16_t value)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zDE2 = value;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_HL2(cz80_struc *cpu, uint16_t value)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zHL2 = value;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_AF2(cz80_struc *cpu, uint16_t val)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zF2 = val;
|
|
zA2 = val >> 8;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_IX(cz80_struc *cpu, uint16_t value)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zIX = value;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_IY(cz80_struc *cpu, uint16_t value)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zIY = value;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_SP(cz80_struc *cpu, uint16_t value)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zSP = value;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_PC(cz80_struc *cpu, uint16_t val)
|
|
{
|
|
cpu->BasePC = (uintptr_t) cpu->Fetch[val >> CZ80_FETCH_SFT];
|
|
cpu->PC = val;
|
|
}
|
|
|
|
|
|
void FASTCALL Cz80_Set_R(cz80_struc *cpu, uint16_t value)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zR = value & 0xFF;
|
|
zR2 = value & 0x80;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_IFF(cz80_struc *cpu, uint16_t value)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zIFF = 0;
|
|
if (value & 1) zIFF1 = CZ80_IFF;
|
|
if (value & 2) zIFF2 = CZ80_IFF;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_IM(cz80_struc *cpu, uint8_t value)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zIM = value & 3;
|
|
}
|
|
|
|
void FASTCALL Cz80_Set_I(cz80_struc *cpu, uint8_t value)
|
|
{
|
|
cz80_struc *CPU = cpu;
|
|
zI = value & 0xFF;
|
|
}
|
|
|
|
//#endif // CPUZ80_CZ80_CORE
|
|
|
|
|