diff --git a/Contralto/AltoSystem.cs b/Contralto/AltoSystem.cs
new file mode 100644
index 0000000..782740d
--- /dev/null
+++ b/Contralto/AltoSystem.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Contralto.CPU;
+using Contralto.Memory;
+
+namespace Contralto
+{
+ ///
+ /// Encapsulates all Alto hardware; represents a complete Alto system.
+ /// Provides interfaces for controlling and debugging the system externally.
+ ///
+ public class AltoSystem
+ {
+ public AltoSystem()
+ {
+ _cpu = new AltoCPU(this);
+ _mem = new MemoryBus();
+ Reset();
+ }
+
+ public void Reset()
+ {
+ _cpu.Reset();
+ _mem.Reset();
+ }
+
+ public void SingleStep()
+ {
+ _mem.Clock();
+ _cpu.ExecuteNext();
+ }
+
+ public AltoCPU CPU
+ {
+ get { return _cpu; }
+ }
+
+ public MemoryBus MemoryBus
+ {
+ get { return _mem; }
+ }
+
+ private AltoCPU _cpu;
+ private MemoryBus _mem;
+ }
+}
diff --git a/Contralto/CPU/CPU.cs b/Contralto/CPU/CPU.cs
index dafc92e..dcbde12 100644
--- a/Contralto/CPU/CPU.cs
+++ b/Contralto/CPU/CPU.cs
@@ -9,25 +9,76 @@ namespace Contralto.CPU
{
public enum TaskType
{
+ Invalid = -1,
Emulator = 0,
DiskSector = 4,
- Ethernet = 5,
- DiskWord = 9,
+ Ethernet = 7,
+ MemoryRefresh = 8,
+ DisplayWord = 9,
Cursor = 10,
DisplayHorizontal = 11,
DisplayVertical = 12,
- Refresh = 14,
+ Parity = 13,
+ DiskWord = 14,
}
public class AltoCPU
{
- public AltoCPU()
+ public AltoCPU(AltoSystem system)
{
+ _system = system;
+
_tasks[(int)TaskType.Emulator] = new EmulatorTask(this);
Reset();
}
+ public Task[] Tasks
+ {
+ get { return _tasks; }
+ }
+
+ public Task CurrentTask
+ {
+ get { return _currentTask; }
+ }
+
+ public ushort[] R
+ {
+ get { return _r; }
+ }
+
+ public ushort[][] S
+ {
+ get { return _s; }
+ }
+
+ public ushort T
+ {
+ get { return _t; }
+ }
+
+ public ushort L
+ {
+ get { return _l; }
+ }
+
+ public ushort M
+ {
+ get { return _m; }
+ }
+
+ public ushort IR
+ {
+ get { return _ir; }
+ }
+
+ public ushort ALUC0
+ {
+ get { return _aluC0; }
+ }
+
+
public void Reset()
{
// Reset registers
@@ -126,7 +177,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 abstract class Task
+ public abstract class Task
{
public Task(AltoCPU cpu)
{
@@ -146,6 +197,11 @@ namespace Contralto.CPU
get { return _wakeup; }
}
+ public ushort MPC
+ {
+ get { return _mpc; }
+ }
+
public virtual void Reset()
{
// From The Alto Hardware Manual (section 2, "Initialization"):
@@ -183,6 +239,7 @@ namespace Contralto.CPU
bool nextTask = false;
bool loadR = false;
ushort aluData = 0;
+ ushort nextModifier = 0;
_loadS = false;
_rSelect = 0;
_busData = 0;
@@ -193,16 +250,39 @@ namespace Contralto.CPU
//
// Wait for memory state machine if a memory operation is requested by this instruction and
// the memory isn't ready yet.
+ // TODO: this needs to be seriously cleaned up.
//
- if ((instruction.BS == BusSource.ReadMD ||
+ if (instruction.BS == BusSource.ReadMD ||
instruction.F1 == SpecialFunction1.LoadMAR ||
- instruction.F2 == SpecialFunction2.StoreMD)
- && !MemoryBus.Ready(MemoryOperation.Load)) //TODO: fix
+ instruction.F2 == SpecialFunction2.StoreMD)
{
- // Suspend operation for this cycle.
- return false;
+
+ MemoryOperation op;
+
+ if (instruction.BS == BusSource.ReadMD)
+ {
+ op = MemoryOperation.Read;
+ }
+ else if(instruction.F1 == SpecialFunction1.LoadMAR)
+ {
+ op = MemoryOperation.LoadAddress;
+ }
+ else
+ {
+ op = MemoryOperation.Store;
+ }
+
+ if (!_cpu._system.MemoryBus.Ready(op))
+ {
+ // Suspend operation for this cycle.
+ return false;
+ }
}
+ // If we have a modified next field from the last instruction, make sure it gets applied to this one.
+ nextModifier = _nextModifier;
+ _nextModifier = 0;
+
_rSelect = instruction.RSELECT;
// Give tasks the chance to modify parameters early on (like RSELECT)
@@ -234,17 +314,31 @@ namespace Contralto.CPU
break;
case BusSource.ReadMD:
- _busData = MemoryBus.ReadMD();
+ _busData = _cpu._system.MemoryBus.ReadMD();
break;
case BusSource.ReadMouse:
- throw new NotImplementedException("ReadMouse bus source not implemented.");
- _busData = 0; // TODO: implement
+ //throw new NotImplementedException("ReadMouse bus source not implemented.");
+ _busData = 0; // TODO: implement;
break;
case BusSource.ReadDisp:
- throw new NotImplementedException("ReadDisp bus source not implemented.");
- _busData = 0; // TODO: implement;
+ // "The high-order bits of IR cannot be read directly, but the displacement field of IR (8 low order bits),
+ // may be read with the <-DISP bus source. If the X field of the instruction is zero (i.e. it specifies page 0
+ // addressing) then the DISP field of the instruction is put on BUS[8-15] and BUS[0-7] is zeroed. If the X
+ // field of the instruction is nonzero (i.e. it specifies PC-relative or base-register addressing) then the DISP
+ // field is sign-extended and put on the bus."
+ // NB: the "X" field of the NOVA instruction is IR[6-7]
+ _busData = (ushort)(_cpu._ir & 0xff);
+
+ if ((_cpu._ir & 0x300) != 0)
+ {
+ // sign extend if necessary
+ if ((_cpu._ir & 0x80) == 0x80)
+ {
+ _busData |= (0xff00);
+ }
+ }
break;
default:
@@ -291,7 +385,7 @@ namespace Contralto.CPU
break;
case SpecialFunction1.LoadMAR:
- MemoryBus.LoadMAR(aluData); // Start main memory reference
+ _cpu._system.MemoryBus.LoadMAR(aluData); // Start main memory reference
break;
case SpecialFunction1.Task:
@@ -373,7 +467,7 @@ namespace Contralto.CPU
break;
case SpecialFunction2.StoreMD:
- MemoryBus.LoadMD(_busData);
+ _cpu._system.MemoryBus.LoadMD(_busData);
break;
case SpecialFunction2.Constant:
@@ -382,7 +476,7 @@ namespace Contralto.CPU
default:
// Let the specific task implementation take a crack at this.
- ExecuteSpecialFunction2((int)instruction.F1);
+ ExecuteSpecialFunction2((int)instruction.F2);
break;
}
@@ -434,9 +528,9 @@ namespace Contralto.CPU
}
//
- // Select next address -- TODO: this is incorrect! _nextModifer should be applied to the *NEXT* instruction, not the current one!
+ // Select next address, using the address modifier from the last instruction.
//
- _mpc = (ushort)(instruction.NEXT | _nextModifier);
+ _mpc = (ushort)(instruction.NEXT | nextModifier);
return nextTask;
}
@@ -743,5 +837,8 @@ namespace Contralto.CPU
private long _clocks;
+ // The system this CPU belongs to
+ private AltoSystem _system;
+
}
}
diff --git a/Contralto/Contralto.csproj b/Contralto/Contralto.csproj
index f4792ef..c4710ec 100644
--- a/Contralto/Contralto.csproj
+++ b/Contralto/Contralto.csproj
@@ -34,6 +34,8 @@
+
+
@@ -41,6 +43,7 @@
+
@@ -48,6 +51,12 @@
+
+ Form
+
+
+ Debugger.cs
+
@@ -170,6 +179,11 @@
PreserveNewest
+
+
+ Debugger.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
\ No newline at end of file
diff --git a/Contralto/Memory/Memory.cs b/Contralto/Memory/Memory.cs
index e643195..c01d535 100644
--- a/Contralto/Memory/Memory.cs
+++ b/Contralto/Memory/Memory.cs
@@ -10,7 +10,7 @@ namespace Contralto.Memory
{
public Memory()
{
- _mem = new ushort[0xffff];
+ _mem = new ushort[0x10000];
}
public ushort Read(int address)
diff --git a/Contralto/Memory/MemoryBus.cs b/Contralto/Memory/MemoryBus.cs
index 8664e3b..70b7d30 100644
--- a/Contralto/Memory/MemoryBus.cs
+++ b/Contralto/Memory/MemoryBus.cs
@@ -10,21 +10,46 @@ namespace Contralto.Memory
{
LoadAddress,
Read,
- Load
+ Store
}
- public static class MemoryBus
+ public class MemoryBus
{
- static MemoryBus()
+ public MemoryBus()
{
_mem = new Memory();
+ Reset();
+ }
+
+ public void Reset()
+ {
_memoryCycle = 0;
_memoryAddress = 0;
_memoryData = 0;
_memoryOperationActive = false;
}
- public static void Clock()
+ public ushort MAR
+ {
+ get { return _memoryAddress; }
+ }
+
+ public ushort MD
+ {
+ get { return _memoryData; }
+ }
+
+ public int Cycle
+ {
+ get { return _memoryCycle; }
+ }
+
+ public bool Active
+ {
+ get { return _memoryOperationActive; }
+ }
+
+ public void Clock()
{
_memoryCycle++;
if (_memoryOperationActive)
@@ -50,7 +75,7 @@ namespace Contralto.Memory
}
}
- public static bool Ready(MemoryOperation op)
+ public bool Ready(MemoryOperation op)
{
if (_memoryOperationActive)
{
@@ -64,7 +89,7 @@ namespace Contralto.Memory
// Read operations take place on cycles 5 and 6
return _memoryCycle > 4;
- case MemoryOperation.Load:
+ case MemoryOperation.Store:
// Write operations take place on cycles 3 and 4
return _memoryCycle > 2;
@@ -79,7 +104,7 @@ namespace Contralto.Memory
}
}
- public static void LoadMAR(ushort address)
+ public void LoadMAR(ushort address)
{
if (_memoryOperationActive)
{
@@ -95,7 +120,7 @@ namespace Contralto.Memory
}
}
- public static ushort ReadMD()
+ public ushort ReadMD()
{
if (_memoryOperationActive)
{
@@ -141,7 +166,7 @@ namespace Contralto.Memory
}
}
- public static void LoadMD(ushort data)
+ public void LoadMD(ushort data)
{
if (_memoryOperationActive)
{
@@ -154,12 +179,14 @@ namespace Contralto.Memory
throw new InvalidOperationException("Unexpected microcode behavior -- LoadMD during incorrect memory cycle.");
case 3:
+ _memoryData = data; // Only really necessary to show in debugger
// Start of doubleword write:
WriteToBus(_memoryAddress, data);
_doubleWordStore = true;
break;
- case 4:
+ case 4:
+ _memoryData = data; // Only really necessary to show in debugger
WriteToBus(_doubleWordStore ? (ushort)(_memoryAddress ^ 1) : _memoryAddress, data);
break;
}
@@ -172,7 +199,7 @@ namespace Contralto.Memory
///
///
///
- private static ushort ReadFromBus(ushort address)
+ private ushort ReadFromBus(ushort address)
{
// TODO: actually dispatch to I/O
return _mem.Read(address);
@@ -184,22 +211,22 @@ namespace Contralto.Memory
///
///
///
- private static void WriteToBus(ushort address, ushort data)
+ private void WriteToBus(ushort address, ushort data)
{
_mem.Load(address, data);
}
- private static Memory _mem;
- private static bool _memoryOperationActive;
- private static int _memoryCycle;
- private static ushort _memoryAddress;
+ private Memory _mem;
+ private bool _memoryOperationActive;
+ private int _memoryCycle;
+ private ushort _memoryAddress;
// Buffered read data (on cycles 3 and 4)
- private static ushort _memoryData;
- private static ushort _memoryData2;
+ private ushort _memoryData;
+ private ushort _memoryData2;
// Indicates a double-word store (started on cycle 3)
- private static bool _doubleWordStore;
+ private bool _doubleWordStore;
}
}
diff --git a/Contralto/OctalHelpers.cs b/Contralto/OctalHelpers.cs
index 0abf7c0..34b8e9f 100644
--- a/Contralto/OctalHelpers.cs
+++ b/Contralto/OctalHelpers.cs
@@ -12,5 +12,11 @@ namespace Contralto
{
return Convert.ToString(i, 8);
}
+
+ public static string ToOctal(int i, int digits)
+ {
+ string octalString = Convert.ToString(i, 8);
+ return new String('0', digits - octalString.Length) + octalString;
+ }
}
}
diff --git a/Contralto/Program.cs b/Contralto/Program.cs
index 913182b..646d01b 100644
--- a/Contralto/Program.cs
+++ b/Contralto/Program.cs
@@ -13,20 +13,13 @@ namespace Contralto
{
static void Main(string[] args)
{
- AltoCPU cpu = new AltoCPU();
- for(int i=0;i<2048;i++)
- {
- MicroInstruction inst = new MicroInstruction(UCodeMemory.UCodeROM[i]);
+ AltoSystem system = new AltoSystem();
- Console.WriteLine("{0}: {1}", OctalHelpers.ToOctal(i), Disassembler.DisassembleInstruction(inst, TaskType.Emulator));
- }
-
- while(true)
- {
- MemoryBus.Clock();
- cpu.ExecuteNext();
- }
+ // for now everything is driven through the debugger
+ Debugger d = new Debugger(system);
+ d.LoadSourceCode("Disassembly\\altoIIcode3.mu");
+ d.ShowDialog();
}
}