mirror of
https://github.com/livingcomputermuseum/ContrAlto.git
synced 2026-01-19 01:18:00 +00:00
Implemented ALU, most of Memory state machine.
This commit is contained in:
parent
5719ec4815
commit
f1ffcb0547
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -47,22 +47,25 @@
|
||||
<Compile Include="CPU\MicroInstruction.cs" />
|
||||
<Compile Include="CPU\Shifter.cs" />
|
||||
<Compile Include="CPU\UCodeMemory.cs" />
|
||||
<Compile Include="Memory\IMemoryMappedDevice.cs" />
|
||||
<Compile Include="Memory\Memory.cs" />
|
||||
<Compile Include="Memory\MemoryBus.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="ROM\C0">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="ROM\C1">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="ROM\C2">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="ROM\C3">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="ROM\C4">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="ROM\U52">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
||||
15
Contralto/Memory/IMemoryMappedDevice.cs
Normal file
15
Contralto/Memory/IMemoryMappedDevice.cs
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
28
Contralto/Memory/Memory.cs
Normal file
28
Contralto/Memory/Memory.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
136
Contralto/Memory/MemoryBus.cs
Normal file
136
Contralto/Memory/MemoryBus.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
BIN
Contralto/ROM/C2
Normal file
BIN
Contralto/ROM/C2
Normal file
Binary file not shown.
BIN
Contralto/ROM/C3
BIN
Contralto/ROM/C3
Binary file not shown.
BIN
Contralto/ROM/C4
BIN
Contralto/ROM/C4
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user