CPCHawk: Datacorder & tape sound, GateArray renderer modes 0, 1 & 2

This commit is contained in:
Asnivor 2018-07-18 12:28:39 +01:00
parent c0fcac5ab1
commit f35bb99c5f
11 changed files with 247 additions and 350 deletions

View File

@ -91,11 +91,16 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
[DefaultValue(true)] [DefaultValue(true)]
public bool DeterministicEmulation { get; set; } public bool DeterministicEmulation { get; set; }
[DisplayName("CPC model")] [DisplayName("CPC Model")]
[Description("The model of Amstrad CPC machine to be emulated")] [Description("The model of Amstrad CPC machine to be emulated")]
[DefaultValue(MachineType.CPC464)] [DefaultValue(MachineType.CPC464)]
public MachineType MachineType { get; set; } public MachineType MachineType { get; set; }
[DisplayName("Auto Start/Stop Tape")]
[Description("If true, CPCHawk will automatically start and stop the tape when the tape motor is triggered")]
[DefaultValue(true)]
public bool AutoStartStopTape { get; set; }
public AmstradCPCSyncSettings Clone() public AmstradCPCSyncSettings Clone()
{ {
return (AmstradCPCSyncSettings)MemberwiseClone(); return (AmstradCPCSyncSettings)MemberwiseClone();

View File

@ -167,6 +167,34 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Emulator); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Emulator);
} }
/// <summary>
/// Tape message that is fired when tape is playing
/// </summary>
public void OSD_TapeMotorActive()
{
if (_tapeInfo.Count == 0)
return;
StringBuilder sb = new StringBuilder();
sb.Append("MOTOR ON (" + _machine.TapeMediaIndex + ": " + _tapeInfo[_machine.TapeMediaIndex].Name + ")");
SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape);
}
/// <summary>
/// Tape message that is fired when tape is playing
/// </summary>
public void OSD_TapeMotorInactive()
{
if (_tapeInfo.Count == 0)
return;
StringBuilder sb = new StringBuilder();
sb.Append("MOTOR OFF (" + _machine.TapeMediaIndex + ": " + _tapeInfo[_machine.TapeMediaIndex].Name + ")");
SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape);
}
/// <summary> /// <summary>
/// Tape message that is fired when tape is playing /// Tape message that is fired when tape is playing
/// </summary> /// </summary>
@ -176,7 +204,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
return; return;
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.Append("PLAYING (" + _machine.TapeMediaIndex + ": " + _tapeInfo[_machine.TapeMediaIndex].Name + ")"); sb.Append("PLAYING MANUAL (" + _machine.TapeMediaIndex + ": " + _tapeInfo[_machine.TapeMediaIndex].Name + ")");
SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape);
} }
@ -190,7 +218,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
return; return;
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.Append("STOPPED (" + _machine.TapeMediaIndex + ": " + _tapeInfo[_machine.TapeMediaIndex].Name + ")"); sb.Append("STOPPED MANUAL (" + _machine.TapeMediaIndex + ": " + _tapeInfo[_machine.TapeMediaIndex].Name + ")");
SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape);
} }

View File

