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

Ethernet tweaks / hacks for IFS, added configuration for 'net boot.

This commit is contained in:
Josh Dersch 2016-02-17 13:54:23 -08:00
parent 325a416b87
commit 209dea8052
37 changed files with 657 additions and 109 deletions

View File

@ -28,8 +28,6 @@ namespace Contralto
_mouse = new Mouse();
_ethernetController = new EthernetController(this);
_cpu = new AltoCPU(this);
// Attach memory-mapped devices to the bus
@ -67,7 +65,10 @@ namespace Contralto
_cpu.Reset();
_ethernetController.Reset();
UCodeMemory.Reset();
UCodeMemory.Reset();
// Force the boot keys on reset.
PressBootKeys();
}
/// <summary>
@ -120,6 +121,18 @@ namespace Contralto
_diskController.Drives[drive].UnloadPack();
}
public void PressBootKeys()
{
//
// Press bootkeys if the user has specified a boot combination.
//
if (Configuration.EthernetBootEnabled)
{
_keyboard.PressBootKeys(Configuration.EthernetBootFile, true);
}
}
public AltoCPU CPU
{
get { return _cpu; }
@ -172,7 +185,7 @@ namespace Contralto
private void T_Elapsed(object sender, ElapsedEventArgs e)
{
System.Console.WriteLine("{0} CPU clocks/sec %{1}. {2} fields/sec", _clocks, ((double)_clocks / 5882353.0) * 100.0, _displayController.Fields);
//System.Console.WriteLine("{0} CPU clocks/sec %{1}. {2} fields/sec", _clocks, ((double)_clocks / 5882353.0) * 100.0, _displayController.Fields);
_clocks = 0;
_displayController.Fields = 0;
}

View File

@ -13,15 +13,22 @@ namespace Contralto
{
static Configuration()
{
// Initialize things to defaults
// Initialize things to defaults.
// TODO: Load from config file.
HostAddress = 0x22;
EthernetBootEnabled = false;
EthernetBootFile = 0;
}
public static string Drive0Image;
public static string Drive1Image;
public static byte HostAddress;
public static string HostEthernetInterfaceName;
public static string HostEthernetInterfaceName;
public static bool HostEthernetAvailable;
public static bool EthernetBootEnabled;
public static ushort EthernetBootFile;
}
}

View File

@ -99,17 +99,17 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AboutBox.cs">
<Compile Include="UI\AboutBox.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="AboutBox.Designer.cs">
<Compile Include="UI\AboutBox.Designer.cs">
<DependentUpon>AboutBox.cs</DependentUpon>
</Compile>
<Compile Include="AltoSystem.cs" />
<Compile Include="AltoWindow.cs">
<Compile Include="UI\AltoWindow.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="AltoWindow.Designer.cs">
<Compile Include="UI\AltoWindow.Designer.cs">
<DependentUpon>AltoWindow.cs</DependentUpon>
</Compile>
<Compile Include="Configuration.cs" />
@ -131,15 +131,21 @@
<Compile Include="CPU\Shifter.cs" />
<Compile Include="CPU\Tasks\Task.cs" />
<Compile Include="CPU\UCodeMemory.cs" />
<Compile Include="Debugger.cs">
<Compile Include="UI\Debugger.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Debugger.Designer.cs">
<Compile Include="UI\Debugger.Designer.cs">
<DependentUpon>Debugger.cs</DependentUpon>
</Compile>
<Compile Include="Display\FakeDisplayController.cs" />
<Compile Include="Display\DisplayController.cs" />
<Compile Include="Display\IAltoDisplay.cs" />
<Compile Include="UI\EthernetBootWindow.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="UI\EthernetBootWindow.Designer.cs">
<DependentUpon>EthernetBootWindow.cs</DependentUpon>
</Compile>
<Compile Include="IClockable.cs" />
<Compile Include="IO\DiabloDrive.cs" />
<Compile Include="IO\DiskController.cs" />
@ -167,6 +173,9 @@
<None Include="Disassembly\MesaROM.mu">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Disk\allgames.dsk">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Disk\bcpl.dsk">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
@ -200,6 +209,9 @@
<None Include="Disk\st76boot.dsk">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Disk\st76new.dsk">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Disk\tdisk4.dsk">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
@ -322,53 +334,32 @@
</None>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="AboutBox.resx">
<EmbeddedResource Include="UI\AboutBox.resx">
<DependentUpon>AboutBox.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="AltoWindow.resx">
<EmbeddedResource Include="UI\AltoWindow.resx">
<DependentUpon>AltoWindow.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Debugger.resx">
<EmbeddedResource Include="UI\Debugger.resx">
<DependentUpon>Debugger.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="UI\EthernetBootWindow.resx">
<DependentUpon>EthernetBootWindow.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Content Include="pcap\PcapDotNet.Base.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="pcap\PcapDotNet.Base.pdb">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="pcap\PcapDotNet.Base.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="pcap\PcapDotNet.Core.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="pcap\PcapDotNet.Core.Extensions.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="pcap\PcapDotNet.Core.Extensions.pdb">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="pcap\PcapDotNet.Core.Extensions.XML">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="pcap\PcapDotNet.Core.pdb">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="pcap\PcapDotNet.Core.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="pcap\PcapDotNet.Packets.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="pcap\PcapDotNet.Packets.pdb">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="pcap\PcapDotNet.Packets.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="pcap\PcapDotNet.Base.dll" />
<Content Include="pcap\PcapDotNet.Base.pdb" />
<Content Include="pcap\PcapDotNet.Base.xml" />
<Content Include="pcap\PcapDotNet.Core.dll" />
<Content Include="pcap\PcapDotNet.Core.Extensions.dll" />
<Content Include="pcap\PcapDotNet.Core.Extensions.pdb" />
<Content Include="pcap\PcapDotNet.Core.Extensions.XML" />
<Content Include="pcap\PcapDotNet.Core.pdb" />
<Content Include="pcap\PcapDotNet.Core.xml" />
<Content Include="pcap\PcapDotNet.Packets.dll" />
<Content Include="pcap\PcapDotNet.Packets.pdb" />
<Content Include="pcap\PcapDotNet.Packets.xml" />
<EmbeddedResource Include="Alto.ico" />
<Content Include="Notes.txt" />
</ItemGroup>

