Files
VGMPLAY.WMF/Debuger/Cpu/Processor/Z80Cpu.OpcodesFx.cs
T

486 lines
13 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 [DD/FD prefixed opcode part]
* Date: 13.04.2007
*
*/
using System;
namespace ZXMAK2.Engine.Cpu.Processor
{
public partial class Z80Cpu
{
#region FXxx ops...
private void FX_LDSPHL(byte cmd) // LD SP,IX
{
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
if (FX == CpuModeIndex.Ix)
regs.SP = regs.IX;
else
regs.SP = regs.IY;
}
private void FX_EX_SP_HL(byte cmd) // EX (SP),IX
{
// 23T (4, 4, 3, 4, 3, 5)
var tmpsp = regs.SP;
regs.MW = RDMEM(tmpsp); Tact += 3;
tmpsp++;
regs.MW += (ushort)(RDMEM(tmpsp) * 0x100); Tact += 3;
RDNOMREQ(tmpsp); Tact++;
if (FX == CpuModeIndex.Ix)
{
WRMEM(tmpsp, regs.XH); Tact += 3;
tmpsp--;
WRMEM(tmpsp, regs.XL); Tact += 3;
WRNOMREQ(tmpsp); Tact++;
WRNOMREQ(tmpsp); Tact++;
regs.IX = regs.MW;
}
else
{
WRMEM(tmpsp, regs.YH); Tact += 3;
tmpsp--;
WRMEM(tmpsp, regs.YL); Tact += 3;
WRNOMREQ(tmpsp); Tact++;
WRNOMREQ(tmpsp); Tact++;
regs.IY = regs.MW;
}
}
private void FX_JP_HL_(byte cmd) // JP (IX)
{
if (FX == CpuModeIndex.Ix)
regs.PC = regs.IX;
else
regs.PC = regs.IY;
}
private void FX_PUSHIX(byte cmd) // PUSH IX
{
// 15 (4, 5, 3, 3)
RDNOMREQ(regs.IR); Tact++;
var val = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
regs.SP--;
WRMEM(regs.SP, (byte)(val >> 8)); Tact += 3;
regs.SP--;
WRMEM(regs.SP, (byte)val); Tact += 3;
}
private void FX_POPIX(byte cmd) // POP IX
{
// 14T (4, 4, 3, 3)
var val = (ushort)RDMEM(regs.SP);
regs.SP++;
Tact += 3;
val |= (ushort)(RDMEM(regs.SP) << 8);
regs.SP++;
if (FX == CpuModeIndex.Ix)
regs.IX = val;
else
regs.IY = val;
Tact += 3;
}
private void FX_ALUAXH(byte cmd) // ADD/ADC/SUB/SBC/AND/XOR/OR/CP A,XH
{
byte val;
if (FX == CpuModeIndex.Ix)
val = (byte)(regs.IX >> 8);
else
val = (byte)(regs.IY >> 8);
_alualg[(cmd & 0x38) >> 3](val);
}
private void FX_ALUAXL(byte cmd) // ADD/ADC/SUB/SBC/AND/XOR/OR/CP A,XL
{
byte val;
if (FX == CpuModeIndex.Ix)
val = (byte)regs.IX;
else
val = (byte)regs.IY;
_alualg[(cmd & 0x38) >> 3](val);
}
private void FX_ALUA_IX_(byte cmd) // ADD/ADC/SUB/SBC/AND/XOR/OR/CP A,(IX)
{
// 19T (4, 4, 3, 5, 3)
var op = (cmd & 0x38) >> 3;
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.PC++;
regs.MW = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
regs.MW = (ushort)(regs.MW + drel);
var val = RDMEM(regs.MW); Tact += 3;
_alualg[op](val);
}
private void FX_ADDIXRR(byte cmd) // ADD IX,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++;
var rde = rr switch
{
0 => regs.BC,
1 => regs.DE,
2 => FX == CpuModeIndex.Ix ? regs.IX : regs.IY,
3 => regs.SP,
_ => throw new ArgumentOutOfRangeException(nameof(cmd), "(cmd & 0x30) >> 4 is out of range"),
};
if (FX == CpuModeIndex.Ix)
{
regs.MW = (ushort)(regs.IX + 1);
regs.IX = ALU_ADDHLRR(regs.IX, rde);
}
else
{
regs.MW = (ushort)(regs.IY + 1);
regs.IY = ALU_ADDHLRR(regs.IY, rde);
}
}
private void FX_DECIX(byte cmd) // DEC IX
{
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
if (FX == CpuModeIndex.Ix)
regs.IX--;
else
regs.IY--;
}
private void FX_INCIX(byte cmd) // INC IX
{
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
if (FX == CpuModeIndex.Ix)
regs.IX++;
else
regs.IY++;
}
private void FX_LDIX_N_(byte cmd) // LD IX,(nnnn)
{
// 20 (4, 4, 3, 3, 3, 3)
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);
if (FX == CpuModeIndex.Ix)
regs.IX = val;
else
regs.IY = val;
Tact += 3;
}
private void FX_LD_NN_IX(byte cmd) // LD (nnnn),IX
{
// 20 (4, 4, 3, 3, 3, 3)
var hl = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
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;
WRMEM(adr, (byte)hl);
Tact += 3;
WRMEM(regs.MW, (byte)(hl >> 8));
Tact += 3;
}
private void FX_LDIXNNNN(byte cmd) // LD IX,nnnn
{
// 14 (4, 4, 3, 3)
var val = (ushort)RDMEM(regs.PC);
regs.PC++;
Tact += 3;
val |= (ushort)(RDMEM(regs.PC) << 8);
regs.PC++;
if (FX == CpuModeIndex.Ix)
regs.IX = val;
else
regs.IY = val;
Tact += 3;
}
private void FX_DEC_IX_(byte cmd) // DEC (IX)
{
// 23T (4, 4, 3, 5, 4, 3)
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.PC++;
regs.MW = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
regs.MW = (ushort)(regs.MW + drel);
var val = RDMEM(regs.MW); Tact += 3;
RDNOMREQ(regs.MW); Tact++;
val = ALU_DECR(val);
WRMEM(regs.MW, val); Tact += 3;
}
private void FX_INC_IX_(byte cmd) // INC (IX)
{
//23T (4, 4, 3, 5, 4, 3)
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.PC++;
regs.MW = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
regs.MW = (ushort)(regs.MW + drel);
var val = RDMEM(regs.MW); Tact += 3;
RDNOMREQ(regs.MW); Tact++;
val = ALU_INCR(val);
WRMEM(regs.MW, val); Tact += 3;
}
private void FX_LD_IX_NN(byte cmd) // LD (IX),nn
{
// 19 (4, 4, 3, 5, 3)
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
regs.PC++;
var val = RDMEM(regs.PC); Tact += 3;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.PC++;
regs.MW = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
regs.MW = (ushort)(regs.MW + drel);
WRMEM(regs.MW, val); Tact += 3;
}
private void FX_LD_IX_R(byte cmd) // LD (IX),R
{
// 19T (4, 4, 3, 5, 3)
var r = cmd & 0x07;
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.PC++;
regs.MW = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
regs.MW = (ushort)(regs.MW + drel);
WRMEM(regs.MW, _regGetters[r]()); Tact += 3;
}
private void FX_LDR_IX_(byte cmd) // LD R,(IX)
{
// 19T (4, 4, 3, 5, 3)
var r = (cmd & 0x38) >> 3;
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.PC++;
regs.MW = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
regs.MW = (ushort)(regs.MW + drel);
_regSetters[r](RDMEM(regs.MW)); Tact += 3;
}
#endregion
#region RdRs...
private void FX_LDHL(byte cmd)
{
if (FX == CpuModeIndex.Ix)
regs.XH = regs.XL;
else
regs.YH = regs.YL;
}
private void FX_LDLH(byte cmd)
{
if (FX == CpuModeIndex.Ix)
regs.XL = regs.XH;
else
regs.YL = regs.YH;
}
private void FX_LDRL(byte cmd)
{
var r = (cmd & 0x38) >> 3;
if (FX == CpuModeIndex.Ix)
_regSetters[r](regs.XL);
else
_regSetters[r](regs.YL);
}
private void FX_LDRH(byte cmd)
{
var r = (cmd & 0x38) >> 3;
if (FX == CpuModeIndex.Ix)
_regSetters[r](regs.XH);
else
_regSetters[r](regs.YH);
}
private void FX_LDLR(byte cmd)
{
var r = cmd & 0x07;
if (FX == CpuModeIndex.Ix)
regs.XL = _regGetters[r]();
else
regs.YL = _regGetters[r]();
}
private void FX_LDHR(byte cmd)
{
var r = cmd & 0x07;
if (FX == CpuModeIndex.Ix)
regs.XH = _regGetters[r]();
else
regs.YH = _regGetters[r]();
}
private void FX_LDLNN(byte cmd) // LD XL,nn
{
// 11T (4, 4, 3)
if (FX == CpuModeIndex.Ix)
regs.XL = RDMEM(regs.PC);
else
regs.YL = RDMEM(regs.PC);
regs.PC++;
Tact += 3;
}
private void FX_LDHNN(byte cmd) // LD XH,nn
{
// 11T (4, 4, 3)
if (FX == CpuModeIndex.Ix)
regs.XH = RDMEM(regs.PC);
else
regs.YH = RDMEM(regs.PC);
regs.PC++;
Tact += 3;
}
private void FX_INCL(byte cmd) // INC XL
{
if (FX == CpuModeIndex.Ix)
regs.XL = ALU_INCR(regs.XL);
else
regs.YL = ALU_INCR(regs.YL);
}
private void FX_INCH(byte cmd) // INC XH
{
if (FX == CpuModeIndex.Ix)
regs.XH = ALU_INCR(regs.XH);
else
regs.YH = ALU_INCR(regs.YH);
}
private void FX_DECL(byte cmd) // DEC XL
{
if (FX == CpuModeIndex.Ix)
regs.XL = ALU_DECR(regs.XL);
else
regs.YL = ALU_DECR(regs.YL);
}
private void FX_DECH(byte cmd) // DEC XH
{
if (FX == CpuModeIndex.Ix)
regs.XH = ALU_DECR(regs.XH);
else
regs.YH = ALU_DECR(regs.YH);
}
#endregion
}
}