mirror of
https://github.com/livingcomputermuseum/ContrAlto.git
synced 2026-01-21 10:12:20 +00:00
Implemented extended memory and fixed issues with S register 0 (which loads M).
This commit is contained in:
parent
78e61389c1
commit
e9a13529c1
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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.
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="extendedMemory"></param>
|
||||
/// <returns></returns>
|
||||
ushort Read(int address);
|
||||
ushort Read(int address, TaskType task, bool extendedMemory);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a word to the specified address.
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="data"></param>
|
||||
void Load(int address, ushort data);
|
||||
void Load(int address, ushort data, TaskType task, bool extendedMemory);
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the range (or ranges) of addresses decoded by this device.
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
/// </summary>
|
||||
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
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
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
|
||||
/// <param name="address"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user