mirror of
https://github.com/livingcomputermuseum/ContrAlto.git
synced 2026-01-23 19:06:39 +00:00
1) The Orbit microcode occasionally expects to be able to do a double-word read in cycles 6 and 7 instead of the usual 5 and 6. 2) The double-word logic incorrectly handles several species of overlapped read/writes, which Spruce's layout microcode uses. As a result, Spruce now works, as do the Smalltalk-80 images. Several tweaks to microcode disassembly (still rough). Completed Orbit / Dover ROS / Dover Print Engine emulation. Still some rough edges; it works and can create PDF output. Tweaked Disk Controller's Restore operation, it is now more accurate though wasn't causing any noticable issues.
160 lines
6.0 KiB
C#
160 lines
6.0 KiB
C#
/*
|
|
This file is part of ContrAlto.
|
|
|
|
ContrAlto is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
ContrAlto is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with ContrAlto. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
using Contralto.Logging;
|
|
using System;
|
|
|
|
namespace Contralto.CPU
|
|
{
|
|
public partial class AltoCPU
|
|
{
|
|
/// <summary>
|
|
/// OrbitTask provides the implementation of the Orbit (printer rasterizer) controller
|
|
/// specific functions.
|
|
/// </summary>
|
|
private sealed class OrbitTask : Task
|
|
{
|
|
public OrbitTask(AltoCPU cpu) : base(cpu)
|
|
{
|
|
_taskType = TaskType.Orbit;
|
|
_wakeup = false;
|
|
}
|
|
|
|
protected override void ExecuteBlock()
|
|
{
|
|
_cpu._system.OrbitController.Stop();
|
|
}
|
|
|
|
protected override ushort GetBusSource(MicroInstruction instruction)
|
|
{
|
|
//
|
|
// The Orbit task is wired to be a RAM-enabled task so it can use
|
|
// S registers.
|
|
// This code is stolen from the Emulator task; we should refactor this...
|
|
//
|
|
EmulatorBusSource ebs = (EmulatorBusSource)instruction.BS;
|
|
|
|
switch (ebs)
|
|
{
|
|
case EmulatorBusSource.ReadSLocation:
|
|
if (instruction.RSELECT != 0)
|
|
{
|
|
return _cpu._s[_rb][instruction.RSELECT];
|
|
}
|
|
else
|
|
{
|
|
// "...when reading data from the S registers onto the processor bus,
|
|
// the RSELECT value 0 causes the current value of the M register to
|
|
// appear on the bus..."
|
|
return _cpu._m;
|
|
}
|
|
|
|
case EmulatorBusSource.LoadSLocation:
|
|
// "When an S register is being loaded from M, the processor bus receives an
|
|
// undefined value rather than being set to zero."
|
|
_loadS = true;
|
|
return 0xffff; // Technically this is an "undefined value," we're defining it as -1.
|
|
|
|
default:
|
|
throw new InvalidOperationException(String.Format("Unhandled bus source {0}", instruction.BS));
|
|
}
|
|
|
|
|
|
}
|
|
|
|
protected override void ExecuteSpecialFunction1Early(MicroInstruction instruction)
|
|
{
|
|
OrbitF1 of1 = (OrbitF1)instruction.F1;
|
|
switch (of1)
|
|
{
|
|
|
|
case OrbitF1.OrbitDeltaWC:
|
|
_busData &= _cpu._system.OrbitController.GetDeltaWC();
|
|
break;
|
|
|
|
case OrbitF1.OrbitDBCWidthRead:
|
|
_busData &= _cpu._system.OrbitController.GetDBCWidth();
|
|
break;
|
|
|
|
case OrbitF1.OrbitOutputData:
|
|
_busData &= _cpu._system.OrbitController.GetOutputDataAlto();
|
|
break;
|
|
|
|
case OrbitF1.OrbitStatus:
|
|
_busData &= _cpu._system.OrbitController.GetOrbitStatus();
|
|
|
|
// branch:
|
|
// "OrbitStatus sets NEXT[7] of IACS os *not* on, i.e. if Orbit is
|
|
// not in a character segment."
|
|
//
|
|
if (!_cpu._system.OrbitController.IACS)
|
|
{
|
|
_nextModifier |= 0x4;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected override void ExecuteSpecialFunction2(MicroInstruction instruction)
|
|
{
|
|
OrbitF2 of2 = (OrbitF2)instruction.F2;
|
|
switch (of2)
|
|
{
|
|
case OrbitF2.OrbitDBCWidthSet:
|
|
_cpu._system.OrbitController.SetDBCWidth(_busData);
|
|
break;
|
|
|
|
case OrbitF2.OrbitXY:
|
|
_cpu._system.OrbitController.SetXY(_busData);
|
|
break;
|
|
|
|
case OrbitF2.OrbitHeight:
|
|
_cpu._system.OrbitController.SetHeight(_busData);
|
|
|
|
// branch:
|
|
// "OrbitHeight sets NEXT[7] if the refresh timer has expired, i.e.
|
|
// if the image buffer needs refreshing."
|
|
//
|
|
if (_cpu._system.OrbitController.RefreshTimerExpired)
|
|
{
|
|
_nextModifier |= 0x4;
|
|
}
|
|
break;
|
|
|
|
case OrbitF2.OrbitFontData:
|
|
_cpu._system.OrbitController.WriteFontData(_busData);
|
|
break;
|
|
|
|
case OrbitF2.OrbitInk:
|
|
_cpu._system.OrbitController.WriteInkData(_busData);
|
|
break;
|
|
|
|
case OrbitF2.OrbitControl:
|
|
_cpu._system.OrbitController.Control(_busData);
|
|
break;
|
|
|
|
case OrbitF2.OrbitROSCommand:
|
|
_cpu._system.OrbitController.SendROSCommand(_busData);
|
|
break;
|
|
|
|
default:
|
|
throw new InvalidOperationException(String.Format("Unhandled orbit F2 {0}.", of2));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|