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;