@ -46,7 +46,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{ {
case MachineType.CPC464: case MachineType.CPC464:
ControllerDefinition = AmstradCPCControllerDefinition; ControllerDefinition = AmstradCPCControllerDefinition;
Init(MachineType.CPC464, _files); Init(MachineType.CPC464, _files, ((AmstradCPCSyncSettings)syncSettings as AmstradCPCSyncSettings).AutoStartStopTape);
break; break;
default: default:
throw new InvalidOperationException("Machine not yet emulated"); throw new InvalidOperationException("Machine not yet emulated");
@ -139,7 +139,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
private MachineType _machineType; private MachineType _machineType;
private void Init(MachineType machineType, List<byte[]> files) private void Init(MachineType machineType, List<byte[]> files, bool autoTape)
{ {
_machineType = machineType; _machineType = machineType;
@ -147,7 +147,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
switch (machineType) switch (machineType)
{ {
case MachineType.CPC464: case MachineType.CPC464:
_machine = new CPC464(this, _cpu, files); _machine = new CPC464(this, _cpu, files, autoTape);
var _systemRom16 = GetFirmware(0x4000, "464ROM"); var _systemRom16 = GetFirmware(0x4000, "464ROM");
var romData16 = RomData.InitROM(machineType, _systemRom16); var romData16 = RomData.InitROM(machineType, _systemRom16);
_machine.InitROM(romData16); _machine.InitROM(romData16);

View File

@ -8,22 +8,22 @@ using System.Text;
namespace BizHawk.Emulation.Cores.Computers.AmstradCPC namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{ {
/// <summary> /// <summary>
/// Represents the tape device (or build-in datacorder as it was called +2 and above) /// Represents the tape device
/// </summary> /// </summary>
public class DatacorderDevice : IPortIODevice public class DatacorderDevice
{ {
#region Construction #region Construction
private CPCBase _machine { get; set; } private CPCBase _machine;
private Z80A _cpu { get; set; } private Z80A _cpu => _machine.CPU;
private IBeeperDevice _buzzer { get; set; } private IBeeperDevice _buzzer => _machine.TapeBuzzer;
/// <summary> /// <summary>
/// Default constructor /// Default constructor
/// </summary> /// </summary>
public DatacorderDevice() public DatacorderDevice(bool autoTape)
{ {
_autoPlay = autoTape;
} }
/// <summary> /// <summary>
@ -33,8 +33,6 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
public void Init(CPCBase machine) public void Init(CPCBase machine)
{ {
_machine = machine; _machine = machine;
_cpu = _machine.CPU;
_buzzer = machine.TapeBuzzer;
} }
#endregion #endregion
@ -44,7 +42,38 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
/// <summary> /// <summary>
/// Signs whether the tape motor is running /// Signs whether the tape motor is running
/// </summary> /// </summary>
public bool TapeMotor; private bool tapeMotor;
public bool TapeMotor
{
get { return tapeMotor; }
set
{
if (tapeMotor == value)
return;
tapeMotor = value;
if (tapeMotor)
{
_machine.CPC.OSD_TapeMotorActive();
if (_autoPlay)
{
Play();
}
}
else
{
_machine.CPC.OSD_TapeMotorInactive();
if (_autoPlay)
{
Stop();
}
}
}
}
/// <summary> /// <summary>
/// Internal counter used to trigger tape buzzer output /// Internal counter used to trigger tape buzzer output
@ -140,7 +169,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
/// </summary> /// </summary>
public void EndFrame() public void EndFrame()
{ {
MonitorFrame(); //MonitorFrame();
} }
public void StartFrame() public void StartFrame()
@ -160,8 +189,11 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
if (_tapeIsPlaying) if (_tapeIsPlaying)
return; return;
if (!_autoPlay)
_machine.CPC.OSD_TapePlaying(); _machine.CPC.OSD_TapePlaying();
_machine.CPC.OSD_TapeMotorActive();
// update the lastCycle // update the lastCycle
_lastCycle = _cpu.TotalExecutedCycles; _lastCycle = _cpu.TotalExecutedCycles;
@ -368,7 +400,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
/// </summary> /// </summary>
public void TapeCycle() public void TapeCycle()
{ {
if (TapeIsPlaying) if (TapeMotor)
{ {
counter++; counter++;
@ -391,10 +423,8 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
// decide how many cycles worth of data we are capturing // decide how many cycles worth of data we are capturing
long cycles = cpuCycle - _lastCycle; long cycles = cpuCycle - _lastCycle;
//bool is48k = _machine.IsIn48kMode();
// check whether tape is actually playing // check whether tape is actually playing
if (_tapeIsPlaying == false) if (tapeMotor == false)
{ {
// it's not playing. Update lastCycle and return // it's not playing. Update lastCycle and return
_lastCycle = cpuCycle; _lastCycle = cpuCycle;
@ -415,7 +445,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
// decrement cycles // decrement cycles
cycles -= _waitEdge; cycles -= _waitEdge;
if (_position == 0 && _tapeIsPlaying) if (_position == 0 && tapeMotor)
{ {
// start of block - take care of initial pulse level for PZX // start of block - take care of initial pulse level for PZX
switch (_dataBlocks[_currentDataBlockIndex].BlockDescription) switch (_dataBlocks[_currentDataBlockIndex].BlockDescription)
@ -437,6 +467,53 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
break; break;
} }
// most of these amstrad tapes appear to have a pause block at the start
// skip this if it is the first block
switch (_dataBlocks[_currentDataBlockIndex].BlockDescription)
{
case BlockType.PAUS:
case BlockType.PAUSE_BLOCK:
case BlockType.Pause_or_Stop_the_Tape:
if (_currentDataBlockIndex == 0)
{
// this is the first block on the tape
SkipBlock(true);
}
else
{
// there may be non-data blocks before this
bool okToSkipPause = true;
for (int i = _currentDataBlockIndex; i >= 0; i--)
{
switch (_dataBlocks[i].BlockDescription)
{
case BlockType.Archive_Info:
case BlockType.BRWS:
case BlockType.Custom_Info_Block:
case BlockType.Emulation_Info:
case BlockType.Glue_Block:
case BlockType.Hardware_Type:
case BlockType.Message_Block:
case BlockType.PZXT:
case BlockType.Text_Description:
break;
default:
okToSkipPause = false;
break;
}
if (!okToSkipPause)
break;
}
if (okToSkipPause)
{
SkipBlock(true);
}
}
break;
}
// notify about the current block // notify about the current block
var bl = _dataBlocks[_currentDataBlockIndex]; var bl = _dataBlocks[_currentDataBlockIndex];
@ -576,188 +653,11 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
currentState = !currentState; currentState = !currentState;
} }
/// <summary>
/// Flash loading implementation
/// (Deterministic Emulation must be FALSE)
/// </summary>
private bool FlashLoad()
{
// deterministic emulation must = false
//if (_machine.Spectrum.SyncSettings.DeterministicEmulation)
//return;
var util = _machine.CPC;
if (_currentDataBlockIndex < 0)
_currentDataBlockIndex = 0;
if (_currentDataBlockIndex >= DataBlocks.Count)
return false;
//var val = GetEarBit(_cpu.TotalExecutedCycles);
//_buzzer.ProcessPulseValue(true, val);
ushort addr = _cpu.RegPC;
if (_machine.CPC.SyncSettings.DeterministicEmulation)
{
}
var tb = DataBlocks[_currentDataBlockIndex];
var tData = tb.BlockData;
if (tData == null || tData.Length < 2)
{
// skip this
return false;
}
var toRead = tData.Length - 1;
if (toRead < _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8))
{
}
else
{
toRead = _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8);
}
if (toRead <= 0)
return false;
var parity = tData[0];
if (parity != _cpu.Regs[_cpu.F_s] + (_cpu.Regs[_cpu.A_s] << 8) >> 8)
return false;
util.SetCpuRegister("Shadow AF", 0x0145);
for (var i = 0; i < toRead; i++)
{
var v = tData[i + 1];
_cpu.Regs[_cpu.L] = v;
parity ^= v;
var d = (ushort)(_cpu.Regs[_cpu.Ixl] + (_cpu.Regs[_cpu.Ixh] << 8) + 1);
_machine.WriteBus(d, v);
}
var pc = (ushort)0x05DF;
if (_cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8) == toRead &&
toRead + 1 < tData.Length)
{
var v = tData[toRead + 1];
_cpu.Regs[_cpu.L] = v;
parity ^= v;
_cpu.Regs[_cpu.B] = 0xB0;
}
else
{
_cpu.Regs[_cpu.L] = 1;
_cpu.Regs[_cpu.B] = 0;
_cpu.Regs[_cpu.F] = 0x50;
_cpu.Regs[_cpu.A] = parity;
pc = 0x05EE;
}
_cpu.Regs[_cpu.H] = parity;
var de = _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8);
util.SetCpuRegister("DE", de - toRead);
var ix = _cpu.Regs[_cpu.Ixl] + (_cpu.Regs[_cpu.Ixh] << 8);
util.SetCpuRegister("IX", ix + toRead);
util.SetCpuRegister("PC", pc);
_currentDataBlockIndex++;
return true;
}
#endregion #endregion
#region TapeMonitor #region TapeMonitor
private long _lastINCycle = 0;
private int _monitorCount;
private int _monitorTimeOut;
private ushort _monitorLastPC;
private ushort[] _monitorLastRegs = new ushort[7];
/// <summary>
/// Resets the TapeMonitor
/// </summary>
private void MonitorReset()
{
_lastINCycle = 0;
_monitorCount = 0;
_monitorLastPC = 0;
_monitorLastRegs = null;
}
/// <summary>
/// An iteration of the monitor process
/// </summary>
public void MonitorRead()
{
long cpuCycle = _cpu.TotalExecutedCycles;
int delta = (int)(cpuCycle - _lastINCycle);
_lastINCycle = cpuCycle;
var nRegs = new ushort[]
{
_cpu.Regs[_cpu.A],
_cpu.Regs[_cpu.B],
_cpu.Regs[_cpu.C],
_cpu.Regs[_cpu.D],
_cpu.Regs[_cpu.E],
_cpu.Regs[_cpu.H],
_cpu.Regs[_cpu.L]
};
if (delta > 0 &&
delta < 96 &&
_cpu.RegPC == _monitorLastPC &&
_monitorLastRegs != null)
{
int dCnt = 0;
int dVal = 0;
for (int i = 0; i < nRegs.Length; i++)
{
if (_monitorLastRegs[i] != nRegs[i])
{
dVal = _monitorLastRegs[i] - nRegs[i];
dCnt++;
}
}
if (dCnt == 1 &&
(dVal == 1 || dVal == -1))
{
_monitorCount++;
if (_monitorCount >= 16 && _autoPlay)
{
if (!_tapeIsPlaying)
{
Play();
_machine.CPC.OSD_TapePlayingAuto();
}
_monitorTimeOut = 50;
}
}
else
{
_monitorCount = 0;
}
}
_monitorLastRegs = nRegs;
_monitorLastPC = _cpu.RegPC;
}
public void AutoStopTape() public void AutoStopTape()
{ {
@ -783,6 +683,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
_machine.CPC.OSD_TapePlayingAuto(); _machine.CPC.OSD_TapePlayingAuto();
} }
/*
public int MaskableInterruptCount = 0; public int MaskableInterruptCount = 0;
private void MonitorFrame() private void MonitorFrame()
@ -851,6 +752,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
} }
} }
} }
*/
#endregion #endregion
@ -866,15 +768,14 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
/// <summary> /// <summary>
/// Device responds to an IN instruction /// Device responds to an IN instruction
/// </summary> /// </summary>
/// <param name="port"></param>
/// <param name="result"></param>
/// <returns></returns> /// <returns></returns>
public bool ReadPort(ushort port, ref int result) public bool ReadPort()
{ {
if (TapeIsPlaying) if (TapeIsPlaying)
{ {
GetEarBit(_cpu.TotalExecutedCycles); GetEarBit(_cpu.TotalExecutedCycles);
} }
/*
if (currentState) if (currentState)
{ {
result |= TAPE_BIT; result |= TAPE_BIT;
@ -883,55 +784,15 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{ {
result &= ~TAPE_BIT; result &= ~TAPE_BIT;
} }
*/
if (!TapeIsPlaying) if (!TapeIsPlaying)
{ {
if (_machine.UPDDiskDevice == null || !_machine.UPDDiskDevice.FDD_IsDiskLoaded) //if (_machine.UPDDiskDevice == null || !_machine.UPDDiskDevice.FDD_IsDiskLoaded)
MonitorRead(); //MonitorRead();
} }
if (_machine.UPDDiskDevice == null || !_machine.UPDDiskDevice.FDD_IsDiskLoaded) //if (_machine.UPDDiskDevice == null || !_machine.UPDDiskDevice.FDD_IsDiskLoaded)
MonitorRead(); //MonitorRead();
/*
if (TapeIsPlaying)
{
if (GetEarBit(_cpu.TotalExecutedCycles))
{
result &= ~(TAPE_BIT); // reset is EAR ON
}
else
{
result |= (TAPE_BIT); // set is EAR Off
}
}
else
{
if (_machine.KeyboardDevice.IsIssue2Keyboard)
{
if ((_machine.LASTULAOutByte & (EAR_BIT + MIC_BIT)) == 0)
{
result &= ~(TAPE_BIT);
}
else
{
result |= (TAPE_BIT);
}
}
else
{
if ((_machine.LASTULAOutByte & EAR_BIT) == 0)
{
result &= ~(TAPE_BIT);
}
else
{
result |= TAPE_BIT;
}
}
}
*/
return true; return true;
} }
@ -939,17 +800,18 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
/// <summary> /// <summary>
/// Device responds to an OUT instruction /// Device responds to an OUT instruction
/// </summary> /// </summary>
/// <param name="port"></param> /// <param name="state"></param>
/// <param name="result"></param>
/// <returns></returns> /// <returns></returns>
public bool WritePort(ushort port, int result) public void WritePort(bool state)
{ {
// not implemented
/*
if (!TapeIsPlaying) if (!TapeIsPlaying)
{ {
currentState = ((byte)result & 0x10) != 0; currentState = ((byte)result & 0x10) != 0;
} }
*/
return true;
} }
#endregion #endregion
@ -970,12 +832,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
ser.Sync("_lastCycle", ref _lastCycle); ser.Sync("_lastCycle", ref _lastCycle);
ser.Sync("_waitEdge", ref _waitEdge); ser.Sync("_waitEdge", ref _waitEdge);
ser.Sync("currentState", ref currentState); ser.Sync("currentState", ref currentState);
ser.Sync("_lastINCycle", ref _lastINCycle); ser.Sync("TapeMotor", ref tapeMotor);
ser.Sync("_monitorCount", ref _monitorCount);
ser.Sync("_monitorTimeOut", ref _monitorTimeOut);
ser.Sync("_monitorLastPC", ref _monitorLastPC);
ser.Sync("_monitorLastRegs", ref _monitorLastRegs, false);
ser.Sync("TapeMotor", ref TapeMotor);
ser.EndSection(); ser.EndSection();
} }

View File

@ -168,6 +168,11 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
{ {
_RMR = value; _RMR = value;
//ScreenMode = _RMR & 0x03; //ScreenMode = _RMR & 0x03;
var sm = _RMR & 0x03;
if (sm != 1)
{
}
if ((_RMR & 0x08) != 0) if ((_RMR & 0x08) != 0)
_machine.UpperROMPaged = false; _machine.UpperROMPaged = false;
@ -254,7 +259,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
/// <summary> /// <summary>
/// Master frame clock counter /// Master frame clock counter
/// </summary> /// </summary>
private int FrameClock; public int FrameClock;
/// <summary> /// <summary>
/// Simulates the gate array memory /WAIT line /// Simulates the gate array memory /WAIT line
@ -354,7 +359,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
// check for frame end // check for frame end
if (FrameClock == FrameLength) if (FrameClock == FrameLength)
{ {
FrameClock = 0; //FrameClock = 0;
FrameEnd = true; FrameEnd = true;
} }
} }
@ -502,7 +507,6 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
// update screenmode // update screenmode
ScreenMode = RMR & 0x03; ScreenMode = RMR & 0x03;
CRT.CurrentLine.InitScanline(ScreenMode, VLC); CRT.CurrentLine.InitScanline(ScreenMode, VLC);
//CRT.InitScanline(VLC, ScreenMode);
} }
else if (!CRCT.HSYNC) else if (!CRCT.HSYNC)
{ {
@ -786,6 +790,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
ser.Sync("CurrentPen", ref CurrentPen); ser.Sync("CurrentPen", ref CurrentPen);
ser.Sync("ClockCounter", ref ClockCounter); ser.Sync("ClockCounter", ref ClockCounter);
ser.Sync("FrameClock", ref FrameClock); ser.Sync("FrameClock", ref FrameClock);
ser.Sync("FrameEnd", ref FrameEnd);
ser.Sync("WaitLine", ref WaitLine); ser.Sync("WaitLine", ref WaitLine);
ser.Sync("_interruptCounter", ref _interruptCounter); ser.Sync("_interruptCounter", ref _interruptCounter);
ser.Sync("ScreenMode", ref ScreenMode); ser.Sync("ScreenMode", ref ScreenMode);
@ -796,6 +801,12 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
ser.Sync("InterruptRaised", ref InterruptRaised); ser.Sync("InterruptRaised", ref InterruptRaised);
ser.Sync("InterruptHoldCounter", ref InterruptHoldCounter); ser.Sync("InterruptHoldCounter", ref InterruptHoldCounter);
ser.Sync("_MA", ref _MA); ser.Sync("_MA", ref _MA);
ser.Sync("IsNewFrame", ref IsNewFrame);
ser.Sync("IsNewLine", ref IsNewLine);
ser.Sync("HCC", ref HCC);
ser.Sync("VLC", ref VLC);
ser.Sync("VideoByte1", ref VideoByte1);
ser.Sync("VideoByte2", ref VideoByte2);
ser.EndSection(); ser.EndSection();
} }

View File

@ -206,7 +206,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
public ushort CurrentByteAddress; public ushort CurrentByteAddress;
/// <summary> /// <summary>
/// ByteCOunter /// ByteCounter
/// </summary> /// </summary>
public int ByteCounter; public int ByteCounter;
@ -890,6 +890,8 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
ser.Sync("VSYNC", ref VSYNC); ser.Sync("VSYNC", ref VSYNC);
ser.Sync("DISPTMG", ref DISPTMG); ser.Sync("DISPTMG", ref DISPTMG);
ser.Sync("MA", ref MA); ser.Sync("MA", ref MA);
ser.Sync("CurrentByteAddress", ref CurrentByteAddress);
ser.Sync("ByteCounter", ref ByteCounter);
ser.Sync("Regs", ref Regs, false); ser.Sync("Regs", ref Regs, false);
ser.Sync("SelectedRegister", ref SelectedRegister); ser.Sync("SelectedRegister", ref SelectedRegister);
ser.Sync("HCC", ref HCC); ser.Sync("HCC", ref HCC);

View File

@ -232,6 +232,12 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
public void SyncState(Serializer ser) public void SyncState(Serializer ser)
{ {
ser.BeginSection("CRT"); ser.BeginSection("CRT");
ser.Sync("BufferWidth", ref _bufferWidth);
ser.Sync("BufferHeight", ref _bufferHeight);
ser.Sync("VirtualHeight", ref _virtualHeight);
ser.Sync("VirtualWidth", ref _virtualWidth);
ser.Sync("ScreenBuffer", ref ScreenBuffer, false);
ser.Sync("ScanlineCounter", ref ScanlineCounter);
ser.EndSection(); ser.EndSection();
} }
@ -322,7 +328,24 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
private void AddBorderValue(int charIndex, int colourValue) private void AddBorderValue(int charIndex, int colourValue)
{ {
Characters[charIndex].Phase = RenderPhase.BORDER; Characters[charIndex].Phase = RenderPhase.BORDER;
switch (ScreenMode)
{
case 0:
Characters[charIndex].Pixels = new int[8]; Characters[charIndex].Pixels = new int[8];
break;
case 1:
Characters[charIndex].Pixels = new int[8];
break;
case 2:
Characters[charIndex].Pixels = new int[16];
break;
case 3:
Characters[charIndex].Pixels = new int[8];
break;
}
for (int i = 0; i < Characters[charIndex].Pixels.Length; i++) for (int i = 0; i < Characters[charIndex].Pixels.Length; i++)
{ {
@ -345,8 +368,9 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
switch (ScreenMode) switch (ScreenMode)
{ {
// 4 bits per pixel - 2 bytes - 4 pixels (8 CRT pixels) // 4 bits per pixel - 2 bytes - 4 pixels (8 CRT pixels)
// RECT
case 0: case 0:
Characters[charIndex].Pixels = new int[4]; Characters[charIndex].Pixels = new int[8];
int m0Count = 0; int m0Count = 0;
@ -356,18 +380,23 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
int m0B0P1 = ((m0B0P1i & 0x40) >> 6) | ((m0B0P1i & 0x04) >> 1) | ((m0B0P1i & 0x10) >> 2) | ((m0B0P1i & 0x01 << 3)); int m0B0P1 = ((m0B0P1i & 0x40) >> 6) | ((m0B0P1i & 0x04) >> 1) | ((m0B0P1i & 0x10) >> 2) | ((m0B0P1i & 0x01 << 3));
Characters[charIndex].Pixels[m0Count++] = CRTDevice.CPCHardwarePalette[pens[m0B0P0]]; Characters[charIndex].Pixels[m0Count++] = CRTDevice.CPCHardwarePalette[pens[m0B0P0]];
Characters[charIndex].Pixels[m0Count++] = CRTDevice.CPCHardwarePalette[pens[m0B0P0]];
Characters[charIndex].Pixels[m0Count++] = CRTDevice.CPCHardwarePalette[pens[m0B0P1]];
Characters[charIndex].Pixels[m0Count++] = CRTDevice.CPCHardwarePalette[pens[m0B0P1]]; Characters[charIndex].Pixels[m0Count++] = CRTDevice.CPCHardwarePalette[pens[m0B0P1]];
int m0B1P0i = vid1 & 170; int m0B1P0i = vid2 & 170;
int m0B1P0 = ((m0B1P0i & 0x80) >> 7) | ((m0B1P0i & 0x08) >> 2) | ((m0B1P0i & 0x20) >> 3) | ((m0B1P0i & 0x02 << 2)); int m0B1P0 = ((m0B1P0i & 0x80) >> 7) | ((m0B1P0i & 0x08) >> 2) | ((m0B1P0i & 0x20) >> 3) | ((m0B1P0i & 0x02 << 2));
int m0B1P1i = vid1 & 85; int m0B1P1i = vid2 & 85;
int m0B1P1 = ((m0B1P1i & 0x40) >> 6) | ((m0B1P1i & 0x04) >> 1) | ((m0B1P1i & 0x10) >> 2) | ((m0B1P1i & 0x01 << 3)); int m0B1P1 = ((m0B1P1i & 0x40) >> 6) | ((m0B1P1i & 0x04) >> 1) | ((m0B1P1i & 0x10) >> 2) | ((m0B1P1i & 0x01 << 3));
Characters[charIndex].Pixels[m0Count++] = CRTDevice.CPCHardwarePalette[pens[m0B1P0]]; Characters[charIndex].Pixels[m0Count++] = CRTDevice.CPCHardwarePalette[pens[m0B1P0]];
Characters[charIndex].Pixels[m0Count++] = CRTDevice.CPCHardwarePalette[pens[m0B1P0]];
Characters[charIndex].Pixels[m0Count++] = CRTDevice.CPCHardwarePalette[pens[m0B1P1]];
Characters[charIndex].Pixels[m0Count++] = CRTDevice.CPCHardwarePalette[pens[m0B1P1]]; Characters[charIndex].Pixels[m0Count++] = CRTDevice.CPCHardwarePalette[pens[m0B1P1]];
break; break;
// 2 bits per pixel - 2 bytes - 8 pixels (16 CRT pixels) // 2 bits per pixel - 2 bytes - 8 pixels (16 CRT pixels)
// SQUARE
case 1: case 1:
Characters[charIndex].Pixels = new int[8]; Characters[charIndex].Pixels = new int[8];
@ -394,18 +423,21 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
Characters[charIndex].Pixels[m1Count++] = CRTDevice.CPCHardwarePalette[pens[m1B1P3]]; Characters[charIndex].Pixels[m1Count++] = CRTDevice.CPCHardwarePalette[pens[m1B1P3]];
break; break;
// 1 bit per pixel - 2 bytes - 16 pixels (32 CRT pixels) // 1 bit per pixel - 2 bytes - 16 pixels (16 CRT pixels)
// RECT
case 2: case 2:
Characters[charIndex].Pixels = new int[16]; Characters[charIndex].Pixels = new int[16];
int m2Count = 0; int m2Count = 0;
int[] pixBuff = new int[16];
for (int bit = 7; bit >= 0; bit--) for (int bit = 7; bit >= 0; bit--)
{ {
int val = vid1.Bit(bit) ? 1 : 0; int val = vid1.Bit(bit) ? 1 : 0;
Characters[charIndex].Pixels[m2Count++] = CRTDevice.CPCHardwarePalette[pens[val]]; Characters[charIndex].Pixels[m2Count++] = CRTDevice.CPCHardwarePalette[pens[val]];
}
}
for (int bit = 7; bit >= 0; bit--) for (int bit = 7; bit >= 0; bit--)
{ {
int val = vid2.Bit(bit) ? 1 : 0; int val = vid2.Bit(bit) ? 1 : 0;
@ -414,6 +446,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
break; break;
// 4 bits per pixel - 2 bytes - 4 pixels (8 CRT pixels) // 4 bits per pixel - 2 bytes - 4 pixels (8 CRT pixels)
// RECT
case 3: case 3:
Characters[charIndex].Pixels = new int[4]; Characters[charIndex].Pixels = new int[4];
@ -461,7 +494,26 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
/// </summary> /// </summary>
public void CommitScanline() public void CommitScanline()
{ {
int hPix = GetPixelCount() * 2; int hScale = 1;
int vScale = 1;
switch (ScreenMode)
{
case 0:
case 1:
case 3:
hScale = 2;
vScale = 2;
break;
case 2:
hScale = 1;
vScale = 2;
break;
}
int hPix = GetPixelCount() * hScale;
//int hPix = GetPixelCount() * 2;
int leftOver = CRT.BufferWidth - hPix; int leftOver = CRT.BufferWidth - hPix;
int lPad = leftOver / 2; int lPad = leftOver / 2;
int rPad = lPad; int rPad = lPad;
@ -477,8 +529,8 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
// render out the scanline // render out the scanline
int pCount = (LineIndex - CRT.TopLinesToTrim) * 2 * CRT.BufferWidth; int pCount = (LineIndex - CRT.TopLinesToTrim) * 2 * CRT.BufferWidth;
// double up // vScale
for (int s = 0; s < 2; s++) for (int s = 0; s < vScale; s++)
{ {
// left padding // left padding
for (int lP = 0; lP < lPad; lP++) for (int lP = 0; lP < lPad; lP++)
@ -493,9 +545,14 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
continue; continue;
for (int p = 0; p < c.Pixels.Length; p++) for (int p = 0; p < c.Pixels.Length; p++)
{
// hScale
for (int h = 0; h < hScale; h++)
{ {
CRT.ScreenBuffer[pCount++] = c.Pixels[p]; CRT.ScreenBuffer[pCount++] = c.Pixels[p];
CRT.ScreenBuffer[pCount++] = c.Pixels[p]; }
//CRT.ScreenBuffer[pCount++] = c.Pixels[p];
} }
} }

View File

@ -73,7 +73,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
/// <summary> /// <summary>
/// Device blipbuffer /// Device blipbuffer
/// </summary> /// </summary>
private readonly BlipBuffer blip = new BlipBuffer(882); private readonly BlipBuffer blip = new BlipBuffer(1024);
#endregion #endregion

View File

@ -56,56 +56,6 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
} }
return (byte)result; return (byte)result;
if ((port & 0x8000) == 0)
{
if ((port & 0x4000) != 0)
{
GateArray.ReadPort(port, ref result);
}
else
{
// ram
}
}
else if ((port & 0x4000) == 0)
{
CRCT.ReadPort(port, ref result);
}
else if ((port & 0x0300) == 0)
{
// rom
}
else if ((port & 0x1000) == 0)
{
// printer
}
else if ((port & 0x0800) == 0)
{
PPI.ReadPort(port, ref result);
}
else if ((port & 0x0400) == 0)
{
// exp
}
return (byte)result;
if (CRCT.ReadPort(port, ref result))
{
return (byte)result;
}
else if (PPI.ReadPort(port, ref result))
{
return (byte)result;
}
else if (GateArray.ReadPort(port, ref result))
{
return (byte)result;
}
return (byte)result;
} }
/// <summary> /// <summary>
@ -156,18 +106,6 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
} }
return; return;
if (GateArray.WritePort(port, value))
{ }
if (CRCT.WritePort(port, value))
{ }
// rom select
// printer port
if (PPI.WritePort(port, value))
{ }
} }
} }
} }

View File

@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
/// </summary> /// </summary>
/// <param name="spectrum"></param> /// <param name="spectrum"></param>
/// <param name="cpu"></param> /// <param name="cpu"></param>
public CPC464(AmstradCPC cpc, Z80A cpu, List<byte[]> files) public CPC464(AmstradCPC cpc, Z80A cpu, List<byte[]> files, bool autoTape)
{ {
CPC = cpc; CPC = cpc;
CPU = cpu; CPU = cpu;
@ -37,7 +37,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
KeyboardDevice = new StandardKeyboard(this); KeyboardDevice = new StandardKeyboard(this);
TapeDevice = new DatacorderDevice(); TapeDevice = new DatacorderDevice(autoTape);
TapeDevice.Init(this); TapeDevice.Init(this);
InitializeMedia(files); InitializeMedia(files);

View File

@ -109,7 +109,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
/// <summary> /// <summary>
/// Gets the current frame cycle according to the CPU tick count /// Gets the current frame cycle according to the CPU tick count
/// </summary> /// </summary>
public virtual long CurrentFrameCycle => CPU.TotalExecutedCycles - LastFrameStartCPUTick; public virtual long CurrentFrameCycle => GateArray.FrameClock; // CPU.TotalExecutedCycles - LastFrameStartCPUTick;
/// <summary> /// <summary>
/// Non-Deterministic bools /// Non-Deterministic bools
@ -170,10 +170,10 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
TapeDevice.TapeCycle(); TapeDevice.TapeCycle();
} }
OverFlow = (int)CurrentFrameCycle - GateArray.FrameLength; //OverFlow = (int)CurrentFrameCycle - GateArray.FrameLength;
// we have reached the end of a frame // we have reached the end of a frame
LastFrameStartCPUTick = CPU.TotalExecutedCycles - OverFlow; LastFrameStartCPUTick = CPU.TotalExecutedCycles; // - OverFlow;
if (AYDevice != null) if (AYDevice != null)
AYDevice.EndFrame(); AYDevice.EndFrame();
@ -199,6 +199,8 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
//System.IO.File.WriteAllText(UPDDiskDevice.outputfile, UPDDiskDevice.outputString); //System.IO.File.WriteAllText(UPDDiskDevice.outputfile, UPDDiskDevice.outputString);
} }
} }
GateArray.FrameClock = 0;
} }
#endregion #endregion
@ -334,14 +336,11 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
ser.Sync("RAM3", ref RAM3, false); ser.Sync("RAM3", ref RAM3, false);
CRCT.SyncState(ser); CRCT.SyncState(ser);
CRT.SyncState(ser);
//KeyboardDevice.SyncState(ser); GateArray.SyncState(ser);
//BuzzerDevice.SyncState(ser); KeyboardDevice.SyncState(ser);
TapeBuzzer.SyncState(ser); TapeBuzzer.SyncState(ser);
AYDevice.SyncState(ser); AYDevice.SyncState(ser);
//.SyncState(ser);
//CPUMon.SyncState(ser);
ser.Sync("tapeMediaIndex", ref tapeMediaIndex); ser.Sync("tapeMediaIndex", ref tapeMediaIndex);
if (ser.IsReader) if (ser.IsReader)