using System;
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
///
/// The abstract class that all emulated models will inherit from
/// * Memory *
///
public abstract partial class SpectrumBase
{
#region Memory Fields & Properties
///
/// ROM Banks
///
public byte[] ROM0 = new byte[0x4000];
public byte[] ROM1 = new byte[0x4000];
public byte[] ROM2 = new byte[0x4000];
public byte[] ROM3 = new byte[0x4000];
///
/// RAM Banks
///
public byte[] RAM0 = new byte[0x4000]; // Bank 0
public byte[] RAM1 = new byte[0x4000]; // Bank 1
public byte[] RAM2 = new byte[0x4000]; // Bank 2
public byte[] RAM3 = new byte[0x4000]; // Bank 3
public byte[] RAM4 = new byte[0x4000]; // Bank 4
public byte[] RAM5 = new byte[0x4000]; // Bank 5
public byte[] RAM6 = new byte[0x4000]; // Bank 6
public byte[] RAM7 = new byte[0x4000]; // Bank 7
///
/// Signs that the shadow screen is now displaying
/// Note: normal screen memory in RAM5 is not altered, the ULA just outputs Screen1 instead (RAM7)
///
public bool SHADOWPaged;
///
/// Index of the current RAM page
/// /// 128k, +2/2a and +3 only
///
public int RAMPaged;
///
/// Signs that all paging is disabled
/// If this is TRUE, then 128k and above machines need a hard reset before paging is allowed again
///
public bool PagingDisabled;
///
/// Index of the currently paged ROM
/// 128k, +2/2a and +3 only
///
protected int ROMPaged;
public virtual int _ROMpaged
{
get { return ROMPaged; }
set { ROMPaged = value; }
}
/*
* +3/+2A only
*/
///
/// High bit of the ROM selection (in normal paging mode)
///
public bool ROMhigh = false;
///
/// Low bit of the ROM selection (in normal paging mode)
///
public bool ROMlow = false;
///
/// Signs that the +2a/+3 special paging mode is activated
///
public bool SpecialPagingMode;
///
/// Index of the current special paging mode (0-3)
///
public int PagingConfiguration;
///
/// The last byte that was read after contended cycles
///
public byte LastContendedReadByte;
#endregion
#region Memory Related Methods
///
/// Simulates reading from the bus
/// Paging should be handled here
///
///
///
public abstract byte ReadBus(ushort addr);
///
/// Pushes a value onto the data bus that should be valid as long as the interrupt is true
///
///
///
public virtual byte PushBus()
{
return 0xFF;
}
///
/// Simulates writing to the bus
/// Paging should be handled here
///
///
///
public virtual void WriteBus(ushort addr, byte value)
{
throw new NotImplementedException("Must be overriden");
}
///
/// Reads a byte of data from a specified memory address
/// (with memory contention if appropriate)
///
///
///
public abstract byte ReadMemory(ushort addr);
///
/// Returns the ROM/RAM enum that relates to this particular memory read operation
///
///
///
public abstract ZXSpectrum.CDLResult ReadCDL(ushort addr);
///
/// Writes a byte of data to a specified memory address
/// (with memory contention if appropriate)
///
///
///
public abstract void WriteMemory(ushort addr, byte value);
///
/// Sets up the ROM
///
///
public abstract void InitROM(RomData romData);
///
/// ULA reads the memory at the specified address
/// (No memory contention)
///
///
///
public virtual byte FetchScreenMemory(ushort addr)
{
var value = ReadBus((ushort)((addr & 0x3FFF) + 0x4000));
//var value = ReadBus(addr);
return value;
}
///
/// Checks whether supplied address is in a potentially contended bank
///
///
public abstract bool IsContended(ushort addr);
///
/// Returns TRUE if there is a contended bank paged in
///
///
public abstract bool ContendedBankPaged();
#endregion
#region Helper Methods
///
/// Detects whether this is a 48k machine (or a 128k in 48k mode)
///
///
public virtual bool IsIn48kMode()
{
if (this.GetType() == typeof(ZX48) ||
this.GetType() == typeof(ZX16) ||
PagingDisabled)
{
return true;
}
else
return false;
}
///
/// Monitors ROM access
/// Used to auto start/stop the tape device when appropriate
///
///
public virtual void TestForTapeTraps(int addr)
{
if (TapeDevice.TapeIsPlaying)
{
// THE 'ERROR' RESTART
if (addr == 8)
{
//TapeDevice?.AutoStopTape();
return;
}
// THE 'ED-ERROR' SUBROUTINE
if (addr == 4223)
{
//TapeDevice?.AutoStopTape();
return;
}
// THE 'ERROR-2' ROUTINE
if (addr == 83)
{
//TapeDevice?.AutoStopTape();
return;
}
// THE 'MASKABLE INTERRUPT' ROUTINE
// This is sometimes used when the tape is to be stopped
//
if (addr == 56)
{
//TapeDevice.MaskableInterruptCount++;
//if (TapeDevice.MaskableInterruptCount > 50)
//{
//TapeDevice.MaskableInterruptCount = 0;
//TapeDevice.AutoStopTape();
//}
//TapeDevice?.AutoStopTape();
return;
}
}
else
{
// THE 'LD-BYTES' SUBROUTINE
if (addr == 1366)
{
//TapeDevice?.AutoStartTape();
return;
}
// THE 'LD-EDGE-2' AND 'LD-EDGE-1' SUBROUTINES
if (addr == 1507)
{
//TapeDevice?.AutoStartTape();
return;
}
}
}
#endregion
}
}