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
|
|
|
|
* ---------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
Fixed Flag emulation for some opcodes:
RRD, RLD, DAA, CCF (bit 3,5)
BIT n, (IX/IY + d) (bit 3,5)
IN BC, r (bit 3,5)
INI, OUTI, IND, OUTD (all flag bits)
CPIR, CPDR (bit 3,5)
INIR, OTIR, INDR, OTDR (all flag bits)
2012-06-09 08:37:22 +02:00
|
|
|
int Z80free_parityBit[256] = {
|
2012-04-07 12:33:47 +02:00
|
|
|
|
|
|
|
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);
|
Fixed Flag emulation for some opcodes:
RRD, RLD, DAA, CCF (bit 3,5)
BIT n, (IX/IY + d) (bit 3,5)
IN BC, r (bit 3,5)
INI, OUTI, IND, OUTD (all flag bits)
CPIR, CPDR (bit 3,5)
INIR, OTIR, INDR, OTDR (all flag bits)
2012-06-09 08:37:22 +02:00
|
|
|
Z80free_adjustFlags(processor, processor->Rm.br.A);
|
2012-04-07 12:33:47 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
Fixed Flag emulation for some opcodes:
RRD, RLD, DAA, CCF (bit 3,5)
BIT n, (IX/IY + d) (bit 3,5)
IN BC, r (bit 3,5)
INI, OUTI, IND, OUTD (all flag bits)
CPIR, CPDR (bit 3,5)
INIR, OTIR, INDR, OTDR (all flag bits)
2012-06-09 08:37:22 +02:00
|
|
|
Z80free_adjustFlags(processor, processor->Rm.br.A);
|
2012-04-07 12:33:47 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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]);
|
Fixed Flag emulation for some opcodes:
RRD, RLD, DAA, CCF (bit 3,5)
BIT n, (IX/IY + d) (bit 3,5)
IN BC, r (bit 3,5)
INI, OUTI, IND, OUTD (all flag bits)
CPIR, CPDR (bit 3,5)
INIR, OTIR, INDR, OTDR (all flag bits)
2012-06-09 08:37:22 +02:00
|
|
|
Z80free_adjustFlags(processor, processor->Rm.br.A);
|
2012-04-07 12:33:47 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|