diff --git a/Contralto/CPU/ALU.cs b/Contralto/CPU/ALU.cs
index 3db19f1..fac3b2b 100644
--- a/Contralto/CPU/ALU.cs
+++ b/Contralto/CPU/ALU.cs
@@ -6,7 +6,10 @@ using System.Threading.Tasks;
namespace Contralto.CPU
{
- // From Alto Hardware Manual, Section 2.1
+ //
+ // This implements the stripped-down version of the 74181 ALU
+ // that the Alto exposes to the microcode, and nothing more.
+ //
static class ALU
{
static ALU()
@@ -14,14 +17,87 @@ namespace Contralto.CPU
_lastCarry = 0;
}
-
-
- public static ushort Execute(AluFunction fn, ushort a, ushort b)
+ public int Carry
{
-
- return 0;
+ get { return _lastCarry; }
}
- private static ushort _lastCarry;
+ public static ushort Execute(AluFunction fn, ushort bus, ushort t)
+ {
+ int r = 0;
+ switch (fn)
+ {
+ case AluFunction.Bus:
+ _lastCarry = 0; // M = 1
+ r = bus;
+ break;
+
+ case AluFunction.T:
+ _lastCarry = 0; // M = 1
+ r= t;
+ break;
+
+ case AluFunction.BusOrT:
+ _lastCarry = 0; // M = 1
+ r = (bus | t);
+ break;
+
+ case AluFunction.BusAndT:
+ case AluFunction.AluBusAndT:
+ _lastCarry = 0; // M = 1
+ r = (bus & t);
+ break;
+
+ case AluFunction.BusXorT:
+ _lastCarry = 0; // M = 1
+ r = (bus ^ t);
+ break;
+
+ case AluFunction.BusPlus1:
+ r = bus + 1;
+ _lastCarry = (r > 0xffff) ? 1 : 0;
+ break;
+
+ case AluFunction.BusMinus1:
+ r = bus - 1;
+ _lastCarry = (r < 0) ? 1 : 0;
+ break;
+
+ case AluFunction.BusPlusT:
+ r = bus + t;
+ _lastCarry = (r > 0xffff) ? 1 : 0;
+ break;
+
+ case AluFunction.BusMinusT:
+ r = bus - t;
+ _lastCarry = (r < 0) ? 1 : 0;
+ break;
+
+ case AluFunction.BusMinusTMinus1:
+ r = bus - t - 1;
+ _lastCarry = (r < 0) ? 1 : 0;
+ break;
+
+ case AluFunction.BusPlusTPlus1:
+ r = bus + t + 1;
+ _lastCarry = (r > 0xffff) ? 1 : 0;
+ break;
+
+ case AluFunction.BusPlusSkip:
+ throw new NotImplementedException("SKIP?");
+
+ case AluFunction.BusAndNotT:
+ r = bus & (~t);
+ _lastCarry = 0;
+ break;
+
+ default:
+ throw new InvalidOperationException(String.Format("Unhandled ALU function {0}", fn));
+ }
+
+ return (ushort)r;
+ }
+
+ private static int _lastCarry;
}
}
diff --git a/Contralto/CPU/CPU.cs b/Contralto/CPU/CPU.cs
index 7dc8967..dfc8157 100644
--- a/Contralto/CPU/CPU.cs
+++ b/Contralto/CPU/CPU.cs
@@ -1,4 +1,5 @@
-using System;
+using Contralto.Memory;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -41,6 +42,9 @@ namespace Contralto.CPU
_currentTask = _nextTask;
_nextTask = null;
+
+ // test
+ _l = ConstantMemory.ConstantROM[0];
}
public void ExecuteNext()
@@ -80,7 +84,7 @@ namespace Contralto.CPU
// Base task class: provides implementation for non-task-specific microcode execution and
// state. Task subclasses implement and execute Task-specific behavior and are called into
// by the base class as necessary.
- private class Task
+ private abstract class Task
{
public Task(AltoCPU cpu)
{
@@ -164,7 +168,7 @@ namespace Contralto.CPU
break;
case BusSource.ReadMD:
- busData = Memory.MD;
+ busData = MemoryBus.ReadMD();
break;
case BusSource.ReadMouse:
@@ -215,7 +219,7 @@ namespace Contralto.CPU
break;
case SpecialFunction1.LoadMAR:
- Memory.LoadMAR(aluData); // Start main memory reference
+ MemoryBus.LoadMAR(aluData); // Start main memory reference
break;
case SpecialFunction1.Task:
@@ -297,7 +301,7 @@ namespace Contralto.CPU
break;
case SpecialFunction2.StoreMD:
- Memory.StoreMD(busData);
+ MemoryBus.StoreMD(busData);
break;
case SpecialFunction2.Constant:
@@ -307,6 +311,7 @@ namespace Contralto.CPU
default:
// Let the specific task implementation take a crack at this.
ExecuteSpecialFunction2((int)instruction.F1);
+ break;
}
//
diff --git a/Contralto/CPU/ConstantMemory.cs b/Contralto/CPU/ConstantMemory.cs
index 1de60cb..e96d046 100644
--- a/Contralto/CPU/ConstantMemory.cs
+++ b/Contralto/CPU/ConstantMemory.cs
@@ -49,18 +49,52 @@ namespace Contralto.CPU
// OR in the data
for (int i = 0; i < length; i++)
{
- _constantRom[file.StartingAddress + i] |= (ushort)((data[AddressMap(i)] & 0xf) << file.BitPosition);
+ _constantRom[file.StartingAddress + i] |= (ushort)((DataMap(data[AddressMap(i)]) & 0xf) << file.BitPosition);
}
}
}
+
+ // And invert all bits
+ for (int i = 0; i < _constantRom.Length; i++)
+ {
+ _constantRom[i] = (ushort)((~_constantRom[i]) & 0xffff);
+ }
}
private static int AddressMap(int address)
- {
- int mappedAddress = (~address) & 0xff;
+ {
+ // Descramble the address bits as they are in no sane order.
+ // (See 05a_AIM.pdf, pg. 5 (Page 9 of the orginal docs))
+ int[] addressMapping = { 7, 2, 1, 0, 3, 4, 5, 6 };
+
+ int mappedAddress = 0;
+
+ for (int i = 0; i < addressMapping.Length; i++)
+ {
+ if ((address & (1 << i)) != 0)
+ {
+ mappedAddress |= (1 << (addressMapping[i]));
+ }
+ }
return mappedAddress;
}
+ private static int DataMap(int data)
+ {
+ // Reverse bits 0-4.
+ int mappedData = 0;
+
+ for (int i = 0; i < 4; i++)
+ {
+ if ((data & (1 << i)) != 0)
+ {
+ mappedData |= (1 << (3-i));
+ }
+ }
+
+ return mappedData;
+ }
+
private static RomFile[] _constantRoms =
{
new RomFile("c0", 0x000, 12),
@@ -69,6 +103,6 @@ namespace Contralto.CPU
new RomFile("c3", 0x000, 0),
};
- private static UInt16[] _constantRom;
+ private static ushort[] _constantRom;
}
}
diff --git a/Contralto/CPU/MicroInstruction.cs b/Contralto/CPU/MicroInstruction.cs
index ca284fb..9f61efc 100644
--- a/Contralto/CPU/MicroInstruction.cs
+++ b/Contralto/CPU/MicroInstruction.cs
@@ -49,20 +49,21 @@ namespace Contralto.CPU
public enum AluFunction
{
Bus = 0,
- BusOrT = 1,
- BusAndT = 2,
- BusXorT = 3,
- BusPlus1 = 4,
- BusMinus1 = 5,
- BusPlusT = 6,
- BusMinusT = 7,
- BusMinusTMinus1 = 8,
- BusPlusTPlus1 = 9,
- BusPlusSkip = 10,
- AluBusAndT = 11,
- BusAndNotT = 12,
- Undefined1 = 13,
- Undefined2 = 14,
+ T = 1,
+ BusOrT = 2,
+ BusAndT = 3,
+ BusXorT = 4,
+ BusPlus1 = 5,
+ BusMinus1 = 6,
+ BusPlusT = 7,
+ BusMinusT = 8 ,
+ BusMinusTMinus1 = 9,
+ BusPlusTPlus1 = 10,
+ BusPlusSkip = 11,
+ AluBusAndT = 12,
+ BusAndNotT = 13,
+ Undefined1 = 14,
+ Undefined2 = 15,
}
public class MicroInstruction
diff --git a/Contralto/Contralto.csproj b/Contralto/Contralto.csproj
index 006ea30..6a03537 100644
--- a/Contralto/Contralto.csproj
+++ b/Contralto/Contralto.csproj
@@ -47,22 +47,25 @@
+
+
+
- PreserveNewest
+ Always
- PreserveNewest
+ Always
+
+
+ Always
- PreserveNewest
-
-
- PreserveNewest
+ Always
PreserveNewest
diff --git a/Contralto/Memory/IMemoryMappedDevice.cs b/Contralto/Memory/IMemoryMappedDevice.cs
new file mode 100644
index 0000000..4c67253
--- /dev/null
+++ b/Contralto/Memory/IMemoryMappedDevice.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Contralto.Memory
+{
+ public interface IMemoryMappedDevice
+ {
+ ushort Read(int address);
+
+ void Load(int address, ushort data);
+ }
+}
diff --git a/Contralto/Memory/Memory.cs b/Contralto/Memory/Memory.cs
new file mode 100644
index 0000000..e643195
--- /dev/null
+++ b/Contralto/Memory/Memory.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Contralto.Memory
+{
+ public class Memory : IMemoryMappedDevice
+ {
+ public Memory()
+ {
+ _mem = new ushort[0xffff];
+ }
+
+ public ushort Read(int address)
+ {
+ return _mem[address];
+ }
+
+ public void Load(int address, ushort data)
+ {
+ _mem[address] = data;
+ }
+
+ private ushort[] _mem;
+ }
+}
diff --git a/Contralto/Memory/MemoryBus.cs b/Contralto/Memory/MemoryBus.cs
new file mode 100644
index 0000000..134e299
--- /dev/null
+++ b/Contralto/Memory/MemoryBus.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Contralto.Memory
+{
+ public static class MemoryBus
+ {
+ static MemoryBus()
+ {
+ _mem = new Memory();
+ _memoryCycle = 0;
+ _memoryAddress = 0;
+ _memoryData = 0;
+ _memoryOperationActive = false;
+ }
+
+ public static void Clock()
+ {
+ if (_memoryOperationActive)
+ {
+ _memoryCycle++;
+
+ switch (_memoryCycle)
+ {
+ case 3:
+ _memoryData = ReadFromBus(_memoryAddress);
+ break;
+
+ case 4:
+ _memoryData2 = ReadFromBus(_memoryAddress ^ 1);
+ break;
+
+ case 6:
+ _memoryOperationActive = false;
+ _doubleWordStore = false;
+ _memoryCycle = 0;
+ break;
+ }
+ }
+ }
+
+ public static void LoadMAR(ushort address)
+ {
+ if (_memoryOperationActive)
+ {
+ // TODO: stall CPU
+ }
+ else
+ {
+ _memoryOperationActive = true;
+ _doubleWordStore = false;
+ _memoryAddress = address;
+ _memoryCycle = 1;
+ }
+ }
+
+ public static ushort ReadMD()
+ {
+ if (_memoryOperationActive)
+ {
+ switch (_memoryCycle)
+ {
+ case 1:
+ case 2:
+ // TODO: good microcode should never do this
+ 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.
+
+ break;
+
+ case 5:
+ // Single word read
+ return _memoryData;
+
+ case 6: // TODO: rectify with timing (doubleword read extends cycle to 6)
+ // Doubleword read:
+ return _memoryData2;
+
+ default:
+ // Invalid state.
+ throw new InvalidOperationException(string.Format("Unexpected memory cycle {0} in memory state machine.", _memoryCycle));
+ }
+ }
+ else
+ {
+ // not running, just return last latched contents
+ return _memoryData;
+ }
+ }
+
+ public static void LoadMD(ushort data)
+ {
+ if (_memoryOperationActive)
+ {
+ switch (_memoryCycle)
+ {
+ case 1:
+ 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;
+
+ case 3:
+ // Start of doubleword write:
+ WriteToBus(_memoryAddress, data);
+ _doubleWordStore = true;
+ break;
+
+ case 4:
+ WriteToBus(_doubleWordStore ? _memoryAddress ^ 1 : _memoryAddress, data);
+ break;
+ }
+
+ }
+ }
+
+
+ private static Memory _mem;
+ private static bool _memoryOperationActive;
+ private static int _memoryCycle;
+ private static ushort _memoryAddress;
+
+ // Buffered read data (on cycles 3 and 4)
+ private static ushort _memoryData;
+ private static ushort _memoryData2;
+
+ // Indicates a double-word store (started on cycle 3)
+ private static bool _doubleWordStore;
+ }
+}
diff --git a/Contralto/Program.cs b/Contralto/Program.cs
index 483af07..1ccebbc 100644
--- a/Contralto/Program.cs
+++ b/Contralto/Program.cs
@@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks;
using Contralto.CPU;
+using Contralto.Memory;
namespace Contralto
{
@@ -16,6 +17,7 @@ namespace Contralto
while(true)
{
+ MemoryBus.Clock();
cpu.ExecuteNext();
}
diff --git a/Contralto/ROM/C2 b/Contralto/ROM/C2
new file mode 100644
index 0000000..68e488e
Binary files /dev/null and b/Contralto/ROM/C2 differ
diff --git a/Contralto/ROM/C3 b/Contralto/ROM/C3
index 68e488e..9c5cc18 100644
Binary files a/Contralto/ROM/C3 and b/Contralto/ROM/C3 differ
diff --git a/Contralto/ROM/C4 b/Contralto/ROM/C4
deleted file mode 100644
index 9c5cc18..0000000
Binary files a/Contralto/ROM/C4 and /dev/null differ