1
0
mirror of https://github.com/livingcomputermuseum/ContrAlto.git synced 2026-01-20 01:44:34 +00:00

185 lines
8.7 KiB
C#

using Contralto.IO;
using Contralto.Logging;
using System;
namespace Contralto.CPU
{
public partial class AltoCPU
{
/// <summary>
/// EthernetTask implements Ethernet-specific task function
/// </summary>
private sealed class EthernetTask : Task
{
public EthernetTask(AltoCPU cpu) : base(cpu)
{
_taskType = TaskType.Ethernet;
_wakeup = false;
_ethernetController = _cpu._system.EthernetController;
}
protected override InstructionCompletion ExecuteInstruction(MicroInstruction instruction)
{
// The Ethernet task only remains awake if there are pending data wakeups
if (_ethernetController.CountdownWakeup)
{
//
// The resulting [Countdown] wakeup is cleared when the Ether task next runs.
_ethernetController.CountdownWakeup = false;
_wakeup = false;
}
return base.ExecuteInstruction(instruction);
}
protected override ushort GetBusSource(int bs)
{
EthernetBusSource ebs = (EthernetBusSource)bs;
switch(ebs)
{
case EthernetBusSource.EIDFCT:
// Input Data Function. Gates the contents of the FIFO to BUS[0-15], and
// increments the read pointer at the end of the cycle.
return _ethernetController.ReadInputFifo(false /* increment read pointer */);
default:
throw new NotImplementedException(String.Format("Unimplemented Ethernet BS {0}", ebs));
}
}
protected override void ExecuteSpecialFunction1Early(MicroInstruction instruction)
{
EthernetF1 ef1 = (EthernetF1)instruction.F1;
switch (ef1)
{
case EthernetF1.EILFCT:
// Early: Input Look Function. Gates the contents of the FIFO to BUS[0-15] but does
// not increment the read pointer.
_busData &= _ethernetController.ReadInputFifo(true /* do not increment read pointer */);
break;
}
}
protected override void ExecuteSpecialFunction1(MicroInstruction instruction)
{
EthernetF1 ef1 = (EthernetF1)instruction.F1;
switch(ef1)
{
case EthernetF1.EILFCT:
// Nothing; handled in Early handler.
break;
case EthernetF1.EPFCT:
// Post Function. Gates interface status to BUS[8-15]. Resets the interface at
// the end of the cycle and removes wakeup for this task.
_busData &= _ethernetController.Status;
_ethernetController.ResetInterface();
_wakeup = false;
Log.Write(LogComponent.EthernetController, "EPFCT: Status {0}, bus now {1}",
Conversion.ToOctal(_ethernetController.Status),
Conversion.ToOctal(_busData));
break;
case EthernetF1.EWFCT:
// Countdown Wakeup Function. Sets a flip flop in the interface that will
// cause a wakeup to the Ether task on the next tick of SWAKMRT. This
// function must be issued in the instruction after a TASK. The resulting
// wakeup is cleared when the Ether task next runs.
Log.Write(LogComponent.EthernetController, "Enabling countdown wakeups.");
_ethernetController.CountdownWakeup = true;
break;
default:
throw new NotImplementedException(String.Format("Unimplemented Ethernet F1 {0}", ef1));
}
}
protected override void ExecuteSpecialFunction2(MicroInstruction instruction)
{
EthernetF2 ef2 = (EthernetF2)instruction.F2;
switch (ef2)
{
case EthernetF2.EODFCT:
// Output Data Function. Loads the FIFO from BUS[0-15], then increments the
// write pointer at the end of the cycle.
_ethernetController.WriteOutputFifo(_busData);
break;
case EthernetF2.EOSFCT:
// Output Start Function. Sets the OBusy flip flop in the interface, starting
// data wakeups to fill the FIFO for output. When the FIFO is full, or EEFct has
// been issued, the interface will wait for silence on the Ether and begin
// transmitting.
_ethernetController.StartOutput();
break;
case EthernetF2.ERBFCT:
// Reset Branch Function. This command dispatch function merges the ICMD
// and OCMD flip flops, into NEXT[6-7]. These flip flops are the means of
// communication between the emulator task and the Ethernet task. The
// emulator task sets them from BUS[14-15] with the STARTF function, causing
// the Ethernet task to wakeup, dispatch on them and then reset them with
// EPFCT.
Log.Write(LogComponent.EthernetController, "EBRBFCT: SIO is {0}.", _ethernetController.IOCMD);
_nextModifier |= (ushort)((_ethernetController.IOCMD << 2));
break;
case EthernetF2.EEFCT:
// End of transmission Function. This function is issued when all of the main
// memory output buffer has been transferred to the FIFO. EEFCT disables
// further data wakeups.
_ethernetController.EndTransmission();
break;
case EthernetF2.EBFCT:
// Branch Function. ORs a one into NEXT[7] if an input data late is detected,
// or an SIO with AC0[14:15] non-zero is issued, or if the transmitter or receiver
// goes done. ORs a one into NEXT[6] if a collision is detected.
if (_ethernetController.DataLate ||
_ethernetController.IOCMD != 0 ||
_ethernetController.OperationDone)
{
Log.Write(LogComponent.EthernetController, "EBFCT: DataLate {0} IOCMD {1} Done {2}", _ethernetController.DataLate, _ethernetController.IOCMD, _ethernetController.OperationDone);
_nextModifier |= 0x4;
}
if (_ethernetController.Collision)
{
Log.Write(LogComponent.EthernetController, "EBFCT: Collision");
_nextModifier |= 0x8;
}
break;
case EthernetF2.ECBFCT:
// Countdown Branch Function. ORs a one into NEXT[7] if the FIFO is not
// empty.
if (!_ethernetController.FIFOEmpty)
{
Log.Write(LogComponent.EthernetController, "ECBFCT: FIFO not empty");
_nextModifier |= 0x4;
}
break;
case EthernetF2.EISFCT:
// Input Start Function. Sets the IBusy flip flop in the interface, causing it to
// hunt for the beginning of a packet: silence on the Ether followed by a
// transition. When the interface has collected two words, it will begin
// generating data wakeups to the microcode.
_ethernetController.StartInput();
break;
default:
throw new NotImplementedException(String.Format("Unimplemented Ethernet F2 {0}", ef2));
}
}
private EthernetController _ethernetController;
}
}
}