mirror of
https://github.com/livingcomputermuseum/ContrAlto.git
synced 2026-05-05 07:24:36 +00:00
Implemented more Disk functionality, fixed bug in ACSOURCE dispatch in Emulator task.
This commit is contained in:
@@ -22,7 +22,7 @@ namespace Contralto.CPU
|
||||
DiskWord = 14,
|
||||
}
|
||||
|
||||
public partial class AltoCPU
|
||||
public partial class AltoCPU : IClockable
|
||||
{
|
||||
public AltoCPU(AltoSystem system)
|
||||
{
|
||||
@@ -115,25 +115,9 @@ namespace Contralto.CPU
|
||||
|
||||
}
|
||||
|
||||
public void ExecuteNext()
|
||||
public void Clock()
|
||||
{
|
||||
if (_currentTask.ExecuteNext())
|
||||
{
|
||||
// Invoke the task switch, this will take effect after
|
||||
// the NEXT instruction, not this one.
|
||||
TaskSwitch();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we have a new task, switch to it now.
|
||||
if (_nextTask != null)
|
||||
{
|
||||
_currentTask = _nextTask;
|
||||
_nextTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
_clocks++;
|
||||
ExecuteNext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -162,6 +146,27 @@ namespace Contralto.CPU
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteNext()
|
||||
{
|
||||
if (_currentTask.ExecuteNext())
|
||||
{
|
||||
// Invoke the task switch, this will take effect after
|
||||
// the NEXT instruction, not this one.
|
||||
TaskSwitch();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we have a new task, switch to it now.
|
||||
if (_nextTask != null)
|
||||
{
|
||||
_currentTask = _nextTask;
|
||||
_nextTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
_clocks++;
|
||||
}
|
||||
|
||||
private void TaskSwitch()
|
||||
{
|
||||
// Select the highest-priority eligible task
|
||||
|
||||
@@ -7,9 +7,9 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Contralto.CPU
|
||||
{
|
||||
static class ConstantMemory
|
||||
static class ControlROM
|
||||
{
|
||||
static ConstantMemory()
|
||||
static ControlROM()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
@@ -17,6 +17,7 @@ namespace Contralto.CPU
|
||||
private static void Init()
|
||||
{
|
||||
LoadConstants(_constantRoms);
|
||||
LoadACSource(_acSourceRoms);
|
||||
}
|
||||
|
||||
public static ushort[] ConstantROM
|
||||
@@ -24,6 +25,11 @@ namespace Contralto.CPU
|
||||
get { return _constantRom; }
|
||||
}
|
||||
|
||||
public static byte[] ACSourceROM
|
||||
{
|
||||
get { return _acSourceRom; }
|
||||
}
|
||||
|
||||
private static void LoadConstants(RomFile[] romInfo)
|
||||
{
|
||||
_constantRom = new ushort[256];
|
||||
@@ -47,7 +53,7 @@ namespace Contralto.CPU
|
||||
// OR in the data
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
_constantRom[file.StartingAddress + i] |= (ushort)((DataMap(data[AddressMap(i)]) & 0xf) << file.BitPosition);
|
||||
_constantRom[file.StartingAddress + i] |= (ushort)((DataMapConstantRom(data[AddressMapConstantRom(i)]) & 0xf) << file.BitPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,7 +65,29 @@ namespace Contralto.CPU
|
||||
}
|
||||
}
|
||||
|
||||
private static int AddressMap(int address)
|
||||
private static void LoadACSource(RomFile romInfo)
|
||||
{
|
||||
_acSourceRom = new byte[256];
|
||||
|
||||
using (FileStream fs = new FileStream(Path.Combine("ROM", romInfo.Filename), FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
int length = (int)fs.Length;
|
||||
if (length != 256)
|
||||
{
|
||||
throw new InvalidOperationException("ROM file should be 256 bytes in length");
|
||||
}
|
||||
byte[] data = new byte[fs.Length];
|
||||
fs.Read(data, 0, (int)fs.Length);
|
||||
|
||||
// Copy in the data, modifying the address as required.
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
_acSourceRom[i] = (byte)((~data[AddressMapACSourceRom(i)]) & 0xf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int AddressMapConstantRom(int address)
|
||||
{
|
||||
// Descramble the address bits as they are in no sane order.
|
||||
// (See 05a_AIM.pdf, pg. 5 (Page 9 of the orginal docs))
|
||||
@@ -77,7 +105,7 @@ namespace Contralto.CPU
|
||||
return mappedAddress;
|
||||
}
|
||||
|
||||
private static int DataMap(int data)
|
||||
private static int DataMapConstantRom(int data)
|
||||
{
|
||||
// Reverse bits 0-4.
|
||||
int mappedData = 0;
|
||||
@@ -93,6 +121,23 @@ namespace Contralto.CPU
|
||||
return mappedData;
|
||||
}
|
||||
|
||||
private static int AddressMapACSourceRom(int data)
|
||||
{
|
||||
// Reverse bits 0-7.
|
||||
int mappedData = 0;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if ((data & (1 << i)) != 0)
|
||||
{
|
||||
mappedData |= (1 << (7 - i));
|
||||
}
|
||||
}
|
||||
|
||||
// And invert.
|
||||
return (~mappedData) & 0xff;
|
||||
}
|
||||
|
||||
private static RomFile[] _constantRoms =
|
||||
{
|
||||
new RomFile("c0", 0x000, 12),
|
||||
@@ -101,6 +146,9 @@ namespace Contralto.CPU
|
||||
new RomFile("c3", 0x000, 0),
|
||||
};
|
||||
|
||||
private static RomFile _acSourceRoms = new RomFile("2kctl.u3", 0x000, 0);
|
||||
|
||||
private static ushort[] _constantRom;
|
||||
private static byte[] _acSourceRom;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace Contralto.CPU
|
||||
instruction.F2 == SpecialFunction2.Constant)
|
||||
{
|
||||
source += String.Format("C({0})",
|
||||
OctalHelpers.ToOctal(ConstantMemory.ConstantROM[(instruction.RSELECT << 3) | ((uint)instruction.BS)]));
|
||||
OctalHelpers.ToOctal(ControlROM.ConstantROM[(instruction.RSELECT << 3) | ((uint)instruction.BS)]));
|
||||
}
|
||||
|
||||
switch (instruction.ALUF)
|
||||
|
||||
@@ -96,7 +96,75 @@ namespace Contralto.CPU
|
||||
case DiskF2.INIT:
|
||||
// "NEXT<-NEXT OR (if WDTASKACT AND WDINIT) then 37B else 0
|
||||
// TODO: figure out how WDTASKACT and WDINIT work.
|
||||
throw new NotImplementedException("INIT not implemented.");
|
||||
|
||||
// From the US Patent (4148098):
|
||||
// "..two multiplexers...allow the setting of the next field bits NEXT(05)-NEXT(09)
|
||||
// to 1 after an error condition is detected and as soon as the word task active signal
|
||||
// WDTASKACT is generated..."
|
||||
|
||||
// Is this always an error condition?
|
||||
Console.WriteLine("Warning: assuming 0 for Disk F2 INIT (unimplemented stub)");
|
||||
break;
|
||||
|
||||
|
||||
case DiskF2.RWC:
|
||||
// "NEXT<-NEXT OR (IF current record to be written THEN 3 ELSE IF
|
||||
// current record to be checked THEN 2 ELSE 0.")
|
||||
// Current record is in bits 8-9 of the command register; this is shifted
|
||||
// by INCREC by the microcode to present the next set of bits.
|
||||
int command = (_cpu._system.DiskController.KADR & 0x00c0) >> 6;
|
||||
|
||||
switch(command)
|
||||
{
|
||||
case 0:
|
||||
// read, no modification.
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// check, OR in 2
|
||||
_nextModifier |= 0x2;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
// write, OR in 3
|
||||
_nextModifier |= 0x3;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DiskF2.XFRDAT:
|
||||
// "NEXT <- NEXT OR (IF current command wants data transfer THEN 1 ELSE 0)
|
||||
// TODO: need to get unshifted bit 14 of the command register. Disk controller should
|
||||
// save this off somewhere.
|
||||
if (_cpu._system.DiskController.DataXfer)
|
||||
{
|
||||
_nextModifier |= 0x1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DiskF2.RECNO:
|
||||
_nextModifier |= _cpu._system.DiskController.RECNO;
|
||||
break;
|
||||
|
||||
case DiskF2.NFER:
|
||||
// "NEXT <- NEXT OR (IF fatal error in latches THEN 0 ELSE 1)"
|
||||
// We assume success for now...
|
||||
_nextModifier |= 0x1;
|
||||
break;
|
||||
|
||||
case DiskF2.STROBON:
|
||||
// "NEXT <- NEXT OR (IF seek strobe still on THEN 1 ELSE 0)"
|
||||
if ((_cpu._system.DiskController.KSTAT & 0x0040) == 0x0040)
|
||||
{
|
||||
_nextModifier |= 0x1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DiskF2.SWRNRDY:
|
||||
// "NEXT <- NEXT OR (IF disk not ready to accept command THEN 1 ELSE 0)
|
||||
// for now, always zero (not sure when this would be 1 yet)
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException(String.Format("Unhandled disk special function 2 {0}", df2));
|
||||
|
||||
@@ -192,54 +192,14 @@ namespace Contralto.CPU
|
||||
// if IR[3-7] = 16B 1 CONVERT
|
||||
// if IR[3-7] = 37B 17B ROMTRAP -- used by Swat, the debugger
|
||||
// else 16B ROMTRAP
|
||||
if ((_cpu._ir & 0x8000) != 0)
|
||||
{
|
||||
_nextModifier = (ushort)(3 - ((_cpu._ir & 0xc0) >> 6));
|
||||
}
|
||||
else if ((_cpu._ir & 0xc000) == 0xc000)
|
||||
{
|
||||
_nextModifier = (ushort)((_cpu._ir & 0x400) >> 10);
|
||||
}
|
||||
else if ((_cpu._ir & 0x1f00) == 0)
|
||||
{
|
||||
_nextModifier = 2;
|
||||
}
|
||||
else if ((_cpu._ir & 0x1f00) == 0x0100)
|
||||
{
|
||||
_nextModifier = 5;
|
||||
}
|
||||
else if ((_cpu._ir & 0x1f00) == 0x0200)
|
||||
{
|
||||
_nextModifier = 3;
|
||||
}
|
||||
else if ((_cpu._ir & 0x1f00) == 0x0300)
|
||||
{
|
||||
_nextModifier = 6;
|
||||
}
|
||||
else if ((_cpu._ir & 0x1f00) == 0x0400)
|
||||
{
|
||||
_nextModifier = 7;
|
||||
}
|
||||
else if ((_cpu._ir & 0x1f00) == 0x0900)
|
||||
{
|
||||
_nextModifier = 4;
|
||||
}
|
||||
else if ((_cpu._ir & 0x1f00) == 0x0a00)
|
||||
{
|
||||
_nextModifier = 4;
|
||||
}
|
||||
else if ((_cpu._ir & 0x1f00) == 0x0e00)
|
||||
{
|
||||
_nextModifier = 1;
|
||||
}
|
||||
else if ((_cpu._ir & 0x1f00) == 0x1f00)
|
||||
{
|
||||
_nextModifier = 0xf;
|
||||
}
|
||||
else
|
||||
{
|
||||
_nextModifier = 0xe;
|
||||
}
|
||||
|
||||
//
|
||||
// NOTE: the above table from the Hardware Manual is incorrect (or at least incomplete / misleading).
|
||||
// There is considerably more that goes into determining the dispatch, which is controlled by a 256x8
|
||||
// PROM. We just use the PROM rather than implementing the above logic (because it works.)
|
||||
//
|
||||
_nextModifier = ControlROM.ACSourceROM[(_cpu._ir & 0xff00) >> 8];
|
||||
|
||||
break;
|
||||
|
||||
case EmulatorF2.ACDEST:
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace Contralto.CPU
|
||||
else
|
||||
{
|
||||
// See also comments below.
|
||||
_busData = ConstantMemory.ConstantROM[(instruction.RSELECT << 3) | ((uint)instruction.BS)];
|
||||
_busData = ControlROM.ConstantROM[(instruction.RSELECT << 3) | ((uint)instruction.BS)];
|
||||
}
|
||||
|
||||
// Constant ROM access:
|
||||
@@ -202,7 +202,7 @@ namespace Contralto.CPU
|
||||
instruction.F1 == SpecialFunction1.Constant ||
|
||||
instruction.F2 == SpecialFunction2.Constant)
|
||||
{
|
||||
_busData &= ConstantMemory.ConstantROM[(instruction.RSELECT << 3) | ((uint)instruction.BS)];
|
||||
_busData &= ControlROM.ConstantROM[(instruction.RSELECT << 3) | ((uint)instruction.BS)];
|
||||
}
|
||||
|
||||
// Do ALU operation
|
||||
|
||||
Reference in New Issue
Block a user