Binary file not shown.

BIN
Contralto/Disk/Josh.dsk Normal file

Binary file not shown.

BIN
Contralto/Disk/allgames.dsk Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Contralto/Disk/st76new.dsk Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -283,6 +283,8 @@ namespace Contralto.IO
_system.CPU.WakeupTask(TaskType.Ethernet);
// And actually tell the host ethernet interface to send the data.
// NOTE: We do not append a checksum to the outgoing 3mbit packet. See comments on the
// receiving end for an explanation.
if (_hostEthernet != null)
{
_hostEthernet.Send(_outputData, _outputIndex);
@ -352,6 +354,15 @@ namespace Contralto.IO
_receiverLock.ExitWriteLock();
}
/// <summary>
/// Runs the input state machine. This runs periodically (as scheduled by the Scheduler) and:
/// 1) Drops incoming packets if the interface is off
/// 2) Pulls incoming packets from the queue if the interface is active
/// 3) Reads words from incoming packets into the controller's FIFO
/// </summary>
/// <param name="timeNsec"></param>
/// <param name="skewNsec"></param>
/// <param name="context"></param>
private void InputHandler(ulong timeNsec, ulong skewNsec, object context)
{
switch(_inputState)
@ -376,15 +387,25 @@ namespace Contralto.IO
{
_incomingPacket = _nextPackets.Dequeue();
// Read the packet length (in words) (first word of the packet). Convert to bytes.
//
// Read the packet length (in words) (first word of the packet as provided by the sending emulator). Convert to bytes.
//
_incomingPacketLength = ((_incomingPacket.ReadByte()) | (_incomingPacket.ReadByte() << 8)) * 2;
// Add one word to the count for the checksum.
// NOTE: This is not provided by the sending emulator and is not computed here either.
// The microcode does not use it and any corrupted packets will be dealt with transparently by the host interface,
// not the emulator.
// We add the word to the count because the microcode expects to read it in from the input FIFO, it is then dropped.
//
_incomingPacketLength += 2;
// Sanity check:
if (_incomingPacketLength > _incomingPacket.Length - 2 &&
(_incomingPacketLength % 2) == 0)
if (_incomingPacketLength > _incomingPacket.Length ||
(_incomingPacketLength % 2) != 0)
{
throw new InvalidOperationException("Invalid 3mbit packet length header.");
throw new InvalidOperationException(
String.Format("Invalid 3mbit packet length header ({0} vs {1}.", _incomingPacketLength, _incomingPacket.Length));
}
Log.Write(LogComponent.EthernetPacket, "Accepting incoming packet (length {0}).", _incomingPacketLength);
@ -403,8 +424,7 @@ namespace Contralto.IO
if (_fifo.Count >= 16)
{
// This shouldn't happen.
Log.Write(LogComponent.EthernetController, "Input FIFO full, Scheduling next wakeup. No words added to the FIFO.");
_receiverLock.ExitUpgradeableReadLock();
Log.Write(LogComponent.EthernetController, "Input FIFO full, Scheduling next wakeup. No words added to the FIFO.");
break;
}

View File

@ -54,7 +54,7 @@ namespace Contralto.IO
{
public HostEthernet(EthernetInterface iface)
{
AttachInterface(iface);
AttachInterface(iface);
}
public HostEthernet(string name)
@ -94,23 +94,22 @@ namespace Contralto.IO
// Sanity check.
if (length < 1)
{
throw new InvalidOperationException("Raw packet data must contain at least two bytes for addressing.");
throw new InvalidOperationException("Raw packet data must contain at least two bytes for addressing.");
}
//
// Outgoing packet contains 2 extra words (4 bytes):
// - prepended packet length (one word)
// - appended checksum (one word)
byte[] packetBytes = new byte[length * 2 + 4];
//
// First two bytes include the length of the 3mbit packet (including checksum); since 10mbit packets have a minimum length of 46
// Outgoing packet contains 1 extra word (2 bytes) containing
// the prepended packet length (one word)
byte[] packetBytes = new byte[length * 2 + 2];
//
// First two bytes include the length of the 3mbit packet; since 10mbit packets have a minimum length of 46
// bytes, and 3mbit packets have no minimum length this is necessary so the receiver can pull out the
// correct amount of data.
//
packetBytes[0] = (byte)(length + 1);
packetBytes[1] = (byte)((length + 1) >> 8);
packetBytes[0] = (byte)(length);
packetBytes[1] = (byte)((length) >> 8);
//
// Do this annoying dance to stuff the ushorts into bytes because this is C#.
@ -121,13 +120,6 @@ namespace Contralto.IO
packetBytes[i * 2 + 3] = (byte)(packet[i] >> 8);
}
//
// Append the checksum.
// TODO: actually calculate it.
//
packetBytes[length * 2 + 2] = 0xbe;
packetBytes[length * 2 + 3] = 0xef;
//
// Grab the source and destination host addresses from the packet we're sending
// and build 10mbit versions.
@ -140,7 +132,7 @@ namespace Contralto.IO
Conversion.ToOctal(destinationHost),
length);
MacAddress destinationMac = new MacAddress((UInt48)(_10mbitMACPrefix | destinationHost));
MacAddress destinationMac = Get10mbitDestinationMacFrom3mbit(destinationHost);
MacAddress sourceMac = new MacAddress((UInt48)(_10mbitMACPrefix | Configuration.HostAddress));
// Build the outgoing packet; place the source/dest addresses, type field and the raw data.
@ -169,15 +161,16 @@ namespace Contralto.IO
//
// Filter out packets intended for the emulator, forward them on, drop everything else.
//
if ((int)p.Ethernet.EtherType == _3mbitFrameType &&
(p.Ethernet.Destination.ToValue() & 0xffffffffff00) == _10mbitMACPrefix &&
(p.Ethernet.Source.ToValue() & 0xff) != Configuration.HostAddress) // drop packets sent by ourselves
if ((int)p.Ethernet.EtherType == _3mbitFrameType && // encapsulated 3mbit frames
((p.Ethernet.Destination.ToValue() & 0xffffffffff00) == _10mbitMACPrefix || // addressed to any emulator OR
p.Ethernet.Destination.ToValue() == _10mbitBroadcast) && // broadcast
(p.Ethernet.Source.ToValue() != (UInt48)(_10mbitMACPrefix | Configuration.HostAddress))) // and not sent by this emulator
{
Log.Write(LogComponent.HostEthernet, "Received encapsulated 3mbit packet.");
_callback(p.Ethernet.Payload.ToMemoryStream());
_callback(p.Ethernet.Payload.ToMemoryStream());
}
else
{
{
// Not for us, discard the packet.
}
}
@ -206,7 +199,7 @@ namespace Contralto.IO
private void Open(bool promiscuous, int timeout)
{
_communicator = _interface.Open(65536, promiscuous ? PacketDeviceOpenAttributes.MaximumResponsiveness | PacketDeviceOpenAttributes.Promiscuous : PacketDeviceOpenAttributes.MaximumResponsiveness, timeout);
_communicator = _interface.Open(65536, promiscuous ? PacketDeviceOpenAttributes.MaximumResponsiveness | PacketDeviceOpenAttributes.Promiscuous : PacketDeviceOpenAttributes.MaximumResponsiveness, timeout);
// Set this to 1 so we'll get packets as soon as they arrive, no buffering.
_communicator.SetKernelMinimumBytesToCopy(1);
@ -221,8 +214,8 @@ namespace Contralto.IO
{
// Kick off receive thread.
_receiveThread = new Thread(ReceiveThread);
_receiveThread.Start();
}
_receiveThread.Start();
}
private void ReceiveThread()
{
@ -233,6 +226,35 @@ namespace Contralto.IO
_communicator.ReceivePackets(-1, ReceiveCallback);
}
private MacAddress Get10mbitDestinationMacFrom3mbit(byte destinationHost)
{
MacAddress destinationMac;
if (destinationHost == _3mbitBroadcast)
{
// 3mbit broadcast gets translated to 10mbit broadcast
destinationMac = new MacAddress(_10mbitBroadcast);
}
else
{
// Check addressing table for external (non emulator) addresses;
// otherwise just address other emulators
// TODO: implement table. Currently hardcoded address 1 to test IFS on dev machine
//
if (destinationHost == 1)
{
destinationMac = new MacAddress((UInt48)(_ifsTestMAC));
}
else
{
destinationMac = new MacAddress((UInt48)(_10mbitMACPrefix | destinationHost)); // emulator destination address
}
}
return destinationMac;
}
private LivePacketDevice _interface;
private PacketCommunicator _communicator;
private ReceivePacketDelegate _callback;
@ -241,13 +263,19 @@ namespace Contralto.IO
// Thread used for receive
private Thread _receiveThread;
private const int _3mbitFrameType = 0xbeef; // easy to identify, ostensibly unused by anything of any import
private const int _3mbitFrameType = 0xbeef; // easy to identify, ostensibly unused by anything of any import
/// <summary>
/// On output, these bytes are prepended to the Alto's 3mbit (1 byte) address to form a full
/// 6 byte Ethernet MAC.
/// On input, ethernet frames are checked for this prefix
/// </summary>
private UInt48 _10mbitMACPrefix = 0x0000aa010200; // 00-00-AA is the old Xerox vendor code, used just to be cute.
private UInt48 _10mbitMACPrefix = 0x0000aa010200; // 00-00-AA is the Xerox vendor code, used just to be cute.
private UInt48 _10mbitBroadcast = (UInt48)0xffffffffffff;
private const int _3mbitBroadcast = 0;
// Temporary; to be replaced with an external address mapping table
private UInt48 _ifsTestMAC = (UInt48)0x001060b88e3e;
}
}

