881 lines
28 KiB
C#
881 lines
28 KiB
C#
/*
|
|
* Copyright 2007, 2015 Alex Makeev
|
|
*
|
|
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
|
|
*
|
|
* ZXMAK2 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.
|
|
*
|
|
* ZXMAK2 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 ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Description: Z80 CPU Emulator [ED prefixed opcode part]
|
|
* Date: 13.04.2007
|
|
*
|
|
*/
|
|
|
|
|
|
using System;
|
|
namespace ZXMAK2.Engine.Cpu.Processor
|
|
{
|
|
public partial class Z80Cpu
|
|
{
|
|
private void ED_LDI(byte cmd)
|
|
{
|
|
// 16T (4, 4, 3, 5)
|
|
|
|
var val = RDMEM(regs.HL); Tact += 3;
|
|
|
|
WRMEM(regs.DE, val); Tact += 3;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
|
|
regs.HL++;
|
|
regs.DE++;
|
|
regs.BC--;
|
|
val += regs.A;
|
|
|
|
regs.F = (byte)((regs.F & CpuFlags.NotHPNF3F5) |
|
|
(val & CpuFlags.F3) | ((val << 4) & CpuFlags.F5));
|
|
if (regs.BC != 0) regs.F |= CpuFlags.P;
|
|
}
|
|
|
|
private void ED_CPI(byte cmd)
|
|
{
|
|
// 16T (4, 4, 3, 5)
|
|
|
|
var cf = regs.F & CpuFlags.C;
|
|
var val = RDMEM(regs.HL); Tact += 3;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
|
|
regs.HL++;
|
|
regs.F = (byte)(CpuTables.Cpf8b[regs.A * 0x100 + val] + cf);
|
|
if (--regs.BC != 0) regs.F |= CpuFlags.P;
|
|
regs.MW++;
|
|
}
|
|
|
|
private void ED_INI(byte cmd) // INI [16T]
|
|
{
|
|
// 16T (4, 5, 3, 4)
|
|
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
|
|
var val = RDPORT(regs.BC); Tact += 3;
|
|
|
|
WRMEM(regs.HL, val); Tact += 3;
|
|
|
|
regs.MW = (ushort)(regs.BC + 1);
|
|
regs.HL++;
|
|
regs.B--;
|
|
|
|
//FUSE
|
|
byte flgtmp = (byte)(val + regs.C + 1);
|
|
regs.F = (byte)(CpuTables.Logf[regs.B] & CpuFlags.NotP);
|
|
if ((CpuTables.Logf[(flgtmp & 0x07) ^ regs.B] & CpuFlags.P) != 0) regs.F |= CpuFlags.P;
|
|
if (flgtmp < val) regs.F |= CpuFlags.HC;
|
|
if ((val & 0x80) != 0) regs.F |= CpuFlags.N;
|
|
|
|
Tact++; //?? really?
|
|
}
|
|
|
|
private void ED_OUTI(byte cmd) // OUTI [16T]
|
|
{
|
|
// 16 (4, 5, 3, 4)
|
|
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
regs.B--;
|
|
|
|
var val = RDMEM(regs.HL); Tact += 3;
|
|
|
|
WRPORT(regs.BC, val); Tact += 3;
|
|
|
|
regs.MW = (ushort)(regs.BC + 1);
|
|
regs.HL++;
|
|
|
|
//FUSE
|
|
byte flgtmp = (byte)(val + regs.L);
|
|
regs.F = (byte)(CpuTables.Logf[regs.B] & CpuFlags.NotP);
|
|
if ((CpuTables.Logf[(flgtmp & 0x07) ^ regs.B] & CpuFlags.P) != 0) regs.F |= CpuFlags.P;
|
|
if (flgtmp < val) regs.F |= CpuFlags.HC;
|
|
if ((val & 0x80) != 0) regs.F |= CpuFlags.N;
|
|
|
|
Tact++; //?? really?
|
|
}
|
|
|
|
private void ED_LDD(byte cmd)
|
|
{
|
|
// 16T (4, 4, 3, 5)
|
|
|
|
var val = RDMEM(regs.HL); Tact += 3;
|
|
|
|
WRMEM(regs.DE, val); Tact += 3;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
|
|
regs.HL--;
|
|
regs.DE--;
|
|
regs.BC--;
|
|
val += regs.A;
|
|
|
|
regs.F = (byte)((regs.F & CpuFlags.NotHPNF3F5) |
|
|
(val & CpuFlags.F3) | ((val << 4) & CpuFlags.F5));
|
|
if (regs.BC != 0) regs.F |= CpuFlags.P;
|
|
}
|
|
|
|
private void ED_CPD(byte cmd)
|
|
{
|
|
// 16T (4, 4, 3, 5)
|
|
|
|
var cf = regs.F & CpuFlags.C;
|
|
var val = RDMEM(regs.HL); Tact += 3;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
|
|
regs.HL--;
|
|
regs.BC--;
|
|
regs.MW--;
|
|
regs.F = (byte)(CpuTables.Cpf8b[regs.A * 0x100 + val] + cf);
|
|
if (regs.BC != 0) regs.F |= CpuFlags.P;
|
|
}
|
|
|
|
private void ED_IND(byte cmd) // IND [16T]
|
|
{
|
|
// 16T (4, 5, 3, 4)
|
|
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
|
|
var val = RDPORT(regs.BC); Tact += 3;
|
|
|
|
WRMEM(regs.HL, val); Tact += 3;
|
|
|
|
regs.MW = (ushort)(regs.BC - 1);
|
|
regs.HL--;
|
|
regs.B--;
|
|
|
|
//FUSE
|
|
byte flgtmp = (byte)(val + regs.C - 1);
|
|
regs.F = (byte)(CpuTables.Logf[regs.B] & CpuFlags.NotP);
|
|
if ((CpuTables.Logf[(flgtmp & 0x07) ^ regs.B] & CpuFlags.P) != 0) regs.F |= CpuFlags.P;
|
|
if (flgtmp < val) regs.F |= CpuFlags.HC;
|
|
if ((val & 0x80) != 0) regs.F |= CpuFlags.N;
|
|
|
|
Tact++; // ?? really?
|
|
}
|
|
|
|
private void ED_OUTD(byte cmd) // OUTD [16T]
|
|
{
|
|
// 16T (4, 5, 3, 4)
|
|
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
|
|
regs.B--;
|
|
var val = RDMEM(regs.HL); Tact += 3;
|
|
|
|
WRPORT(regs.BC, val); Tact += 3;
|
|
|
|
regs.MW = (ushort)(regs.BC - 1);
|
|
regs.HL--;
|
|
|
|
//FUSE
|
|
byte flgtmp = (byte)(val + regs.L);
|
|
regs.F = (byte)(CpuTables.Logf[regs.B] & CpuFlags.NotP);
|
|
if ((CpuTables.Logf[(flgtmp & 0x07) ^ regs.B] & CpuFlags.P) != 0) regs.F |= CpuFlags.P;
|
|
if (flgtmp < val) regs.F |= CpuFlags.HC;
|
|
if ((val & 0x80) != 0) regs.F |= CpuFlags.N;
|
|
|
|
Tact++; // ?? really?
|
|
}
|
|
|
|
private void ED_LDIR(byte cmd)
|
|
{
|
|
//BC==0 => 16T (4, 4, 3, 5)
|
|
//BC!=0 => 21T (4, 4, 3, 5, 5)
|
|
|
|
var val = RDMEM(regs.HL); Tact += 3;
|
|
|
|
WRMEM(regs.DE, val); Tact += 3;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
|
|
regs.BC--;
|
|
val += regs.A;
|
|
|
|
regs.F &= CpuFlags.NotHPNF3F5;
|
|
if (regs.BC != 0)
|
|
{
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
regs.PC--;
|
|
regs.MW = regs.PC;
|
|
regs.PC--;
|
|
|
|
// YF = PCi.13; XF = PCi.11
|
|
regs.F |= (byte)(regs.PCH & CpuFlags.F3F5);
|
|
regs.F |= CpuFlags.P;
|
|
}
|
|
else
|
|
{
|
|
// YF = PCi.13; XF = PCi.11
|
|
regs.F |= (byte)((val & CpuFlags.F3) | ((val << 4) & CpuFlags.F5));
|
|
}
|
|
regs.HL++;
|
|
regs.DE++;
|
|
}
|
|
|
|
private void ED_CPIR(byte cmd)
|
|
{
|
|
//BC==0 => 16T (4, 4, 3, 5)
|
|
//BC!=0 => 21T (4, 4, 3, 5, 5)
|
|
|
|
regs.MW++;
|
|
var cf = regs.F & CpuFlags.C;
|
|
var val = RDMEM(regs.HL); Tact += 3;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
|
|
regs.BC--;
|
|
regs.F = (byte)(CpuTables.Cpf8b[regs.A * 0x100 + val] + cf);
|
|
|
|
if (regs.BC != 0)
|
|
{
|
|
regs.F |= CpuFlags.P;
|
|
if ((regs.F & CpuFlags.Z) == 0)
|
|
{
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
regs.PC--;
|
|
regs.MW = regs.PC;
|
|
regs.PC--;
|
|
|
|
// YF = PCi.13; XF = PCi.11
|
|
regs.F &= CpuFlags.NotF3F5;
|
|
regs.F |= (byte)(regs.PCH & CpuFlags.F3F5);
|
|
}
|
|
}
|
|
regs.HL++;
|
|
}
|
|
|
|
private void ED_INIR(byte cmd) // INIR [16T/21T]
|
|
{
|
|
// B==0 => 16T (4, 5, 3, 4)
|
|
// B!=0 => 21T (4, 5, 3, 4, 5)
|
|
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
|
|
var val = RDPORT(regs.BC); Tact += 3;
|
|
|
|
var nf = (byte)((val >> 6) & CpuFlags.N);
|
|
var t = val + ((regs.C + 1) & 0xff);
|
|
var hcf = t > 255 ? CpuFlags.HC : 0;
|
|
|
|
WRMEM(regs.HL++, val); Tact += 3;
|
|
regs.MW = (ushort)(regs.BC + 1);
|
|
|
|
regs.B--; Tact++;
|
|
var pf = CpuTables.Parity[(t & 7) ^ regs.B];
|
|
|
|
if (regs.B != 0)
|
|
{
|
|
WRNOMREQ(regs.HL); Tact++;
|
|
WRNOMREQ(regs.HL); Tact++;
|
|
WRNOMREQ(regs.HL); Tact++;
|
|
WRNOMREQ(regs.HL); Tact++;
|
|
WRNOMREQ(regs.HL); Tact++;
|
|
regs.PC -= 2;
|
|
|
|
regs.F = (byte)(
|
|
/* ZF = 0 */
|
|
(regs.B & CpuFlags.S) | /* SF = Bo.7 */
|
|
(regs.PCH & CpuFlags.F3F5) | /* YF = PCi.13; XF = PCi.11 */
|
|
nf); /* NF = IO.7 */
|
|
if (hcf != 0)
|
|
{
|
|
regs.F |= CpuFlags.C;
|
|
if ((val & 0x80) != 0)
|
|
{
|
|
// PF = PF ^ Parity((B - 1) & 0x7) ^ 1;
|
|
// HF = (B & 0x0F) == 0x00;
|
|
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B - 1) & 7] ^ CpuFlags.P);
|
|
if ((regs.B & 0x0f) == 0x00)
|
|
regs.F |= CpuFlags.H;
|
|
}
|
|
else
|
|
{
|
|
// PF = PF ^ Parity((B + 1) & 0x7) ^ 1;
|
|
// HF = (B & 0x0F) == 0x0F;
|
|
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B + 1) & 7] ^ CpuFlags.P);
|
|
if ((regs.B & 0x0f) == 0x0f)
|
|
regs.F |= CpuFlags.H;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// PF = PF ^ Parity(B & 0x7) ^ 1;
|
|
regs.F |= (byte)(pf ^ CpuTables.Parity[regs.B & 7] ^ CpuFlags.P);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
regs.F = (byte)(CpuFlags.Z | /* ZF = 1; SF, YF, XF = 0 */
|
|
hcf | /* HF, CF = T > 255 */
|
|
pf | /* PF = ((T & 7) ^ Bo).parity */
|
|
nf); /* NF = IO.7 */
|
|
}
|
|
}
|
|
|
|
private void ED_OTIR(byte cmd) // OTIR [16T/21T]
|
|
{
|
|
// B==0 => 16T (4, 5, 3, 4)
|
|
// B!=0 => 21T (4, 5, 3, 4, 5)
|
|
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
|
|
var val = RDMEM(regs.HL++); Tact += 3;
|
|
regs.MW = (ushort)(regs.BC + 1);
|
|
|
|
var nf = (byte)((val >> 6) & CpuFlags.N);
|
|
var t = val + regs.L;
|
|
var hcf = t > 255 ? CpuFlags.HC : 0;
|
|
|
|
regs.B--;
|
|
var pf = CpuTables.Parity[(t & 7) ^ regs.B];
|
|
|
|
WRPORT(regs.BC, val); Tact += 3;
|
|
Tact++;
|
|
|
|
if (regs.B != 0)
|
|
{
|
|
RDNOMREQ(regs.BC); Tact++;
|
|
RDNOMREQ(regs.BC); Tact++;
|
|
RDNOMREQ(regs.BC); Tact++;
|
|
RDNOMREQ(regs.BC); Tact++;
|
|
RDNOMREQ(regs.BC); Tact++;
|
|
regs.PC -= 2;
|
|
|
|
regs.F = (byte)(
|
|
/* ZF = 0 */
|
|
(regs.B & CpuFlags.S) | /* SF = Bo.7 */
|
|
(regs.PCH & CpuFlags.F3F5) |/* YF = PCi.13; XF = PCi.11 */
|
|
nf); /* NF = IO.7 */
|
|
if (hcf != 0)
|
|
{
|
|
regs.F |= CpuFlags.C;
|
|
if ((val & 0x80) != 0)
|
|
{
|
|
// PF = PF ^ Parity((B - 1) & 0x7) ^ 1;
|
|
// HF = (B & 0x0F) == 0x00;
|
|
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B - 1) & 7] ^ CpuFlags.P);
|
|
if ((regs.B & 0x0f) == 0x00)
|
|
regs.F |= CpuFlags.H;
|
|
}
|
|
else
|
|
{
|
|
// PF = PF ^ Parity((B + 1) & 0x7) ^ 1;
|
|
// HF = (B & 0x0F) == 0x0F;
|
|
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B + 1) & 7] ^ CpuFlags.P);
|
|
if ((regs.B & 0x0f) == 0x0f)
|
|
regs.F |= CpuFlags.H;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// PF = PF ^ Parity(B & 0x7) ^ 1;
|
|
regs.F |= (byte)(pf ^ CpuTables.Parity[regs.B & 7] ^ CpuFlags.P);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
regs.F = (byte)(CpuFlags.Z | /* ZF = 1; SF, YF, XF = 0 */
|
|
hcf | /* HF, CF = T > 255 */
|
|
pf | /* PF = ((T & 7) ^ Bo).parity */
|
|
nf); /* NF = IO.7 */
|
|
}
|
|
}
|
|
|
|
private void ED_LDDR(byte cmd)
|
|
{
|
|
//BC==0 => 16T (4, 4, 3, 5)
|
|
//BC!=0 => 21T (4, 4, 3, 5, 5)
|
|
|
|
var val = RDMEM(regs.HL); Tact += 3;
|
|
|
|
WRMEM(regs.DE, val); Tact += 3;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
|
|
regs.BC--;
|
|
val += regs.A;
|
|
|
|
regs.F &= CpuFlags.NotHPNF3F5;
|
|
if (regs.BC != 0)
|
|
{
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
WRNOMREQ(regs.DE); Tact++;
|
|
regs.PC--;
|
|
regs.MW = regs.PC;
|
|
regs.PC--;
|
|
|
|
// YF = PCi.13; XF = PCi.11
|
|
regs.F |= (byte)(regs.PCH & CpuFlags.F3F5);
|
|
regs.F |= CpuFlags.P;
|
|
}
|
|
else
|
|
{
|
|
// YF = PCi.13; XF = PCi.11
|
|
regs.F |= (byte)((val & CpuFlags.F3) | ((val << 4) & CpuFlags.F5));
|
|
}
|
|
regs.HL--;
|
|
regs.DE--;
|
|
}
|
|
|
|
private void ED_CPDR(byte cmd)
|
|
{
|
|
// BC==0 => 16T (4, 4, 3, 5)
|
|
// BC!=0 => 21T (4, 4, 3, 5, 5)
|
|
|
|
regs.MW--;
|
|
var cf = regs.F & CpuFlags.C;
|
|
var val = RDMEM(regs.HL); Tact += 3;
|
|
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
regs.BC--;
|
|
regs.F = (byte)(CpuTables.Cpf8b[regs.A * 0x100 + val] + cf);
|
|
|
|
if (regs.BC != 0)
|
|
{
|
|
regs.F |= CpuFlags.P;
|
|
if ((regs.F & CpuFlags.Z) == 0)
|
|
{
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
regs.PC--;
|
|
regs.MW = regs.PC;
|
|
regs.PC--;
|
|
|
|
// YF = PCi.13; XF = PCi.11
|
|
regs.F &= CpuFlags.NotF3F5;
|
|
regs.F |= (byte)(regs.PCH & CpuFlags.F3F5);
|
|
}
|
|
}
|
|
regs.HL--;
|
|
}
|
|
|
|
private void ED_INDR(byte cmd) // INDR [16T/21T]
|
|
{
|
|
// B==0 => 16 (4, 5, 3, 4)
|
|
// B!=0 => 21 (4, 5, 3, 4, 5)
|
|
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
|
|
var val = RDPORT(regs.BC); Tact += 3;
|
|
|
|
var nf = (byte)((val >> 6) & CpuFlags.N);
|
|
var t = val + ((regs.C - 1) & 0xff);
|
|
var hcf = t > 255 ? CpuFlags.HC : 0;
|
|
|
|
WRMEM(regs.HL--, val); Tact += 3;
|
|
regs.MW = (ushort)(regs.BC - 1);
|
|
|
|
regs.B--; Tact++;
|
|
var pf = CpuTables.Parity[(t & 7) ^ regs.B];
|
|
|
|
if (regs.B != 0)
|
|
{
|
|
WRNOMREQ(regs.HL); Tact++;
|
|
WRNOMREQ(regs.HL); Tact++;
|
|
WRNOMREQ(regs.HL); Tact++;
|
|
WRNOMREQ(regs.HL); Tact++;
|
|
WRNOMREQ(regs.HL); Tact++;
|
|
regs.PC -= 2;
|
|
|
|
regs.F = (byte)(
|
|
/* ZF = 0 */
|
|
(regs.B & CpuFlags.S) | /* SF = Bo.7 */
|
|
(regs.PCH & CpuFlags.F3F5) |/* YF = PCi.13; XF = PCi.11 */
|
|
nf); /* NF = IO.7 */
|
|
if (hcf != 0)
|
|
{
|
|
regs.F |= CpuFlags.C;
|
|
if ((val & 0x80) != 0)
|
|
{
|
|
// PF = PF ^ Parity((B - 1) & 0x7) ^ 1;
|
|
// HF = (B & 0x0F) == 0x00;
|
|
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B - 1) & 7] ^ CpuFlags.P);
|
|
if ((regs.B & 0x0f) == 0x00)
|
|
regs.F |= CpuFlags.H;
|
|
}
|
|
else
|
|
{
|
|
// PF = PF ^ Parity((B + 1) & 0x7) ^ 1;
|
|
// HF = (B & 0x0F) == 0x0F;
|
|
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B + 1) & 7] ^ CpuFlags.P);
|
|
if ((regs.B & 0x0f) == 0x0f)
|
|
regs.F |= CpuFlags.H;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// PF = PF ^ Parity(B & 0x7) ^ 1;
|
|
regs.F |= (byte)(pf ^ CpuTables.Parity[regs.B & 7] ^ CpuFlags.P);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
regs.F = (byte)(CpuFlags.Z | /* ZF = 1; SF, YF, XF = 0 */
|
|
hcf | /* HF, CF = T > 255 */
|
|
pf | /* PF = ((T & 7) ^ Bo).parity */
|
|
nf); /* NF = IO.7 */
|
|
}
|
|
}
|
|
|
|
private void ED_OTDR(byte cmd) //OTDR [16T/21T]
|
|
{
|
|
// B==0 => 16T (4, 5, 3, 4)
|
|
// B!=0 => 21T (4, 5, 3, 4, 5)
|
|
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
|
|
var val = RDMEM(regs.HL--); Tact += 3;
|
|
regs.MW = (ushort)(regs.BC - 1);
|
|
|
|
var nf = (byte)((val >> 6) & CpuFlags.N);
|
|
var t = val + regs.L;
|
|
var hcf = t > 255 ? CpuFlags.HC : 0;
|
|
|
|
regs.B--;
|
|
var pf = CpuTables.Parity[(t & 7) ^ regs.B];
|
|
|
|
WRPORT(regs.BC, val); Tact += 3;
|
|
Tact++;
|
|
|
|
if (regs.B != 0)
|
|
{
|
|
RDNOMREQ(regs.BC); Tact++;
|
|
RDNOMREQ(regs.BC); Tact++;
|
|
RDNOMREQ(regs.BC); Tact++;
|
|
RDNOMREQ(regs.BC); Tact++;
|
|
RDNOMREQ(regs.BC); Tact++;
|
|
regs.PC -= 2;
|
|
|
|
regs.F = (byte)(
|
|
/* ZF = 0 */
|
|
(regs.B & CpuFlags.S) | /* SF = Bo.7 */
|
|
(regs.PCH & CpuFlags.F3F5) |/* YF = PCi.13; XF = PCi.11 */
|
|
nf); /* NF = IO.7 */
|
|
if (hcf != 0)
|
|
{
|
|
regs.F |= CpuFlags.C;
|
|
if ((val & 0x80) != 0)
|
|
{
|
|
// PF = PF ^ Parity((B - 1) & 0x7) ^ 1;
|
|
// HF = (B & 0x0F) == 0x00;
|
|
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B - 1) & 7] ^ CpuFlags.P);
|
|
if ((regs.B & 0x0f) == 0x00)
|
|
regs.F |= CpuFlags.H;
|
|
}
|
|
else
|
|
{
|
|
// PF = PF ^ Parity((B + 1) & 0x7) ^ 1;
|
|
// HF = (B & 0x0F) == 0x0F;
|
|
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B + 1) & 7] ^ CpuFlags.P);
|
|
if ((regs.B & 0x0f) == 0x0f)
|
|
regs.F |= CpuFlags.H;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// PF = PF ^ Parity(B & 0x7) ^ 1;
|
|
regs.F |= (byte)(pf ^ CpuTables.Parity[regs.B & 7] ^ CpuFlags.P);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
regs.F = (byte)(CpuFlags.Z | /* ZF = 1; SF, YF, XF = 0 */
|
|
hcf | /* HF, CF = T > 255 */
|
|
pf | /* PF = ((T & 7) ^ Bo).parity */
|
|
nf); /* NF = IO.7 */
|
|
}
|
|
}
|
|
|
|
private void ED_INRC(byte cmd) // in R,(c) [12T]
|
|
{
|
|
// 12T (4, 4, 4)
|
|
var r = (cmd & 0x38) >> 3;
|
|
|
|
regs.MW = regs.BC;
|
|
var pval = RDPORT(regs.BC);
|
|
regs.MW++;
|
|
if (r != CpuRegId.F)
|
|
_regSetters[r](pval);
|
|
regs.F = (byte)(CpuTables.Logf[pval] | (regs.F & CpuFlags.C));
|
|
Tact += 4;
|
|
}
|
|
|
|
private void ED_OUTCR_NMOS(byte cmd) // out (c),R [12T]
|
|
{
|
|
// 12T (4, 4, 4)
|
|
var r = (cmd & 0x38) >> 3;
|
|
|
|
regs.MW = regs.BC;
|
|
if (r != CpuRegId.F)
|
|
WRPORT(regs.BC, _regGetters[r]());
|
|
else
|
|
WRPORT(regs.BC, 0x00); // 0 for Z80 and 0xFF for Z84
|
|
regs.MW++;
|
|
Tact += 4;
|
|
}
|
|
|
|
private void ED_OUTCR_CMOS(byte cmd) // out (c),R [12T]
|
|
{
|
|
// 12T (4, 4, 4)
|
|
var r = (cmd & 0x38) >> 3;
|
|
|
|
regs.MW = regs.BC;
|
|
if (r != CpuRegId.F)
|
|
WRPORT(regs.BC, _regGetters[r]());
|
|
else
|
|
WRPORT(regs.BC, 0xFF); // 0 for Z80 and 0xFF for Z84
|
|
regs.MW++;
|
|
Tact += 4;
|
|
}
|
|
|
|
private void ED_ADCHLRR(byte cmd) // adc hl,RR
|
|
{
|
|
var rr = (cmd & 0x30) >> 4;
|
|
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
|
|
regs.MW = (ushort)(regs.HL + 1);
|
|
byte fl = (byte)((((regs.HL & 0x0FFF) + (_pairGetters[rr]() & 0x0FFF) + (regs.F & CpuFlags.C)) >> 8) & CpuFlags.H);
|
|
uint tmp = (uint)((regs.HL & 0xFFFF) + (_pairGetters[rr]() & 0xFFFF) + (regs.F & CpuFlags.C)); // AF???
|
|
if ((tmp & 0x10000) != 0) fl |= CpuFlags.C;
|
|
if ((tmp & 0xFFFF) == 0) fl |= CpuFlags.Z;
|
|
int ri = (int)(short)regs.HL + (int)(short)_pairGetters[rr]() + (int)(regs.F & CpuFlags.C);
|
|
if (ri < -0x8000 || ri >= 0x8000) fl |= CpuFlags.P;
|
|
regs.HL = (ushort)tmp;
|
|
regs.F = (byte)(fl | (regs.H & CpuFlags.SF3F5));
|
|
}
|
|
|
|
private void ED_SBCHLRR(byte cmd) // sbc hl,RR
|
|
{
|
|
var rr = (cmd & 0x30) >> 4;
|
|
|
|
RDNOMREQ(regs.IR); Tact += 1;
|
|
RDNOMREQ(regs.IR); Tact += 1;
|
|
RDNOMREQ(regs.IR); Tact += 1;
|
|
RDNOMREQ(regs.IR); Tact += 1;
|
|
RDNOMREQ(regs.IR); Tact += 1;
|
|
RDNOMREQ(regs.IR); Tact += 1;
|
|
RDNOMREQ(regs.IR); Tact += 1;
|
|
|
|
regs.MW = (ushort)(regs.HL + 1);
|
|
byte fl = CpuFlags.N;
|
|
fl |= (byte)((((regs.HL & 0x0FFF) - (_pairGetters[rr]() & 0x0FFF) - (regs.F & CpuFlags.C)) >> 8) & CpuFlags.H);
|
|
uint tmp = (uint)((regs.HL & 0xFFFF) - (_pairGetters[rr]() & 0xFFFF) - (regs.F & CpuFlags.C)); // AF???
|
|
if ((tmp & 0x10000) != 0) fl |= CpuFlags.C;
|
|
if ((tmp & 0xFFFF) == 0) fl |= CpuFlags.Z;
|
|
int ri = (int)(short)regs.HL - (int)(short)_pairGetters[rr]() - (int)(regs.F & CpuFlags.C);
|
|
if (ri < -0x8000 || ri >= 0x8000) fl |= CpuFlags.P;
|
|
regs.HL = (ushort)tmp;
|
|
regs.F = (byte)(fl | (regs.H & CpuFlags.SF3F5));
|
|
}
|
|
|
|
private void ED_LDRR_NN_(byte cmd) // ld RR,(NN)
|
|
{
|
|
// 20T (4, 4, 3, 3, 3, 3)
|
|
var rr = (cmd & 0x30) >> 4;
|
|
|
|
var adr = (ushort)RDMEM(regs.PC);
|
|
regs.PC++;
|
|
Tact += 3;
|
|
|
|
adr += (ushort)(RDMEM(regs.PC) * 0x100);
|
|
regs.PC++;
|
|
regs.MW = (ushort)(adr + 1);
|
|
Tact += 3;
|
|
|
|
var val = (ushort)RDMEM(adr);
|
|
Tact += 3;
|
|
|
|
val += (ushort)(RDMEM(regs.MW) * 0x100);
|
|
_pairSetters[rr](val);
|
|
Tact += 3;
|
|
}
|
|
|
|
private void ED_LD_NN_RR(byte cmd) // ld (NN),RR
|
|
{
|
|
// 20 (4, 4, 3, 3, 3, 3)
|
|
var rr = (cmd & 0x30) >> 4;
|
|
|
|
var adr = (ushort)RDMEM(regs.PC);
|
|
regs.PC++;
|
|
Tact += 3;
|
|
|
|
adr += (ushort)(RDMEM(regs.PC) * 0x100);
|
|
regs.PC++;
|
|
regs.MW = (ushort)(adr + 1);
|
|
var val = _pairGetters[rr]();
|
|
Tact += 3;
|
|
|
|
WRMEM(adr, (byte)val);
|
|
Tact += 3;
|
|
|
|
WRMEM(regs.MW, (byte)(val >> 8));
|
|
Tact += 3;
|
|
}
|
|
|
|
private void ED_RETN(byte cmd) // reti/retn
|
|
{
|
|
// 14T (4, 4, 3, 3)
|
|
|
|
IFF1 = IFF2;
|
|
var adr = (ushort)RDMEM(regs.SP);
|
|
Tact += 3;
|
|
|
|
adr += (ushort)(RDMEM(++regs.SP) * 0x100);
|
|
++regs.SP;
|
|
regs.PC = adr;
|
|
regs.MW = adr;
|
|
Tact += 3;
|
|
}
|
|
|
|
private void ED_IM(byte cmd) // im X
|
|
{
|
|
var mode = (byte)((cmd & 0x18) >> 3);
|
|
if (mode < 2) mode = 1;
|
|
mode--;
|
|
|
|
IM = mode;
|
|
}
|
|
|
|
private void ED_LDXRA(byte cmd) // ld I/R,a
|
|
{
|
|
var ir = (cmd & 0x08) == 0;
|
|
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
|
|
if (ir) // I
|
|
regs.I = regs.A;
|
|
else
|
|
regs.R = regs.A;
|
|
}
|
|
|
|
private void ED_LDAXR(byte cmd) // ld a,I/R
|
|
{
|
|
var ir = (cmd & 0x08) == 0;
|
|
|
|
RDNOMREQ(regs.IR); Tact++;
|
|
|
|
if (ir) // I
|
|
regs.A = regs.I;
|
|
else
|
|
regs.A = regs.R;
|
|
|
|
regs.F = (byte)(((regs.F & CpuFlags.C) | CpuTables.Logf[regs.A]) & CpuFlags.NotP);
|
|
switch (_type)
|
|
{
|
|
case CpuType.ZILOG_NMOS:
|
|
case CpuType.NEC_NMOS:
|
|
case CpuType.ST_CMOS:
|
|
SCANSIG?.Invoke();
|
|
if (!(INT && IFF1) && IFF2)
|
|
{
|
|
regs.F |= CpuFlags.P;
|
|
}
|
|
break;
|
|
case CpuType.ZILOG_CMOS:
|
|
if (IFF2)
|
|
{
|
|
regs.F |= CpuFlags.P;
|
|
}
|
|
break;
|
|
default:
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
private void ED_RRD(byte cmd) // RRD
|
|
{
|
|
// 18T (4, 4, 3, 4, 3)
|
|
|
|
var tmp = RDMEM(regs.HL); Tact += 3;
|
|
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
|
|
regs.MW = (ushort)(regs.HL + 1);
|
|
var val = (byte)((regs.A << 4) | (tmp >> 4));
|
|
|
|
WRMEM(regs.HL, val); Tact += 3;
|
|
regs.A = (byte)((regs.A & 0xF0) | (tmp & 0x0F));
|
|
regs.F = (byte)(CpuTables.Logf[regs.A] | (regs.F & CpuFlags.C));
|
|
}
|
|
|
|
private void ED_RLD(byte cmd) // RLD
|
|
{
|
|
// 18T (4, 4, 3, 4, 3)
|
|
|
|
var tmp = RDMEM(regs.HL); Tact += 3;
|
|
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
RDNOMREQ(regs.HL); Tact++;
|
|
|
|
regs.MW = (ushort)(regs.HL + 1);
|
|
var val = (byte)((regs.A & 0x0F) | (tmp << 4));
|
|
|
|
WRMEM(regs.HL, val); Tact += 3;
|
|
regs.A = (byte)((regs.A & 0xF0) | (tmp >> 4));
|
|
regs.F = (byte)(CpuTables.Logf[regs.A] | (regs.F & CpuFlags.C));
|
|
}
|
|
|
|
private void ED_NEG(byte cmd) // NEG
|
|
{
|
|
regs.F = CpuTables.Sbcf[regs.A];
|
|
regs.A = (byte)-regs.A;
|
|
}
|
|
}
|
|
}
|