1
0
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:
Josh Dersch 2015-11-05 17:29:41 -08:00
parent 78e61389c1
commit e9a13529c1
6 changed files with 126 additions and 31 deletions

View File

@ -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:

View File

@ -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:

View File

@ -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
}

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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;