diff --git a/Contralto/CPU/Tasks/EmulatorTask.cs b/Contralto/CPU/Tasks/EmulatorTask.cs
index 4bf1232..0646eba 100644
--- a/Contralto/CPU/Tasks/EmulatorTask.cs
+++ b/Contralto/CPU/Tasks/EmulatorTask.cs
@@ -40,7 +40,17 @@ namespace Contralto.CPU
switch (ebs)
{
case EmulatorBusSource.ReadSLocation:
- return _cpu._s[_cpu._rb][_rSelect];
+ if (_rSelect != 0)
+ {
+ return _cpu._s[_cpu._rb][_rSelect];
+ }
+ else
+ {
+ // "...when reading data from the S registers onto the processor bus,
+ // the RSELECT value 0 causes the current value of the M register to
+ // appear on the bus..."
+ return _cpu._m;
+ }
case EmulatorBusSource.LoadSLocation:
_loadS = true;
@@ -71,7 +81,7 @@ namespace Contralto.CPU
break;
case EmulatorF1.SWMODE:
- // nothing! for now.
+ throw new NotImplementedException();
break;
default:
diff --git a/Contralto/CPU/Tasks/Task.cs b/Contralto/CPU/Tasks/Task.cs
index 73a9b3f..74d9d0a 100644
--- a/Contralto/CPU/Tasks/Task.cs
+++ b/Contralto/CPU/Tasks/Task.cs
@@ -241,8 +241,9 @@ namespace Contralto.CPU
// Do nothing. Well, that was easy.
break;
- case SpecialFunction1.LoadMAR:
- _cpu._system.MemoryBus.LoadMAR(aluData); // Start main memory reference
+ case SpecialFunction1.LoadMAR:
+ // Do MAR or XMAR reference based on whether F2 is MD<-, indicating an extended memory reference.
+ _cpu._system.MemoryBus.LoadMAR(aluData, _taskType, instruction.F2 == SpecialFunction2.StoreMD);
break;
case SpecialFunction1.Task:
@@ -326,7 +327,12 @@ namespace Contralto.CPU
break;
case SpecialFunction2.StoreMD:
- _cpu._system.MemoryBus.LoadMD(_busData);
+ // Special case for XMAR; if F1 is a LoadMAR we do nothing here;
+ // the handler for LoadMAR will load the correct bank.
+ if (instruction.F1 != SpecialFunction1.LoadMAR)
+ {
+ _cpu._system.MemoryBus.LoadMD(_busData);
+ }
break;
case SpecialFunction2.Constant:
diff --git a/Contralto/IO/Keyboard.cs b/Contralto/IO/Keyboard.cs
index a0b8511..cbfc485 100644
--- a/Contralto/IO/Keyboard.cs
+++ b/Contralto/IO/Keyboard.cs
@@ -5,6 +5,8 @@ using System.Text;
using System.Threading.Tasks;
using Contralto.Memory;
+using Contralto.CPU;
+using Contralto.Logging;
namespace Contralto.IO
{
@@ -18,13 +20,14 @@ namespace Contralto.IO
}
- public ushort Read(int address)
+ public ushort Read(int address, TaskType task, bool extendedMemoryReference)
{
// TODO: implement; return nothing pressed for any address now.
+ Log.Write(LogComponent.Keyboard, "Keyboard read; unimplemented.");
return 0xffff;
}
- public void Load(int address, ushort data)
+ public void Load(int address, ushort data, TaskType task, bool extendedMemoryReference)
{
// nothing
}
diff --git a/Contralto/Memory/IMemoryMappedDevice.cs b/Contralto/Memory/IMemoryMappedDevice.cs
index 1dfadd8..ccf8d34 100644
--- a/Contralto/Memory/IMemoryMappedDevice.cs
+++ b/Contralto/Memory/IMemoryMappedDevice.cs
@@ -1,4 +1,5 @@
-using System;
+using Contralto.CPU;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -42,15 +43,16 @@ namespace Contralto.Memory
/// Reads a word from the specified address.
///
///
+ ///
///
- ushort Read(int address);
+ ushort Read(int address, TaskType task, bool extendedMemory);
///
/// Writes a word to the specified address.
///
///
///
- void Load(int address, ushort data);
+ void Load(int address, ushort data, TaskType task, bool extendedMemory);
///
/// Specifies the range (or ranges) of addresses decoded by this device.
diff --git a/Contralto/Memory/Memory.cs b/Contralto/Memory/Memory.cs
index 8c81d64..7f2bdc0 100644
--- a/Contralto/Memory/Memory.cs
+++ b/Contralto/Memory/Memory.cs
@@ -1,4 +1,5 @@
-using Contralto.Logging;
+using Contralto.CPU;
+using Contralto.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -16,17 +17,53 @@ namespace Contralto.Memory
public void Reset()
{
- _mem = new ushort[0x10000];
+ // 4 64K banks
+ _mem = new ushort[0x40000];
+ _xmBanks = new ushort[16];
}
- public ushort Read(int address)
+ public ushort Read(int address, TaskType task, bool extendedMemory)
{
- return _mem[address];
+ // Check for XM registers; this occurs regardless of XM flag since it's in the I/O page.
+ if (address >= _xmBanksStart && address < _xmBanksStart + 16)
+ {
+ return _xmBanks[address - _xmBanksStart];
+ }
+ else
+ {
+ address += 0x10000 * GetBankNumber(task, extendedMemory);
+ ushort data = _mem[address];
+
+ if (extendedMemory)
+ {
+ Log.Write(LogComponent.Memory, "extended memory read from {0} - {1}", Conversion.ToOctal(address), Conversion.ToOctal(data));
+ }
+
+ return data;
+ }
}
- public void Load(int address, ushort data)
- {
- _mem[address] = data;
+ public void Load(int address, ushort data, TaskType task, bool extendedMemory)
+ {
+ // Check for XM registers; this occurs regardless of XM flag since it's in the I/O page.
+ if (address >= _xmBanksStart && address < _xmBanksStart + 16)
+ {
+ _xmBanks[address - _xmBanksStart] = data;
+ Log.Write(LogComponent.Memory, "XM register for task {0} set to bank {1} (normal), {2} (xm)",
+ (TaskType)(address - _xmBanksStart),
+ (data & 0xc) >> 2,
+ (data & 0x3));
+ }
+ else
+ {
+ address += 0x10000 * GetBankNumber(task, extendedMemory);
+ _mem[address] = data;
+
+ if (extendedMemory)
+ {
+ Log.Write(LogComponent.Memory, "extended memory write to {0} of {1}", Conversion.ToOctal(address), Conversion.ToOctal(data));
+ }
+ }
}
public MemoryRange[] Addresses
@@ -34,11 +71,22 @@ namespace Contralto.Memory
get { return _addresses; }
}
+ private int GetBankNumber(TaskType task, bool extendedMemory)
+ {
+ return extendedMemory ? _xmBanks[(int)task] & 0x3 : (_xmBanks[(int)task] & 0xc) >> 2;
+ }
+
private readonly MemoryRange[] _addresses =
{
- new MemoryRange(0, 0xfdff), // to 176777; IO page above this.
+ new MemoryRange(0, _memTop), // Main bank of RAM to 176777; IO page above this.
+ new MemoryRange(_xmBanksStart, _xmBanksStart + 16), // Memory bank registers
};
+ private const int _memTop = 0xfdff; // 176777
+ private const int _xmBanksStart = 0xffe0; // 177740
+
private ushort[] _mem;
+
+ private ushort[] _xmBanks;
}
}
diff --git a/Contralto/Memory/MemoryBus.cs b/Contralto/Memory/MemoryBus.cs
index 0648ca6..931603b 100644
--- a/Contralto/Memory/MemoryBus.cs
+++ b/Contralto/Memory/MemoryBus.cs
@@ -1,4 +1,6 @@
-using System;
+using Contralto.CPU;
+using Contralto.Logging;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -51,6 +53,7 @@ namespace Contralto.Memory
_memoryAddress = 0;
_memoryData = 0;
_memoryOperationActive = false;
+ _extendedMemoryReference = false;
}
public ushort MAR
@@ -79,7 +82,9 @@ namespace Contralto.Memory
///
public ushort DebugReadWord(ushort address)
{
- return ReadFromBus(address);
+ // TODO: allow debug reads from any bank.
+ // probably add special debug calls to IMemoryMappedDevice iface.
+ return ReadFromBus(address, TaskType.Emulator, false);
}
public void Clock()
@@ -91,12 +96,12 @@ namespace Contralto.Memory
{
case 3:
// Buffered read of single word
- _memoryData = ReadFromBus(_memoryAddress);
+ _memoryData = ReadFromBus(_memoryAddress, _task, _extendedMemoryReference);
break;
case 4:
// Buffered read of double-word
- _memoryData2 = ReadFromBus((ushort)(_memoryAddress ^ 1));
+ _memoryData2 = ReadFromBus((ushort)(_memoryAddress ^ 1), _task, _extendedMemoryReference);
break;
case 5:
@@ -137,7 +142,7 @@ namespace Contralto.Memory
}
}
- public void LoadMAR(ushort address)
+ public void LoadMAR(ushort address, TaskType task, bool extendedMemoryReference)
{
if (_memoryOperationActive)
{
@@ -149,9 +154,11 @@ namespace Contralto.Memory
_memoryOperationActive = true;
_doubleWordStore = false;
_memoryAddress = address;
+ _extendedMemoryReference = extendedMemoryReference;
+ _task = task;
_memoryCycle = 1;
}
- }
+ }
public ushort ReadMD()
{
@@ -171,6 +178,7 @@ namespace Contralto.Memory
case 5:
// Single word read
+ Log.Write(LogType.Verbose, LogComponent.Memory, "Single-word read of {0} from {1} (cycle 5)", Conversion.ToOctal(_memoryData), Conversion.ToOctal(_memoryAddress ^ 1));
return _memoryData;
// ***
@@ -190,10 +198,12 @@ namespace Contralto.Memory
// If this is memory cycle 6 we will return the last half of the doubleword to complete a double-word read.
if (_memoryCycle == 6)
{
+ Log.Write(LogType.Verbose, LogComponent.Memory, "Double-word read of {0} from {1} (cycle 6)", Conversion.ToOctal(_memoryData2), Conversion.ToOctal(_memoryAddress ^ 1));
return _memoryData2;
}
else
{
+ Log.Write(LogType.Verbose, LogComponent.Memory, "Single-word read of {0} from {1} (post cycle 6)", Conversion.ToOctal(_memoryData), Conversion.ToOctal(_memoryAddress));
return _memoryData;
}
}
@@ -214,13 +224,27 @@ namespace Contralto.Memory
case 3:
_memoryData = data; // Only really necessary to show in debugger
// Start of doubleword write:
- WriteToBus(_memoryAddress, data);
+ WriteToBus(_memoryAddress, data, _task, _extendedMemoryReference);
_doubleWordStore = true;
+
+ Log.Write(
+ LogType.Verbose,
+ LogComponent.Memory,
+ "Single-word store of {0} to {1} (cycle 3)",
+ Conversion.ToOctal(data),
+ Conversion.ToOctal(_memoryAddress));
break;
case 4:
_memoryData = data; // Only really necessary to show in debugger
- WriteToBus(_doubleWordStore ? (ushort)(_memoryAddress ^ 1) : _memoryAddress, data);
+ Log.Write(
+ LogType.Verbose,
+ LogComponent.Memory,
+ _doubleWordStore ? "Double-word store of {0} to {1} (cycle 4)" : "Single-word store of {0} to {1} (cycle 4)",
+ Conversion.ToOctal(data),
+ _doubleWordStore ? Conversion.ToOctal(_memoryAddress ^ 1) : Conversion.ToOctal(_memoryAddress));
+
+ WriteToBus(_doubleWordStore ? (ushort)(_memoryAddress ^ 1) : _memoryAddress, data, _task, _extendedMemoryReference);
break;
}
@@ -232,13 +256,13 @@ namespace Contralto.Memory
///
///
///
- private ushort ReadFromBus(ushort address)
+ private ushort ReadFromBus(ushort address, TaskType task, bool extendedMemoryReference)
{
// Look up address in hash; if populated ask the device
// to return a value otherwise throw.
if (_bus.ContainsKey(address))
{
- return _bus[address].Read(address);
+ return _bus[address].Read(address, task, extendedMemoryReference);
}
else
{
@@ -254,13 +278,13 @@ namespace Contralto.Memory
///
///
///
- private void WriteToBus(ushort address, ushort data)
+ private void WriteToBus(ushort address, ushort data, TaskType task, bool extendedMemoryReference)
{
// Look up address in hash; if populated ask the device
// to store a value otherwise throw.
if (_bus.ContainsKey(address))
{
- _bus[address].Load(address, data);
+ _bus[address].Load(address, data, task, extendedMemoryReference);
}
else
{
@@ -277,7 +301,9 @@ namespace Contralto.Memory
private bool _memoryOperationActive;
private int _memoryCycle;
private ushort _memoryAddress;
-
+ private bool _extendedMemoryReference;
+ private TaskType _task;
+
// Buffered read data (on cycles 3 and 4)
private ushort _memoryData;
private ushort _memoryData2;