1
0
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:
Josh Dersch 2015-08-20 18:02:01 -07:00
parent 5719ec4815
commit f1ffcb0547
12 changed files with 336 additions and 36 deletions

View File

@ -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;
}
}

View File

@ -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;
}
//

View File

@ -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;
}
}

View File

@ -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

View File

@ -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>

View 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);
}
}

View 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;
}
}

View 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;
}
}

View File

@ -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

Binary file not shown.

Binary file not shown.

Binary file not shown.