fbzx-wii/src/z80free/Z80free.c

784 lines
18 KiB
C
Raw Normal View History

2012-04-07 12:33:47 +02:00
/*
* Copyright 2008-2009 (C) Raster Software Vigo (Sergio Costas)
* This file is part of Z80Free, with some bits extracted
* and fixed from libZ80 (from Gabriel Gambetta)
*
* Z80Free is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Z80Free is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "Z80free.h"
void Z80free_reset(Z80FREE *processor) {
processor->PC=0;
processor->IFF1=0;
processor->IFF2=0;
processor->Rm.wr.AF=0xFFFF;
processor->Rm.wr.BC=0xFFFF;
processor->Rm.wr.DE=0xFFFF;
processor->Rm.wr.HL=0xFFFF;
processor->Rm.wr.IX=0xFFFF;
processor->Rm.wr.IY=0xFFFF;
processor->Ra.wr.AF=0xFFFF;
processor->Ra.wr.BC=0xFFFF;
processor->Ra.wr.DE=0xFFFF;
processor->Ra.wr.HL=0xFFFF;
processor->HALT=0;
processor->IM=0;
processor->I=0;
processor->Status=0;
processor->IAddr_done=0;
processor->INT_P=0;
processor->NMI_P=0;
}
void Z80free_INT(Z80FREE *processor,byte value) {
processor->INT_P=1;
processor->empty_bus=value;
}
int Z80free_step(Z80FREE *processor) {
int retval=0;
do {
retval+=Z80free_ustep(processor);
} while(processor->Status!=Z80XX);
return (retval);
}
int Z80free_ustep(Z80FREE *processor) {
static byte opcode,d1;
int retval=0;
processor->R++;
if (processor->Status==Z80XX) {
if (processor->NMI_P) { // NMI triggered
if (processor->HALT) {
processor->HALT=0;
processor->PC++;
}
processor->NMI_P=0;
Z80free_doPush(processor,processor->PC);
processor->PC=0x0066;
processor->IFF1=0; // disable INTs
processor->Status=Z80INT;
return(11); // we use 11 tstates for attending a NMI
}
if (processor->INT_P) {
processor->INT_P=0;
if (processor->IFF1==1) { // allow INTs only in this case
if (processor->HALT) {
processor->HALT=0;
processor->PC++;
}
processor->Status=Z80INT;
processor->IFF1=0;
processor->IFF2=0;
Z80free_doPush(processor,processor->PC);
if (processor->IM!=2) { // we will forget IM0 mode for now; maybe in the future...
processor->PC=0x0038;
return (13);
} else {
processor->PC=Z80free_read16(((((word)processor->I)<<8)&0xFF00) | ((word)processor->empty_bus));
return (19);
}
}
}
}
if (processor->IFF1>1) // set the right status for interrupts
processor->IFF1--;
opcode=Z80free_Rd(processor->PC);
processor->PC++;
switch(processor->Status) {
case Z80INT:
processor->Status=Z80XX;
case Z80XX:
if (opcode==0xCB) {
processor->Status=Z80CB;
return 4;
} else if (opcode==0xED) {
processor->Status=Z80ED;
return 4;
} else if (opcode==0xDD) {
processor->Status=Z80DD;
return 4;
} else if (opcode==0xFD) {
processor->Status=Z80FD;
return 4;
} else {
return(Z80free_codes(processor,opcode));
}
break;
case Z80CB:
processor->Status=Z80XX;
return(Z80free_codesCB(processor,opcode));
break;
case Z80ED:
processor->Status=Z80XX;
return(Z80free_codesED(processor,opcode));
break;
case Z80DD:
if (opcode==0xDD) {
return 4;
}
if (opcode==0xFD) {
processor->Status=Z80FD;
return 4;
}
processor->Status=Z80XX;
if (opcode==0xCB) {
d1=Z80free_Rd(processor->PC++);
retval+=Z80free_codesDDCB(processor,d1);
} else {
retval+=Z80free_codesDD(processor,opcode);
}
processor->IAddr_done=0;
return (retval);
break;
case Z80FD:
if (opcode==0xDD) {
processor->Status=Z80DD;
return 4;
}
if (opcode==0xFD) {
return 4;
}
processor->Status=Z80XX;
if (opcode==0xCB) {
d1=Z80free_Rd(processor->PC++);
retval+=Z80free_codesFDCB(processor,d1);
} else {
retval+=Z80free_codesFD(processor,opcode);
}
processor->IAddr_done=0;
return (retval);
break;
}
return 0;
}
/* ---------------------------------------------------------
* Flag operations
* ---------------------------------------------------------
*/
/** Sets a flag */
inline void Z80free_setFlag(Z80FREE *processor, byte flag) {
processor->Rm.br.F |= flag;
}
/** Resets a flag */
inline void Z80free_resFlag(Z80FREE *processor, byte flag) {
processor->Rm.br.F &= ~flag;
}
/** Puts a value in a flag */
inline void Z80free_valFlag(Z80FREE *processor, byte flag, int val) {
if (val)
processor->Rm.br.F |= flag;
else
processor->Rm.br.F &= ~flag;
}
/** Returns a flag */
inline int Z80free_getFlag(Z80FREE *processor, byte flag) {
return (processor->Rm.br.F & flag) != 0;
}
/* ---------------------------------------------------------
* Flag adjustments
* ---------------------------------------------------------
*/
static int Z80free_parityBit[256] = {
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 };
inline void Z80free_adjustFlags (Z80FREE *processor, byte val) {
Z80free_valFlag(processor,F_5, (val & F_5) != 0);
Z80free_valFlag(processor,F_3, (val & F_3) != 0);
}
inline void Z80free_adjustFlagSZP (Z80FREE *processor, byte val) {
Z80free_valFlag(processor,F_S, (val & 0x80) != 0);
Z80free_valFlag(processor,F_Z, (val == 0));
Z80free_valFlag(processor,F_PV, Z80free_parityBit[val]);
}
// Adjust flags after AND, OR, XOR
inline void Z80free_adjustLogicFlag (Z80FREE *processor, int flagH) {
Z80free_valFlag(processor,F_S, (processor->Rm.br.A & 0x80) != 0);
Z80free_valFlag(processor,F_Z, (processor->Rm.br.A == 0));
Z80free_valFlag(processor,F_H, flagH);
Z80free_valFlag(processor,F_N, 0);
Z80free_valFlag(processor,F_C, 0);
Z80free_valFlag(processor,F_PV, Z80free_parityBit[processor->Rm.br.A]);
Z80free_adjustFlags(processor, processor->Rm.br.A);
}
/* ---------------------------------------------------------
* Generic operations
* ---------------------------------------------------------
*/
byte Z80free_readR(Z80FREE *processor) {
Z80free_adjustFlagSZP(processor,(0x7F&processor->R)|(0x80&processor->R2));
Z80free_valFlag(processor,F_PV,processor->IFF2);
Z80free_valFlag(processor,F_N, 0);
Z80free_valFlag(processor,F_H, 0);
Z80free_adjustFlags(processor,(0x7F&processor->R)|(0x80&processor->R2));
return ((0x7F&processor->R)|(0x80&processor->R2));
}
void Z80free_setR(Z80FREE *processor,byte value) {
processor->R=value;
processor->R2=value;
}
byte Z80free_readI(Z80FREE *processor) {
Z80free_adjustFlagSZP(processor,processor->I);
Z80free_valFlag(processor,F_PV,processor->IFF2);
Z80free_valFlag(processor,F_N, 0);
Z80free_valFlag(processor,F_H, 0);
Z80free_adjustFlags(processor,processor->I);
return (processor->I);
}
/** Do an arithmetic operation (ADD, SUB, ADC, SBC y CP) */
byte Z80free_doArithmetic (Z80FREE *processor, byte value1,byte value2, int withCarry, int isSub) {
static word res; /* To detect carry */
static byte carry;
if (withCarry && Z80free_getFlag(processor,F_C))
carry=1;
else
carry=0;
if (isSub) {
Z80free_setFlag(processor,F_N);
res = ((word)value1) - ((word)value2) - ((word)carry);
Z80free_valFlag(processor,F_H, ((value1 ^ value2 ^ res) & 0x10) != 0);
Z80free_valFlag(processor,F_PV, (((value1 ^ value2)&0x080) && (((res^value1)&0x080))));
} else {
Z80free_resFlag(processor,F_N);
res = ((word)value1) + ((word)value2) + ((word)carry);
Z80free_valFlag(processor,F_H, (((value1 & 0x0F) + (value2 & 0x0F)+carry) & 0x10) != 0);
Z80free_valFlag(processor,F_PV, ((((value1 ^ value2)&0x080)==0) && ((res^value1)&0x080)));
}
Z80free_valFlag(processor,F_S, ((res & 0x080) != 0));
Z80free_valFlag(processor,F_C, ((res & 0x0100) != 0));
Z80free_valFlag(processor,F_Z, ((res&0xFF) == 0));
Z80free_adjustFlags(processor, res&0xFF);
return (byte)(res & 0xFF);
}
word Z80free_doArithmetic16 (Z80FREE *processor, word value1,word value2, int withCarry, int isSub) {
static word tmp;
static byte Ftmp;
Ftmp=processor->Rm.br.F; // store the F register to restore the unchanged bits when doing operations without carry
tmp=(word)Z80free_doArithmetic(processor,(byte)(value1&0x00FF),(byte)(value2&0x00FF),withCarry,isSub);
tmp|=((word)Z80free_doArithmetic(processor,(byte)((value1>>8)&0x00FF),(byte)((value2>>8)&0x00FF),1,isSub))<<8;
if (tmp) {
Z80free_resFlag(processor,F_Z);
} else {
Z80free_setFlag(processor,F_Z);
}
if (tmp&0x08000) {
Z80free_setFlag(processor,F_S);
} else {
Z80free_resFlag(processor,F_S);
}
if (!(withCarry|isSub)) {
processor->Rm.br.F &= 0x3B; // preserve the new values of C, N, 3, H and 5
processor->Rm.br.F |= (Ftmp & 0xC4); // set the old values of P/V, Z and S
}
return (tmp);
}
void Z80free_doAND (Z80FREE *processor, byte value) {
processor->Rm.br.A &= value;
Z80free_adjustLogicFlag(processor, 1);
}
void Z80free_doOR (Z80FREE *processor, byte value) {
processor->Rm.br.A |= value;
Z80free_adjustLogicFlag(processor, 0);
}
void Z80free_doXOR (Z80FREE *processor, byte value) {
processor->Rm.br.A ^= value;
Z80free_adjustLogicFlag(processor, 0);
}
void Z80free_doBIT (Z80FREE *processor, int b, byte val) {
if (val & (1 << b))
Z80free_resFlag(processor,F_Z | F_PV);
else
Z80free_setFlag(processor,F_Z | F_PV);
Z80free_setFlag(processor,F_H);
Z80free_resFlag(processor,F_N);
if ((b == 7) && !Z80free_getFlag(processor,F_Z))
Z80free_setFlag(processor,F_S);
else
Z80free_resFlag(processor,F_S);
/*Z80free_resFlag(processor,F_5);
if ((b == 5) && !Z80free_getFlag(processor,F_Z))
Z80free_setFlag(processor,F_5);
Z80free_resFlag(processor,F_3);
if ((b == 3) && !Z80free_getFlag(processor,F_Z))
Z80free_setFlag(processor,F_3);*/
Z80free_adjustFlags(processor,val);
}
byte Z80free_doSetRes (Z80FREE *processor, int bit, int pos, byte val) {
if (bit)
val |= (1 << pos);
else
val &= ~(1 << pos);
return val;
}
byte Z80free_doIncDec (Z80FREE *processor, byte val, int isDec) {
if (isDec) {
Z80free_valFlag(processor,F_PV, (val & 0x80) && !((val - 1) & 0x80));
val--;
Z80free_valFlag(processor,F_H, (val & 0x0F)==0x0F);
} else {
Z80free_valFlag(processor,F_PV, !(val & 0x80) && ((val + 1) & 0x80));
val++;
Z80free_valFlag(processor,F_H, (val & 0x0F)==0);
}
Z80free_valFlag(processor,F_S, ((val & 0x80) != 0));
Z80free_valFlag(processor,F_Z, (val == 0));
Z80free_valFlag(processor,F_N, isDec);
Z80free_adjustFlags(processor, val);
return val;
}
word Z80free_doIncDec16 (Z80FREE *processor, word val, int isDec) {
if (isDec) {
val--;
} else {
val++;
}
return val;
}
byte Z80free_doRLC (Z80FREE *processor, int adjFlags, byte val) {
Z80free_valFlag(processor,F_C, (val & 0x80) != 0);
val <<= 1;
val |= (byte)Z80free_getFlag(processor,F_C);
Z80free_adjustFlags(processor, val);
Z80free_resFlag(processor,F_H | F_N);
if (adjFlags)
Z80free_adjustFlagSZP(processor, val);
return val;
}
byte Z80free_doRL (Z80FREE *processor, int adjFlags, byte val) {
int CY = Z80free_getFlag(processor,F_C);
Z80free_valFlag(processor,F_C, (val & 0x80) != 0);
val <<= 1;
val |= (byte)CY;
Z80free_adjustFlags(processor, val);
Z80free_resFlag(processor,F_H | F_N);
if (adjFlags)
Z80free_adjustFlagSZP(processor, val);
return val;
}
byte Z80free_doRRC (Z80FREE *processor, int adjFlags, byte val) {
Z80free_valFlag(processor,F_C, (val & 0x01) != 0);
val >>= 1;
val |= ((byte)Z80free_getFlag(processor,F_C) << 7);
Z80free_adjustFlags(processor, val);
Z80free_resFlag(processor,F_H | F_N);
if (adjFlags)
Z80free_adjustFlagSZP(processor, val);
return val;
}
byte Z80free_doRR (Z80FREE *processor, int adjFlags, byte val) {
int CY = Z80free_getFlag(processor,F_C);
Z80free_valFlag(processor,F_C, (val & 0x01));
val >>= 1;
val |= (CY << 7);
Z80free_adjustFlags(processor, val);
Z80free_resFlag(processor,F_H | F_N);
if (adjFlags)
Z80free_adjustFlagSZP(processor, val);
return val;
}
byte Z80free_doSL (Z80FREE *processor, int isArith, byte val) {
Z80free_valFlag(processor,F_C, (val & 0x80) != 0);
val <<= 1;
if (isArith)
val |= 1;
Z80free_adjustFlags(processor, val);
Z80free_resFlag(processor,F_H | F_N);
Z80free_adjustFlagSZP(processor, val);
return val;
}
byte Z80free_doSR (Z80FREE *processor, int isArith, byte val) {
static int b;
b = (val & 0x80);
Z80free_valFlag(processor,F_C, (val & 0x01) != 0);
val >>= 1;
if (isArith)
val |= (byte)b;
Z80free_adjustFlags(processor, val);
Z80free_resFlag(processor,F_H | F_N);
Z80free_adjustFlagSZP(processor, val);
return val;
}
void Z80free_doRLD(Z80FREE *processor) {
static byte tmp,tmp2;
tmp=processor->Rm.br.A;
tmp2=Z80free_Rd(processor->Rm.wr.HL);
processor->Rm.br.A&=0xF0;
processor->Rm.br.A|=(0x0F&(tmp2>>4));
Z80free_Wr(processor->Rm.wr.HL,((tmp2<<4)&0xF0)|(tmp&0x0F));
Z80free_resFlag(processor,F_H | F_N);
Z80free_adjustFlagSZP(processor, processor->Rm.br.A);
}
void Z80free_doRRD(Z80FREE *processor) {
static byte tmp,tmp2;
tmp=processor->Rm.br.A;
tmp2=Z80free_Rd(processor->Rm.wr.HL);
processor->Rm.br.A&=0xF0;
processor->Rm.br.A|=(0x0F&tmp2);
Z80free_Wr(processor->Rm.wr.HL,((tmp2>>4)&0x0F)|((tmp<<4)&0xF0));
Z80free_resFlag(processor,F_H | F_N);
Z80free_adjustFlagSZP(processor, processor->Rm.br.A);
}
void Z80free_doPush (Z80FREE *processor, word val) {
processor->Rm.wr.SP-=2;
Z80free_write16(processor->Rm.wr.SP, val);
}
word Z80free_doPop (Z80FREE *processor) {
static word val;
val = Z80free_read16(processor->Rm.wr.SP);
processor->Rm.wr.SP+=2;
return val;
}
/* The DAA opcode
* According to the value in A and the flags set, add a value to A
*
* Flags set Byte (0..9)(0..9)
* --------------------------------------------
* (None) + &00
* Carry:+ &60
* Subtract:+ &00
* Subtract+Carry:+ &A0
* Half-carry:+ &06
* Half-carry+Carry:+ &66
* Half-carry+Subtract:+ &FA
* Half-carry+Subtract+Carry:+ &9A
*
* Flags set Byte (0..9)(A..F)
* --------------------------------------------
* (None) + &06
* Carry:+ &66
* Subtract:+ &00
* Subtract+Carry:+ &a0
* Half-carry:+ &06
* Half-carry+Carry:+ &66
* Half-carry+Subtract:+ &fa
* Half-carry+Subtract+Carry:+ &9A
*
* Flags set Byte (A..F)(0..9)
* --------------------------------------------
* (None) + &60
* Carry:+ &60
* Subtract:+ &00
* Subtract+Carry:+ &A0
* Half-carry:+ &66
* Half-carry+Carry:+ &66
* Half-carry+Subtract:+ &fa
* Half-carry+Subtract+Carry:+ &9A
*
* Flags set Byte (A..F)(A..F)
* --------------------------------------------
* (None) + &66
* Carry:+ &66
* Subtract:+ &00
* Subtract+Carry:+ &a0
* Half-carry:+ &66
* Half-carry+Carry:+ &66
* Half-carry+Subtract:+ &fa
* Half-carry+Subtract+Carry:+ &9A
*/
static int Z80free_DAA_BYTETYPE1[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 };
static int Z80free_DAA_BYTETYPE2[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2 };
static byte Z80free_DAA_ADJUSTMENT[4][6] = {
{0x00,0x06,0x00,0x66,0x60,0x66},
{0x06,0x06,0x06,0x66,0x66,0x66},
{0x60,0x66,0x60,0x66,0x60,0x66},
{0x66,0x66,0x66,0x66,0x66,0x66} };
void Z80free_doDAA (Z80FREE *processor) {
byte oldval;
int byteType;
int flagMask = 0;
/* (0..8)(0..9) = 0 */
/* (0..8)(A..F) = 1 */
/* (9) (0..9) = 2 */
/* (9) (A..F) = 3 */
/* (A..F)(0..9) = 4 */
/* (A..F)(A..F) = 5 */
byteType = Z80free_DAA_BYTETYPE1[(processor->Rm.br.A&0x0F)] | ((Z80free_DAA_BYTETYPE2[(processor->Rm.br.A >> 4)&0x0F]) << 1);
oldval=(processor->Rm.br.A&0x0F);
if (Z80free_getFlag(processor,F_C))
flagMask |= 2;
if (Z80free_getFlag(processor,F_H))
flagMask |= 1;
if (processor->Rm.br.F&F_N) {
processor->Rm.br.A -= Z80free_DAA_ADJUSTMENT[flagMask][byteType];
} else {
processor->Rm.br.A += Z80free_DAA_ADJUSTMENT[flagMask][byteType];
}
if ((byteType<3)&&((processor->Rm.br.F&F_C)==0)) {
Z80free_resFlag(processor,F_C);
} else {
Z80free_setFlag(processor,F_C);
}
if ((processor->Rm.br.F&F_N)==0) {
if (oldval>9) {
Z80free_setFlag(processor,F_H);
} else {
Z80free_resFlag(processor,F_H);
}
} else {
if (processor->Rm.br.F&F_H) {
if (oldval>5) {
Z80free_resFlag(processor,F_H);
} else {
Z80free_setFlag(processor,F_H);
}
}
}
processor->Rm.br.F&=0x57;
processor->Rm.br.F|=(processor->Rm.br.A&0xA4);
if (processor->Rm.br.A) {
Z80free_resFlag(processor,F_Z);
} else {
Z80free_setFlag(processor,F_Z);
}
Z80free_valFlag(processor,F_PV, Z80free_parityBit[processor->Rm.br.A]);
}
void Z80free_jump_relative(Z80FREE *processor,byte relvar) {
static word rel2;
rel2=(word)relvar;
if (relvar&0x080) {
rel2|=0xFF00;
}
processor->PC+=rel2;
}
word Z80free_addr_relative(Z80FREE *processor,word address) {
static word rel2;
if (processor->IAddr_done) {
return (processor->IAddr);
}
processor->IAddr_done=1;
rel2=(word)Z80free_read_param_8(processor);
if (rel2&0x080) {
rel2|=0xFF00;
}
processor->IAddr=address+rel2;
return (address+rel2);
}
word Z80free_addr_relativeXDCB(Z80FREE *processor,word address,byte d1) {
static word rel2;
rel2=(word)d1;
if (rel2&0x080) {
rel2|=0xFF00;
}
processor->IAddr=address+rel2;
return (address+rel2);
}
void Z80free_write16 (register word addr,register word val) {
Z80free_Wr(addr, (byte)(val & 0xFF));
val >>= 8;
addr++;
Z80free_Wr(addr, (byte)(val & 0xFF));
}
word Z80free_read16 (register word addr) {
static word v1;
v1=((word)Z80free_Rd(addr))&0x00FF;
addr++;
return (v1 + ((((word)Z80free_Rd(addr)) << 8)&0xFF00));
}
byte Z80free_read_param_8(Z80FREE *processor) {
return(Z80free_Rd(processor->PC++));
}
word Z80free_read_param_16(Z80FREE *processor) {
static word value;
value=Z80free_read16(processor->PC);
processor->PC+=2;
return (value);
}