View File

@ -84,21 +84,22 @@ namespace Contralto.IO
public ushort Bitmask;
}
/// <summary>
/// Currently just a stub indicating that no keys are being pressed.
/// Implements the Alto's keyboard and its encodings. It also provides
/// functionality for automatically pressing boot address key combinations.
/// </summary>
public class Keyboard : IMemoryMappedDevice
{
public Keyboard()
{
InitMap();
Reset();
Reset();
}
public void Reset()
{
_keyWords = new ushort[4];
_bootKeysPressed = false;
}
public ushort Read(int address, TaskType task, bool extendedMemoryReference)
@ -114,6 +115,14 @@ namespace Contralto.IO
public void KeyDown(AltoKey key)
{
//
// If we had been holding boot keys, release them now that a real user is pressing a key.
if (_bootKeysPressed)
{
Reset();
_bootKeysPressed = false;
}
AltoKeyBit bits = _keyMap[key];
_keyWords[bits.Word] |= _keyMap[key].Bitmask;
}
@ -124,12 +133,30 @@ namespace Contralto.IO
_keyWords[bits.Word] &= (ushort)~_keyMap[key].Bitmask;
}
public void PressBootKeys(ushort bootAddress, bool netBoot)
{
for (int i = 0; i < 16; i++)
{
if ((bootAddress & (0x8000 >> i)) != 0)
{
KeyDown(_bootKeys[i]);
}
}
if (netBoot)
{
// BS is held for netbooting
KeyDown(AltoKey.BS);
}
_bootKeysPressed = true;
}
public MemoryRange[] Addresses
{
get { return _addresses; }
}
private readonly MemoryRange[] _addresses =
{
new MemoryRange(0xfe1c, 0xfe1f), // 177034-177037
@ -207,5 +234,16 @@ namespace Contralto.IO
private ushort[] _keyWords;
private Dictionary<AltoKey, AltoKeyBit> _keyMap;
/// <summary>
/// The keys used to specify a 16-bit boot address, from MSB to LSB
/// </summary>
private AltoKey[] _bootKeys = new AltoKey[]
{
AltoKey.D3, AltoKey.D2, AltoKey.W, AltoKey.Q, AltoKey.S, AltoKey.A, AltoKey.D9, AltoKey.I,
AltoKey.X, AltoKey.O, AltoKey.L, AltoKey.Comma, AltoKey.Quote, AltoKey.RBracket, AltoKey.BlankMiddle, AltoKey.BlankTop
};
private bool _bootKeysPressed;
}
}

