diff --git a/Contralto/CPU/ALU.cs b/Contralto/CPU/ALU.cs
index fac3b2b..deceb0f 100644
--- a/Contralto/CPU/ALU.cs
+++ b/Contralto/CPU/ALU.cs
@@ -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;
}
}
diff --git a/Contralto/CPU/CPU.cs b/Contralto/CPU/CPU.cs
index dfc8157..a4fa88f 100644
--- a/Contralto/CPU/CPU.cs
+++ b/Contralto/CPU/CPU.cs
@@ -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
diff --git a/Contralto/Memory/MemoryBus.cs b/Contralto/Memory/MemoryBus.cs
index 134e299..8664e3b 100644
--- a/Contralto/Memory/MemoryBus.cs
+++ b/Contralto/Memory/MemoryBus.cs
@@ -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;
}
}
}
+ ///
+ /// Dispatches reads to memory mapped hardware (RAM, I/O)
+ ///
+ ///
+ ///
+ private static ushort ReadFromBus(ushort address)
+ {
+ // TODO: actually dispatch to I/O
+ return _mem.Read(address);
+ }
+
+ ///
+ /// Dispatches writes to memory mapped hardware (RAM, I/O
+ ///
+ ///
+ ///
+ ///
+ private static void WriteToBus(ushort address, ushort data)
+ {
+ _mem.Load(address, data);
+ }
+
private static Memory _mem;
private static bool _memoryOperationActive;