mirror of
https://github.com/livingcomputermuseum/ContrAlto.git
synced 2026-01-23 19:06:39 +00:00
Tweaks to ALU, CPU, Memory
This commit is contained in:
parent
f1ffcb0547
commit
9c3ee3afac
@ -14,12 +14,12 @@ namespace Contralto.CPU
|
||||
{
|
||||
static ALU()
|
||||
{
|
||||
_lastCarry = 0;
|
||||
_carry = 0;
|
||||
}
|
||||
|
||||
public int Carry
|
||||
public static int Carry
|
||||
{
|
||||
get { return _lastCarry; }
|
||||
get { return _carry; }
|
||||
}
|
||||
|
||||
public static ushort Execute(AluFunction fn, ushort bus, ushort t)
|
||||
@ -28,59 +28,59 @@ namespace Contralto.CPU
|
||||
switch (fn)
|
||||
{
|
||||
case AluFunction.Bus:
|
||||
_lastCarry = 0; // M = 1
|
||||
_carry = 0; // M = 1
|
||||
r = bus;
|
||||
break;
|
||||
|
||||
case AluFunction.T:
|
||||
_lastCarry = 0; // M = 1
|
||||
_carry = 0; // M = 1
|
||||
r= t;
|
||||
break;
|
||||
|
||||
case AluFunction.BusOrT:
|
||||
_lastCarry = 0; // M = 1
|
||||
_carry = 0; // M = 1
|
||||
r = (bus | t);
|
||||
break;
|
||||
|
||||
case AluFunction.BusAndT:
|
||||
case AluFunction.AluBusAndT:
|
||||
_lastCarry = 0; // M = 1
|
||||
_carry = 0; // M = 1
|
||||
r = (bus & t);
|
||||
break;
|
||||
|
||||
case AluFunction.BusXorT:
|
||||
_lastCarry = 0; // M = 1
|
||||
_carry = 0; // M = 1
|
||||
r = (bus ^ t);
|
||||
break;
|
||||
|
||||
case AluFunction.BusPlus1:
|
||||
r = bus + 1;
|
||||
_lastCarry = (r > 0xffff) ? 1 : 0;
|
||||
_carry = (r > 0xffff) ? 1 : 0;
|
||||
break;
|
||||
|
||||
case AluFunction.BusMinus1:
|
||||
r = bus - 1;
|
||||
_lastCarry = (r < 0) ? 1 : 0;
|
||||
_carry = (r < 0) ? 1 : 0;
|
||||
break;
|
||||
|
||||
case AluFunction.BusPlusT:
|
||||
r = bus + t;
|
||||
_lastCarry = (r > 0xffff) ? 1 : 0;
|
||||
_carry = (r > 0xffff) ? 1 : 0;
|
||||
break;
|
||||
|
||||
case AluFunction.BusMinusT:
|
||||
r = bus - t;
|
||||
_lastCarry = (r < 0) ? 1 : 0;
|
||||
_carry = (r < 0) ? 1 : 0;
|
||||
break;
|
||||
|
||||
case AluFunction.BusMinusTMinus1:
|
||||
r = bus - t - 1;
|
||||
_lastCarry = (r < 0) ? 1 : 0;
|
||||
_carry = (r < 0) ? 1 : 0;
|
||||
break;
|
||||
|
||||
case AluFunction.BusPlusTPlus1:
|
||||
r = bus + t + 1;
|
||||
_lastCarry = (r > 0xffff) ? 1 : 0;
|
||||
_carry = (r > 0xffff) ? 1 : 0;
|
||||
break;
|
||||
|
||||
case AluFunction.BusPlusSkip:
|
||||
@ -88,7 +88,7 @@ namespace Contralto.CPU
|
||||
|
||||
case AluFunction.BusAndNotT:
|
||||
r = bus & (~t);
|
||||
_lastCarry = 0;
|
||||
_carry = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -98,6 +98,6 @@ namespace Contralto.CPU
|
||||
return (ushort)r;
|
||||
}
|
||||
|
||||
private static int _lastCarry;
|
||||
private static int _carry;
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,8 +43,6 @@ namespace Contralto.CPU
|
||||
_currentTask = _nextTask;
|
||||
_nextTask = null;
|
||||
|
||||
// test
|
||||
_l = ConstantMemory.ConstantROM[0];
|
||||
}
|
||||
|
||||
public void ExecuteNext()
|
||||
@ -141,7 +139,20 @@ namespace Contralto.CPU
|
||||
ushort busData = 0; // from BUS
|
||||
ushort aluData = 0; // from ALU
|
||||
bool nextTask = false;
|
||||
ushort nextModifier = 0; // for branches (OR'd into NEXT field)
|
||||
ushort nextModifier = 0; // for branches (OR'd into NEXT field)
|
||||
|
||||
//
|
||||
// Wait for memory state machine if a memory operation is requested by this instruction and
|
||||
// the memory isn't ready yet.
|
||||
//
|
||||
if ((instruction.BS == BusSource.ReadMD ||
|
||||
instruction.F1 == SpecialFunction1.LoadMAR ||
|
||||
instruction.F2 == SpecialFunction2.StoreMD)
|
||||
&& !MemoryBus.Ready())
|
||||
{
|
||||
// Suspend operation for this cycle.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Select BUS data.
|
||||
if (instruction.F1 != SpecialFunction1.Constant &&
|
||||
@ -168,6 +179,7 @@ namespace Contralto.CPU
|
||||
break;
|
||||
|
||||
case BusSource.ReadMD:
|
||||
// TODO: wait for MD if not ready.
|
||||
busData = MemoryBus.ReadMD();
|
||||
break;
|
||||
|
||||
@ -301,7 +313,7 @@ namespace Contralto.CPU
|
||||
break;
|
||||
|
||||
case SpecialFunction2.StoreMD:
|
||||
MemoryBus.StoreMD(busData);
|
||||
MemoryBus.LoadMD(busData);
|
||||
break;
|
||||
|
||||
case SpecialFunction2.Constant:
|
||||
@ -345,7 +357,7 @@ namespace Contralto.CPU
|
||||
_cpu._l = aluData;
|
||||
|
||||
// Save ALUC0 for use in the next ALUCY special function.
|
||||
_cpu._aluC0 = ALU.Carry;
|
||||
_cpu._aluC0 = (ushort)ALU.Carry;
|
||||
}
|
||||
|
||||
// Do shifter
|
||||
|
||||
@ -6,6 +6,13 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Contralto.Memory
|
||||
{
|
||||
public enum MemoryOperation
|
||||
{
|
||||
LoadAddress,
|
||||
Read,
|
||||
Load
|
||||
}
|
||||
|
||||
public static class MemoryBus
|
||||
{
|
||||
static MemoryBus()
|
||||
@ -19,34 +26,65 @@ namespace Contralto.Memory
|
||||
|
||||
public static void Clock()
|
||||
{
|
||||
_memoryCycle++;
|
||||
if (_memoryOperationActive)
|
||||
{
|
||||
_memoryCycle++;
|
||||
|
||||
{
|
||||
switch (_memoryCycle)
|
||||
{
|
||||
case 3:
|
||||
// Buffered read of single word
|
||||
_memoryData = ReadFromBus(_memoryAddress);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
_memoryData2 = ReadFromBus(_memoryAddress ^ 1);
|
||||
// Buffered read of double-word
|
||||
_memoryData2 = ReadFromBus((ushort)(_memoryAddress ^ 1));
|
||||
break;
|
||||
|
||||
case 6:
|
||||
case 5:
|
||||
// End of memory operation
|
||||
_memoryOperationActive = false;
|
||||
_doubleWordStore = false;
|
||||
_memoryCycle = 0;
|
||||
_doubleWordStore = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Ready(MemoryOperation op)
|
||||
{
|
||||
if (_memoryOperationActive)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case MemoryOperation.LoadAddress:
|
||||
// Can't start a new Load operation until the current one is finished.
|
||||
return false;
|
||||
|
||||
case MemoryOperation.Read:
|
||||
// Read operations take place on cycles 5 and 6
|
||||
return _memoryCycle > 4;
|
||||
|
||||
case MemoryOperation.Load:
|
||||
// Write operations take place on cycles 3 and 4
|
||||
return _memoryCycle > 2;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException(String.Format("Unexpected memory operation {0}", op));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing running right now, we're ready for anything.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoadMAR(ushort address)
|
||||
{
|
||||
if (_memoryOperationActive)
|
||||
{
|
||||
// TODO: stall CPU
|
||||
// This should not happen; CPU should check whether the operation is possible using Ready and stall if not.
|
||||
throw new InvalidOperationException("Invalid LoadMAR request during active memory operation.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -69,17 +107,17 @@ namespace Contralto.Memory
|
||||
throw new InvalidOperationException("Unexpected microcode behavior -- ReadMD too soon after start of memory cycle.");
|
||||
case 3:
|
||||
case 4:
|
||||
// TODO: not ready yet; need to tell CPU to wait.
|
||||
|
||||
// This should not happen; CPU should check whether the operation is possible using Ready and stall if not.
|
||||
throw new InvalidOperationException("Invalid ReadMR request during cycle 3 or 4 of memory operation.");
|
||||
break;
|
||||
|
||||
case 5:
|
||||
// Single word read
|
||||
return _memoryData;
|
||||
|
||||
case 6: // TODO: rectify with timing (doubleword read extends cycle to 6)
|
||||
// Doubleword read:
|
||||
return _memoryData2;
|
||||
// ***
|
||||
// NB: Handler for double-word read (cycle 6) is in the "else" clause below; this is kind of a hack.
|
||||
// ***
|
||||
|
||||
default:
|
||||
// Invalid state.
|
||||
@ -88,8 +126,18 @@ namespace Contralto.Memory
|
||||
}
|
||||
else
|
||||
{
|
||||
// not running, just return last latched contents
|
||||
return _memoryData;
|
||||
// memory state machine not running, just return last latched contents.
|
||||
// ("Because the Alto II latches memory contents, it is possible to execute _MD anytime after
|
||||
// cycle 5 of a reference and obtain the results of the read operation")
|
||||
// If this is memory cycle 6 we will return the last half of the doubleword to complete a double-word read.
|
||||
if (_memoryCycle == 6)
|
||||
{
|
||||
return _memoryData2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _memoryData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,8 +151,7 @@ namespace Contralto.Memory
|
||||
case 2:
|
||||
case 5:
|
||||
// TODO: good microcode should never do this
|
||||
throw new InvalidOperationException("Unexpected microcode behavior -- LoadMD too soon after start of memory cycle.");
|
||||
break;
|
||||
throw new InvalidOperationException("Unexpected microcode behavior -- LoadMD during incorrect memory cycle.");
|
||||
|
||||
case 3:
|
||||
// Start of doubleword write:
|
||||
@ -113,13 +160,35 @@ namespace Contralto.Memory
|
||||
break;
|
||||
|
||||
case 4:
|
||||
WriteToBus(_doubleWordStore ? _memoryAddress ^ 1 : _memoryAddress, data);
|
||||
WriteToBus(_doubleWordStore ? (ushort)(_memoryAddress ^ 1) : _memoryAddress, data);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispatches reads to memory mapped hardware (RAM, I/O)
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
private static ushort ReadFromBus(ushort address)
|
||||
{
|
||||
// TODO: actually dispatch to I/O
|
||||
return _mem.Read(address);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispatches writes to memory mapped hardware (RAM, I/O
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
private static void WriteToBus(ushort address, ushort data)
|
||||
{
|
||||
_mem.Load(address, data);
|
||||
}
|
||||
|
||||
|
||||
private static Memory _mem;
|
||||
private static bool _memoryOperationActive;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user