View File

@ -54,7 +54,7 @@ namespace Contralto.Logging
static Log()
{
// TODO: make configurable
_components = LogComponent.EthernetPacket | LogComponent.HostEthernet | LogComponent.EthernetController; // LogComponent.DiskController | LogComponent.DiskSectorTask | LogComponent.Debug | LogComponent.CPU; // LogComponent.EthernetController; // | LogComponent.Microcode | LogComponent.Memory | LogComponent.CPU;
_components = LogComponent.None; // LogComponent.EthernetPacket | LogComponent.HostEthernet | LogComponent.EthernetController; // LogComponent.DiskController | LogComponent.DiskSectorTask | LogComponent.Debug | LogComponent.CPU; // LogComponent.EthernetController; // | LogComponent.Microcode | LogComponent.Memory | LogComponent.CPU;
_type = LogType.Normal | LogType.Warning | LogType.Error | LogType.Verbose;
//_logStream = new StreamWriter("log.txt");

View File

@ -12,6 +12,9 @@ namespace Contralto
{
// Handle command-line args
PrintHerald();
// See if WinPCap is installed and working
TestPCap();
ParseCommandLine(args);
@ -31,13 +34,6 @@ namespace Contralto
mainWindow.AttachSystem(system);
/*
Debugger d = new Debugger(system);
system.AttachDisplay(d);
d.LoadSourceCode(MicrocodeBank.ROM0, "Disassembly\\altoIIcode3.mu");
d.LoadSourceCode(MicrocodeBank.ROM1, "Disassembly\\MesaROM.mu");
d.ShowDialog();
*/
mainWindow.ShowDialog();
@ -80,7 +76,14 @@ namespace Contralto
case "-hostinterface":
if (index < args.Length)
{
Configuration.HostEthernetInterfaceName = args[index++];
if (!Configuration.HostEthernetAvailable)
{
Console.WriteLine("Ethernet functionality is disabled, host interface cannot be specified.");
}
else
{
Configuration.HostEthernetInterfaceName = args[index++];
}
}
else
{
@ -89,11 +92,18 @@ namespace Contralto
break;
case "-listinterfaces":
List<EthernetInterface> interfaces = EthernetInterface.EnumerateDevices();
foreach (EthernetInterface i in interfaces)
if (!Configuration.HostEthernetAvailable)
{
Console.WriteLine("Name: '{0}'\n Description: '{1}'\n MAC '{2}'", i.Name, i.Description, i.MacAddress);
Console.WriteLine("Ethernet functionality is disabled, interfaces cannot be enumerated.");
}
else
{
List<EthernetInterface> interfaces = EthernetInterface.EnumerateDevices();
foreach (EthernetInterface i in interfaces)
{
Console.WriteLine("Name: '{0}'\n Description: '{1}'\n MAC '{2}'", i.Name, i.Description, i.MacAddress);
}
}
break;
@ -127,5 +137,24 @@ namespace Contralto
// TODO: make more useful.
Console.WriteLine("Something is wrong, try again.");
}
private static void TestPCap()
{
// Just try enumerating interfaces, if this fails for any reason we assume
// PCap is not properly installed.
try
{
List<EthernetInterface> interfaces = EthernetInterface.EnumerateDevices();
Configuration.HostEthernetAvailable = true;
}
catch
{
Console.WriteLine("WARNING: WinPCAP does not appear to be properly installed.");
Console.WriteLine(" Ethernet functionality is disabled.");
Console.WriteLine(" Please install WinPCAP from: http://www.winpcap.org/");
Configuration.HostEthernetAvailable = false;
}
}
}
}

