1
0
mirror of https://github.com/livingcomputermuseum/ContrAlto.git synced 2026-01-26 04:01:07 +00:00

Fixed drive select logic (multiple drives now work properly -- fingers crossed) and some minor cleanup and dead-code removal.

This commit is contained in:
Josh Dersch
2016-03-24 17:31:21 -07:00
parent bfda781576
commit c4565f81a5
10 changed files with 78 additions and 80 deletions

View File

@@ -22,9 +22,7 @@ namespace Contralto.CPU
}
protected override InstructionCompletion ExecuteInstruction(MicroInstruction instruction)
{
// Log.Write(LogComponent.Debug, "{0}: {1}", Conversion.ToOctal(_mpc), UCodeDisassembler.DisassembleInstruction(instruction, _taskType));
{
InstructionCompletion completion = base.ExecuteInstruction(instruction);
// Deal with SECLATE semantics: If the Disk Sector task wakes up and runs before
@@ -89,7 +87,7 @@ namespace Contralto.CPU
case DiskF1.LoadKSTAT:
// "KSTAT[12-15] are loaded from BUS[12-15]. (Actually BUS[13] is ORed onto
// KSTAT[13].)"
// KSTAT[13].)"
// From the schematic (and ucode source, based on the values it actually uses for BUS[13]), BUS[13]
// is also inverted. So there's that, too.
@@ -170,11 +168,7 @@ namespace Contralto.CPU
if (!_diskController.FatalError)
{
_nextModifier |= 0x1;
}
else
{
Console.WriteLine("fatal disk error on disk {0}", _diskController.Drive);
}
}
break;
case DiskF2.STROBON:
@@ -190,8 +184,7 @@ namespace Contralto.CPU
// "NEXT <- NEXT OR (IF disk not ready to accept command THEN 1 ELSE 0)
_nextModifier |= GetInitModifier(instruction);
if (!_diskController.Ready)
{
Console.WriteLine("disk {0} not ready", _diskController.Drive);
{
_nextModifier |= 0x1;
}
break;

View File

@@ -36,10 +36,10 @@ namespace Contralto.CPU
break;
case DisplayHorizontalF2.SETMODE:
_displayController.SETMODE(_busData);
// "If bit 0 = 1, the bit clock rate is set to 100ns period (at the start of the next scan line),
// and a 1 is merged into NEXT[9]."
_displayController.SETMODE(_busData);
if ((_busData & 0x8000) != 0)
{
_nextModifier |= 1;

View File

@@ -18,6 +18,12 @@ namespace Contralto.CPU
_wakeup = true;
}
public override void Reset()
{
base.Reset();
_wakeup = true;
}
public override void BlockTask()
{
throw new InvalidOperationException("The emulator task cannot be blocked.");
@@ -176,14 +182,11 @@ namespace Contralto.CPU
// "...causes (IR[3-4] XOR 3) to be used as the low-order two bits of the RSELECT field.
// This address the accumulators from the destination field of the instruction. The selected
// register may be loaded or read."
_rSelect = (_rSelect & 0xfffc) | ((((uint)_cpu._ir & 0x1800) >> 11) ^ 3);
break;
case EmulatorF2.LoadDNS:
//
// "...DNS also addresses R from (3-IR[3 - 4])..."
//
_rSelect = (_rSelect & 0xfffc) | ((((uint)_cpu._ir & 0x1800) >> 11) ^ 3);
_rSelect = (_rSelect & 0xfffc) | ((((uint)_cpu._ir & 0x1800) >> 11) ^ 3);
break;
}
@@ -195,12 +198,11 @@ namespace Contralto.CPU
switch (ef2)
{
case EmulatorF2.LoadIR:
// based on block diagram, this always comes from the bus
// Load IR from the bus
_cpu._ir = _busData;
// "IR<- also merges bus bits 0, 5, 6 and 7 into NEXT[6-9] which does a first level
// instruction dispatch."
// Assuming for now this is an OR operation like everything else that modifies NEXT.
// instruction dispatch."
_nextModifier = (ushort)(((_busData & 0x8000) >> 12) | ((_busData & 0x0700) >> 8));
// "IR<- clears SKIP"

View File

@@ -7,7 +7,7 @@ namespace Contralto.CPU
public partial class AltoCPU
{
/// <summary>
/// EthernetTask implements Ethernet-specific task function
/// EthernetTask implements Ethernet-specific task functions
/// </summary>
private sealed class EthernetTask : Task
{

View File

@@ -3,7 +3,7 @@
public partial class AltoCPU
{
/// <summary>
/// DisplayWordTask provides functionality for the Memory Refresh task
/// DisplayWordTask provides functionality for the Memory Refresh task.
/// </summary>
private sealed class MemoryRefreshTask : Task
{
@@ -12,18 +12,16 @@
_taskType = TaskType.MemoryRefresh;
_wakeup = false;
}
/*
protected override InstructionCompletion ExecuteInstruction(MicroInstruction instruction)
{
//
// Based on readings of the MRT microcode, the MRT keeps its wakeup
// until it executes a BLOCK.
// "; This version assumes MRTACT is cleared by BLOCK, not MAR<- R37"
//
return base.ExecuteInstruction(instruction);
}*/
}
//
// MRT has no special functions or special behavior, but here's a note regarding the MRT
// wakeup behavior, for future reference:
//
// Based on readings of the MRT microcode, the MRT keeps its wakeup
// until it executes a BLOCK. (i.e. no special wakeup handling at all.)
// "; This version assumes MRTACT is cleared by BLOCK, not MAR<- R37"
//
}
}
}

View File

@@ -14,10 +14,11 @@ namespace Contralto.CPU
MemoryWait,
}
// Task:
// 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.
/// <summary>
/// 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.
/// </summary>
public abstract class Task
{
public Task(AltoCPU cpu)
@@ -25,9 +26,7 @@ namespace Contralto.CPU
_wakeup = false;
_mpc = 0xffff; // invalid, for sanity checking
_taskType = TaskType.Invalid;
_cpu = cpu;
_block = false;
_cpu = cpu;
}
public int Priority
@@ -61,15 +60,6 @@ namespace Contralto.CPU
set { _firstInstructionAfterSwitch = value; }
}
/// <summary>
/// Indicates whether the current uInstruction asserts BLOCK.
/// Used by hardware for various tasks.
/// </summary>
public bool BLOCK
{
get { return _block; }
}
public virtual void Reset()
{
// From The Alto Hardware Manual (section 2, "Initialization"):
@@ -82,6 +72,8 @@ namespace Contralto.CPU
_swMode = false;
_wrtRam = false;
_wakeup = false;
_skip = 0;
}
public virtual void SoftReset()
@@ -104,11 +96,7 @@ namespace Contralto.CPU
public InstructionCompletion ExecuteNext()
{
MicroInstruction instruction = UCodeMemory.GetInstruction(_mpc, _taskType);
// Grab BLOCK bit so that other tasks / hardware can look at it
_block = instruction.F1 == SpecialFunction1.Block;
MicroInstruction instruction = UCodeMemory.GetInstruction(_mpc, _taskType);
return ExecuteInstruction(instruction);
}
@@ -309,7 +297,7 @@ namespace Contralto.CPU
// It also doensn't appear to affect the execution of the standard Alto uCode in any significant
// way, but is included here for correctness.
//
//if (!_firstInstructionAfterSwitch)
if (!_firstInstructionAfterSwitch)
{
// Yield to other more important tasks
completion = InstructionCompletion.TaskSwitch;
@@ -572,8 +560,6 @@ namespace Contralto.CPU
protected bool _wakeup;
protected bool _firstInstructionAfterSwitch;
protected bool _block;
// Emulator Task-specific data. This is placed here because it is used by the ALU and it's easier to reference in the
// base class even if it does break encapsulation. See notes in the EmulatorTask class for meaning.
protected int _skip;

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -55,13 +55,25 @@ namespace Contralto.IO
// position is reached (before any data is transferred)."
_dataXfer = (_kAdr & 0x2) != 0x2;
//
// Select disk from bit 14 of KDATA.
// The HW reference claims that the drive is selected by bit 14 of KDATA XOR'd with bit 15
// of KADR but I can find no evidence in the schematics that this is actually so.
// Page 18 of the controller schematic ("DISK ADDRESSING") shows that the current DATA(14) (KDATA bit 14)
// value is gated into the DISK select lines (running to the drive) whenever a KADR<- F1 is executed.
// It is possible that the HW ref is telling the truth but the XORing is done by the Sector Task uCode
// and not the hardware, but where this is actually occurring is not obvious.
// At any rate: The below behavior appears to work correctly, so I'm sticking with it.
//
_disk = ((_kDataWrite & 0x2) >> 1);
Log.Write(LogComponent.DiskController, "KADR set to {0} (Header {1}, Label {2}, Data {3}, Xfer {4}, Drive {5})",
Conversion.ToOctal(_kAdr),
Conversion.ToOctal((_kAdr & 0xc0) >> 6),
Conversion.ToOctal((_kAdr & 0x30) >> 4),
Conversion.ToOctal((_kAdr & 0xc) >> 2),
_dataXfer,
_kAdr & 0x1);
_disk);
Log.Write(LogComponent.DiskController, " -Disk Address ({0}) is C/H/S {1}/{2}/{3}, Drive {4} Restore {5}",
Conversion.ToOctal(_kDataWrite),
@@ -77,7 +89,7 @@ namespace Contralto.IO
{
// Restore operation to cyl. 0:
InitSeek(0);
}
}
}
}
@@ -106,19 +118,7 @@ namespace Contralto.IO
if (_sendAdr & (_kDataWrite & 0x2) != 0)
{
// Select disk if _sendAdr is true
_disk = (_kAdr & 0x1);
_seeking = false;
// Clear the NOTREADY flag depending on whether the drive is loaded or not
if (_drives[_disk].IsLoaded)
{
_kStat &= (ushort)~NOTREADY;
}
else
{
_kStat |= NOTREADY;
}
_seeking = false;
}
}
@@ -214,7 +214,8 @@ namespace Contralto.IO
//
return (_kStat & SECLATE) != 0 ||
(_kStat & SEEKFAIL) != 0 ||
(_kStat & NOTREADY) != 0;
(_kStat & NOTREADY) != 0 ||
(!Ready);
}
}
@@ -279,6 +280,16 @@ namespace Contralto.IO
_kStat = (ushort)((_kStat & 0x0fff) | (_sector << 12));
// Clear the NOTREADY flag depending on whether the selected drive is loaded or not
if (_drives[_disk].IsLoaded)
{
_kStat &= (ushort)~NOTREADY;
}
else
{
_kStat |= NOTREADY;
}
// Reset internal state machine for sector data
_sectorWordIndex = 0;
_syncWordWritten = false;
@@ -397,7 +408,7 @@ namespace Contralto.IO
//
// Set "seek fail" bit based on selected cylinder (if out of bounds) and do not
// commence a seek if so.
if (destCylinder > SelectedDrive.Pack.Geometry.Cylinders - 1)
if (!SelectedDrive.IsLoaded || destCylinder > SelectedDrive.Pack.Geometry.Cylinders - 1)
{
_kStat |= SEEKFAIL;
@@ -703,11 +714,19 @@ namespace Contralto.IO
private bool _debugRead;
// KSTAT bitfields
public static readonly ushort SECLATE = 0x10;
public static readonly ushort NOTREADY = 0x20;
public static readonly ushort STROBE = 0x40;
public static readonly ushort SEEKFAIL = 0x80;
//
// KSTAT bitfields.
// Note that in reality the SECLATE status bit (bit 11) is a bit more nuanced; it's actually the OR of two signals:
// 1) SECLATE while the Sector Task is enabled (meaning that the sector task missed the beginning of a sector and that's bad).
// This is emulated.
// 2) CARRY while the Word Task is enabled. CARRY in this case is the carry out from the disk word shift register, signaling
// a completed word. If the Word Task is still running while a word is completed, this indicates that the word task missed that
// word and that's a fault. This is not currently emulated.
//
public static readonly ushort SECLATE = 0x10; // status bit 11
public static readonly ushort NOTREADY = 0x20; // 10
public static readonly ushort STROBE = 0x40; // 9
public static readonly ushort SEEKFAIL = 0x80; // 8
}
}