View File

@ -52,6 +52,7 @@
this.CaptureStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.SystemStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.DiskStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.SystemEthernetBootMenu = new System.Windows.Forms.ToolStripMenuItem();
((System.ComponentModel.ISupportInitialize)(this.DisplayBox)).BeginInit();
this.menuStrip1.SuspendLayout();
this.StatusLine.SuspendLayout();
@ -92,7 +93,7 @@
// exitToolStripMenuItem
//
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
this.exitToolStripMenuItem.Size = new System.Drawing.Size(92, 22);
this.exitToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.exitToolStripMenuItem.Text = "Exit";
this.exitToolStripMenuItem.Click += new System.EventHandler(this.OnFileExitClick);
//
@ -103,6 +104,7 @@
this.SystemResetMenuItem,
this.drive0ToolStripMenuItem,
this.drive1ToolStripMenuItem,
this.SystemEthernetBootMenu,
this.optionsToolStripMenuItem,
this.SystemShowDebuggerMenuItem});
this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
@ -174,14 +176,14 @@
// loadToolStripMenuItem
//
this.loadToolStripMenuItem.Name = "loadToolStripMenuItem";
this.loadToolStripMenuItem.Size = new System.Drawing.Size(134, 22);
this.loadToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.loadToolStripMenuItem.Text = "Load...";
this.loadToolStripMenuItem.Click += new System.EventHandler(this.OnSystemDrive1LoadClick);
//
// unloadToolStripMenuItem
//
this.unloadToolStripMenuItem.Name = "unloadToolStripMenuItem";
this.unloadToolStripMenuItem.Size = new System.Drawing.Size(134, 22);
this.unloadToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.unloadToolStripMenuItem.Text = "Unload...";
this.unloadToolStripMenuItem.Click += new System.EventHandler(this.OnSystemDrive1UnloadClick);
//
@ -189,7 +191,7 @@
//
this.Drive1ImageName.Enabled = false;
this.Drive1ImageName.Name = "Drive1ImageName";
this.Drive1ImageName.Size = new System.Drawing.Size(134, 22);
this.Drive1ImageName.Size = new System.Drawing.Size(152, 22);
this.Drive1ImageName.Text = "Image Name";
//
// optionsToolStripMenuItem
@ -219,7 +221,7 @@
// aboutToolStripMenuItem
//
this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem";
this.aboutToolStripMenuItem.Size = new System.Drawing.Size(103, 22);
this.aboutToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.aboutToolStripMenuItem.Text = "About";
this.aboutToolStripMenuItem.Click += new System.EventHandler(this.OnHelpAboutClick);
//
@ -254,6 +256,13 @@
this.DiskStatusLabel.Size = new System.Drawing.Size(82, 17);
this.DiskStatusLabel.Text = "DiskStatusLabel";
//
// SystemEthernetBootMenu
//
this.SystemEthernetBootMenu.Name = "SystemEthernetBootMenu";
this.SystemEthernetBootMenu.Size = new System.Drawing.Size(210, 22);
this.SystemEthernetBootMenu.Text = "Ethernet Boot...";
this.SystemEthernetBootMenu.Click += new System.EventHandler(this.OnEthernetBootClicked);
//
// AltoWindow
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -310,5 +319,6 @@
private System.Windows.Forms.ToolStripMenuItem Drive1ImageName;
private System.Windows.Forms.ToolStripStatusLabel SystemStatusLabel;
private System.Windows.Forms.ToolStripStatusLabel DiskStatusLabel;
private System.Windows.Forms.ToolStripMenuItem SystemEthernetBootMenu;
}
}

View File

@ -135,6 +135,17 @@ namespace Contralto
Drive1ImageName.Text = _noImageLoadedText;
}
private void OnEthernetBootClicked(object sender, EventArgs e)
{
EthernetBootWindow bootWindow = new EthernetBootWindow();
bootWindow.ShowDialog();
//
// Apply settings to system.
//
_system.PressBootKeys();
}
private void OnHelpAboutClick(object sender, EventArgs e)
{
AboutBox about = new AboutBox();
@ -618,7 +629,7 @@ namespace Contralto
private void InitKeymap()
{
_keyMap = new Dictionary<Keys, AltoKey>();
_keyMap.Add(Keys.A, AltoKey.A);
_keyMap.Add(Keys.B, AltoKey.B);
_keyMap.Add(Keys.C, AltoKey.C);
@ -659,6 +670,7 @@ namespace Contralto
_keyMap.Add(Keys.OemPeriod, AltoKey.Period);
_keyMap.Add(Keys.Oemcomma, AltoKey.Comma);
_keyMap.Add(Keys.OemQuotes, AltoKey.Quote);
_keyMap.Add(Keys.Oem5, AltoKey.BSlash);
_keyMap.Add(Keys.OemBackslash, AltoKey.BSlash);
_keyMap.Add(Keys.OemQuestion, AltoKey.FSlash);
_keyMap.Add(Keys.Oemplus, AltoKey.Plus);

View File

@ -0,0 +1,133 @@
namespace Contralto
{
partial class EthernetBootWindow
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.EthernetBootEnabled = new System.Windows.Forms.CheckBox();
this.BootFileGroup = new System.Windows.Forms.GroupBox();
this.label1 = new System.Windows.Forms.Label();
this.BootFileComboBox = new System.Windows.Forms.ComboBox();
this.OKButton = new System.Windows.Forms.Button();
this.CancelButton = new System.Windows.Forms.Button();
this.BootFileGroup.SuspendLayout();
this.SuspendLayout();
//
// EthernetBootEnabled
//
this.EthernetBootEnabled.AutoSize = true;
this.EthernetBootEnabled.Location = new System.Drawing.Point(7, 12);
this.EthernetBootEnabled.Name = "EthernetBootEnabled";
this.EthernetBootEnabled.Size = new System.Drawing.Size(133, 17);
this.EthernetBootEnabled.TabIndex = 0;
this.EthernetBootEnabled.Text = "Ethernet Boot Enabled";
this.EthernetBootEnabled.UseVisualStyleBackColor = true;
this.EthernetBootEnabled.CheckedChanged += new System.EventHandler(this.OnCheckChanged);
//
// BootFileGroup
//
this.BootFileGroup.Controls.Add(this.label1);
this.BootFileGroup.Controls.Add(this.BootFileComboBox);
this.BootFileGroup.Location = new System.Drawing.Point(4, 35);
this.BootFileGroup.Name = "BootFileGroup";
this.BootFileGroup.Size = new System.Drawing.Size(397, 62);
this.BootFileGroup.TabIndex = 1;
this.BootFileGroup.TabStop = false;
this.BootFileGroup.Text = "Boot File";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(6, 16);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(359, 13);
this.label1.TabIndex = 1;
this.label1.Text = "Select a standard boot file number below, or enter a custom value in octal. ";
//
// BootFileComboBox
//
this.BootFileComboBox.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend;
this.BootFileComboBox.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems;
this.BootFileComboBox.FormattingEnabled = true;
this.BootFileComboBox.Location = new System.Drawing.Point(6, 32);
this.BootFileComboBox.Name = "BootFileComboBox";
this.BootFileComboBox.Size = new System.Drawing.Size(158, 21);
this.BootFileComboBox.TabIndex = 0;
this.BootFileComboBox.SelectedIndexChanged += new System.EventHandler(this.BootFileComboBox_SelectedIndexChanged);
//
// OKButton
//
this.OKButton.Location = new System.Drawing.Point(245, 103);
this.OKButton.Name = "OKButton";
this.OKButton.Size = new System.Drawing.Size(75, 23);
this.OKButton.TabIndex = 2;
this.OKButton.Text = "OK";
this.OKButton.UseVisualStyleBackColor = true;
this.OKButton.Click += new System.EventHandler(this.OKButton_Click);
//
// CancelButton
//
this.CancelButton.Location = new System.Drawing.Point(326, 103);
this.CancelButton.Name = "CancelButton";
this.CancelButton.Size = new System.Drawing.Size(75, 23);
this.CancelButton.TabIndex = 3;
this.CancelButton.Text = "Cancel";
this.CancelButton.UseVisualStyleBackColor = true;
this.CancelButton.Click += new System.EventHandler(this.CancelButton_Click);
//
// EthernetBootWindow
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(413, 130);
this.Controls.Add(this.CancelButton);
this.Controls.Add(this.OKButton);
this.Controls.Add(this.BootFileGroup);
this.Controls.Add(this.EthernetBootEnabled);
this.Name = "EthernetBootWindow";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Ethernet Boot Options";
this.BootFileGroup.ResumeLayout(false);
this.BootFileGroup.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.CheckBox EthernetBootEnabled;
private System.Windows.Forms.GroupBox BootFileGroup;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ComboBox BootFileComboBox;
private System.Windows.Forms.Button OKButton;
private System.Windows.Forms.Button CancelButton;
}
}

View File

@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Contralto
{
public partial class EthernetBootWindow : Form
{
public EthernetBootWindow()
{
InitializeComponent();
LoadBootEntries();
BootFileGroup.Enabled = EthernetBootEnabled.Checked = Configuration.EthernetBootEnabled;
SelectBootFile(Configuration.EthernetBootFile);
}
private void LoadBootEntries()
{
foreach(BootFileEntry e in _bootEntries)
{
BootFileComboBox.Items.Add(e);
}
}
private void SelectBootFile(ushort fileNumber)
{
// Find the matching entry, if any.
bool found = false;
for (int i = 0; i < BootFileComboBox.Items.Count; i++)
{
if (((BootFileEntry)BootFileComboBox.Items[i]).FileNumber == fileNumber)
{
BootFileComboBox.Select(i, 1);
BootFileComboBox.Text = BootFileComboBox.Items[i].ToString();
found = true;
break;
}
}
if (!found)
{
// No matching entry, just fill in the text box with the number.
BootFileComboBox.Text = Conversion.ToOctal(fileNumber);
}
}
private void BootFileComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
_selectedBoot = ((BootFileEntry)BootFileComboBox.SelectedItem).FileNumber;
}
private void OKButton_Click(object sender, EventArgs e)
{
if (BootFileComboBox.SelectedItem == null)
{
try
{
_selectedBoot = Convert.ToUInt16(BootFileComboBox.Text, 8);
}
catch
{
MessageBox.Show("Please select a valid boot entry or type in a valid boot number.", "Invalid selection");
return;
}
}
else
{
_selectedBoot = ((BootFileEntry)BootFileComboBox.SelectedItem).FileNumber;
}
Configuration.EthernetBootFile = _selectedBoot;
Configuration.EthernetBootEnabled = _bootEnabled;
this.Close();
}
private void CancelButton_Click(object sender, EventArgs e)
{
this.Close();
}
private void OnCheckChanged(object sender, EventArgs e)
{
BootFileGroup.Enabled = _bootEnabled = EthernetBootEnabled.Checked;
}
private BootFileEntry[] _bootEntries = new BootFileEntry[]
{
new BootFileEntry(0, "DMT"),
new BootFileEntry(1, "NewOS"),
new BootFileEntry(2, "FTP"),
new BootFileEntry(3, "Scavenger"),
new BootFileEntry(4, "CopyDisk"),
new BootFileEntry(5, "CRTTest"),
new BootFileEntry(6, "MADTest"),
new BootFileEntry(7, "Chat"),
new BootFileEntry(8, "NetExec"),
new BootFileEntry(9, "PupTest"),
new BootFileEntry(10, "EtherWatch"),
new BootFileEntry(11, "KeyTest"),
new BootFileEntry(13, "DiEx"),
new BootFileEntry(15, "EDP"),
new BootFileEntry(16, "BFSTest"),
new BootFileEntry(17, "GateControl"),
new BootFileEntry(18, "EtherLoad"),
};
private ushort _selectedBoot;
private bool _bootEnabled;
}
public struct BootFileEntry
{
public BootFileEntry(ushort number, string desc)
{
FileNumber = number;
Description = desc;
}
public override string ToString()
{
return String.Format("{0} - {1}", Conversion.ToOctal(FileNumber), Description);
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
public ushort FileNumber;
public string Description;
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>