diff --git a/Contralto/AltoSystem.cs b/Contralto/AltoSystem.cs index fd6eb10..c262144 100644 --- a/Contralto/AltoSystem.cs +++ b/Contralto/AltoSystem.cs @@ -65,10 +65,7 @@ namespace Contralto _cpu.Reset(); _ethernetController.Reset(); - UCodeMemory.Reset(); - - // Force the boot keys on reset. - PressBootKeys(); + UCodeMemory.Reset(); } /// @@ -126,18 +123,20 @@ namespace Contralto _diskController.Drives[drive].UnloadPack(); } - public void PressBootKeys() + public void PressBootKeys(AlternateBootType bootType) { - // - // Press bootkeys if the user has specified a boot combination. - // - if (Configuration.EthernetBootEnabled) + switch(bootType) { - _keyboard.PressBootKeys(Configuration.BootAddress, true); + case AlternateBootType.Disk: + _keyboard.PressBootKeys(Configuration.BootAddress, false); + break; + + case AlternateBootType.Ethernet: + _keyboard.PressBootKeys(Configuration.BootFile, true); + break; } } - public AltoCPU CPU { get { return _cpu; } diff --git a/Contralto/Configuration.cs b/Contralto/Configuration.cs index ac99029..0e05b39 100644 --- a/Contralto/Configuration.cs +++ b/Contralto/Configuration.cs @@ -41,6 +41,18 @@ namespace Contralto /// Encapsulate frames inside UDP datagrams on the host interface. /// UDPEncapsulation, + + /// + /// No encapsulation; sent packets are dropped on the floor and no packets are received. + /// + None, + } + + public enum AlternateBootType + { + None, + Disk, + Ethernet, } /// @@ -53,8 +65,9 @@ namespace Contralto // Initialize things to defaults. HostAddress = 0x22; - EthernetBootEnabled = false; + AlternateBootType = AlternateBootType.Disk; BootAddress = 0; + BootFile = 0; SystemType = SystemType.TwoKRom; @@ -98,18 +111,23 @@ namespace Contralto /// /// The type of interface to use to host networking. /// - public static PacketInterfaceType HostPacketInterfaceType; + public static PacketInterfaceType HostPacketInterfaceType; /// - /// Whether to enable Ethernet boot at reset + /// The type of Alternate Boot to apply /// - public static bool EthernetBootEnabled; + public static AlternateBootType AlternateBootType; /// - /// The address/file to boot at reset + /// The address to boot at reset for a disk alternate boot /// public static ushort BootAddress; + /// + /// The file to boot at reset for an ethernet alternate boot + /// + public static ushort BootFile; + /// /// Whether to render the display "interlaced" or not. /// @@ -140,7 +158,7 @@ namespace Contralto while (!configStream.EndOfStream) { lineNumber++; - string line = configStream.ReadLine().ToLowerInvariant().Trim(); + string line = configStream.ReadLine().Trim(); if (string.IsNullOrEmpty(line)) { @@ -161,7 +179,7 @@ namespace Contralto try { - switch (parameter) + switch (parameter.ToLowerInvariant()) { case "drive0image": Drive0Image = value; @@ -187,14 +205,18 @@ namespace Contralto HostPacketInterfaceType = (PacketInterfaceType)Enum.Parse(typeof(PacketInterfaceType), value, true); break; - case "ethernetbootenabled": - EthernetBootEnabled = bool.Parse(value); + case "alternateboottype": + AlternateBootType = (AlternateBootType)Enum.Parse(typeof(AlternateBootType), value, true); break; case "bootaddress": BootAddress = Convert.ToUInt16(value, 8); break; + case "bootfile": + BootFile = Convert.ToUInt16(value, 8); + break; + case "interlacedisplay": InterlaceDisplay = bool.Parse(value); break; @@ -251,8 +273,9 @@ namespace Contralto } configStream.WriteLine("HostPacketInterfaceType {0}", HostPacketInterfaceType); - configStream.WriteLine("EthernetBootEnabled {0}", EthernetBootEnabled); + configStream.WriteLine("AlternateBootType {0}", AlternateBootType); configStream.WriteLine("BootAddress {0}", Conversion.ToOctal(BootAddress)); + configStream.WriteLine("BootFile {0}", Conversion.ToOctal(BootFile)); configStream.WriteLine("InterlaceDisplay {0}", InterlaceDisplay); configStream.WriteLine("ThrottleSpeed {0}", ThrottleSpeed); } diff --git a/Contralto/Disk/allgames.dsk b/Contralto/Disk/allgames.dsk index b33f0be..aa6e380 100644 Binary files a/Contralto/Disk/allgames.dsk and b/Contralto/Disk/allgames.dsk differ diff --git a/Contralto/Disk/diag.dsk b/Contralto/Disk/diag.dsk index a2750d3..8280966 100644 Binary files a/Contralto/Disk/diag.dsk and b/Contralto/Disk/diag.dsk differ diff --git a/Contralto/ExecutionController.cs b/Contralto/ExecutionController.cs index 3f53b16..58aa3ef 100644 --- a/Contralto/ExecutionController.cs +++ b/Contralto/ExecutionController.cs @@ -23,9 +23,10 @@ namespace Contralto } - public void StartExecution() + public void StartExecution(AlternateBootType bootType) { StartAltoExecutionThread(); + _system.PressBootKeys(bootType); } public void StopExecution() @@ -39,7 +40,7 @@ namespace Contralto } } - public void Reset() + public void Reset(AlternateBootType bootType) { bool running = IsRunning; @@ -47,13 +48,13 @@ namespace Contralto { StopExecution(); } - _system.Reset(); + _system.Reset(); + _system.PressBootKeys(bootType); if (running) { - StartExecution(); + StartExecution(AlternateBootType.None); } - } public bool IsRunning diff --git a/Contralto/HighResTimer.cs b/Contralto/HighResTimer.cs index 12ca5b5..b487fce 100644 --- a/Contralto/HighResTimer.cs +++ b/Contralto/HighResTimer.cs @@ -62,7 +62,7 @@ namespace Contralto public static extern bool DeleteTimerQueue(IntPtr hTimerQueue, IntPtr hCompletionEvent); [DllImport("kernel32.dll", EntryPoint = "CreateTimerQueueTimer")] - public static extern bool CreateTimerQueueTimer(out IntPtr phNewTimer, IntPtr hTimerQueue, IntPtr Callback, IntPtr Parameter, UInt32 DueTime, UInt32 Period, ulong Flags); + public static extern bool CreateTimerQueueTimer(out IntPtr phNewTimer, IntPtr hTimerQueue, IntPtr Callback, IntPtr Parameter, UInt32 DueTime, UInt32 Period, uint Flags); [DllImport("kernel32.dll", EntryPoint = "ChangeTimerQueueTimer")] public static extern bool ChangeTimerQueueTimer(IntPtr hTimerQueue, IntPtr hTimer, UInt32 DueTime, UInt32 Period); diff --git a/Contralto/IO/EthernetController.cs b/Contralto/IO/EthernetController.cs index a697cc9..ea1634f 100644 --- a/Contralto/IO/EthernetController.cs +++ b/Contralto/IO/EthernetController.cs @@ -21,25 +21,32 @@ namespace Contralto.IO Reset(); _fifoTransmitWakeupEvent = new Event(_fifoTransmitDuration, null, OutputFifoCallback); - + // Attach real Ethernet device if user has specified one, otherwise leave unattached; output data // will go into a bit-bucket. - switch(Configuration.HostPacketInterfaceType) + try { - case PacketInterfaceType.UDPEncapsulation: - _hostInterface = new UDPEncapsulation(Configuration.HostPacketInterfaceName); - _hostInterface.RegisterReceiveCallback(OnHostPacketReceived); - break; + switch (Configuration.HostPacketInterfaceType) + { + case PacketInterfaceType.UDPEncapsulation: + _hostInterface = new UDPEncapsulation(Configuration.HostPacketInterfaceName); + _hostInterface.RegisterReceiveCallback(OnHostPacketReceived); + break; - case PacketInterfaceType.EthernetEncapsulation: - _hostInterface = new HostEthernetEncapsulation(Configuration.HostPacketInterfaceName); - _hostInterface.RegisterReceiveCallback(OnHostPacketReceived); - break; + case PacketInterfaceType.EthernetEncapsulation: + _hostInterface = new HostEthernetEncapsulation(Configuration.HostPacketInterfaceName); + _hostInterface.RegisterReceiveCallback(OnHostPacketReceived); + break; - default: - _hostInterface = null; - break; + default: + _hostInterface = null; + break; + } + } + catch + { + _hostInterface = null; } // More words than the Alto will ever send. @@ -359,7 +366,9 @@ namespace Contralto.IO } else { - Log.Write(LogType.Error, LogComponent.EthernetPacket, "Packet queue has reached its limit of {0} packets, dropping incoming packet.", _maxQueuedPackets); + Log.Write(LogType.Error, LogComponent.EthernetPacket, "Input packet queue has reached its limit of {0} packets, dropping oldest packet.", _maxQueuedPackets); + _nextPackets.Dequeue(); + _nextPackets.Enqueue(data); } _receiverLock.ExitWriteLock(); @@ -367,7 +376,7 @@ namespace Contralto.IO /// /// Runs the input state machine. This runs periodically (as scheduled by the Scheduler) and: - /// 1) Drops incoming packets if the interface is off + /// 1) Ignores incoming packets if the receiver 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 /// @@ -379,13 +388,16 @@ namespace Contralto.IO switch(_inputState) { case InputState.ReceiverOff: - // Receiver is off, if we have any incoming packets, drop the first. + // Receiver is off, if we have any incoming packets, they are ignored. + // TODO: would it make sense to expire really old packets (say more than a couple of seconds old) + // so that the receiver doesn't pick up ancient history the next time it runs? + // We already cycle out packets as new ones come in, so this would only be an issue on very quiet networks. + // (And even then I don't know if it's really an issue.) _receiverLock.EnterReadLock(); if (_nextPackets.Count > 0) { - _nextPackets.Dequeue(); - Log.Write(LogComponent.EthernetPacket, "Receiver is off, dropped incoming packet from packet queue."); + Log.Write(LogComponent.EthernetPacket, "Receiver is off, ignoring incoming packet from packet queue."); } _receiverLock.ExitReadLock(); break; diff --git a/Contralto/IO/HostEthernet.cs b/Contralto/IO/HostEthernet.cs new file mode 100644 index 0000000..f6a9617 --- /dev/null +++ b/Contralto/IO/HostEthernet.cs @@ -0,0 +1,281 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PcapDotNet.Base; +using PcapDotNet.Core; +using PcapDotNet.Core.Extensions; +using PcapDotNet.Packets; +using PcapDotNet.Packets.Ethernet; +using System.IO; +using Contralto.Logging; +using System.Threading; + +namespace Contralto.IO +{ + + public struct EthernetInterface + { + public EthernetInterface(string name, string description, MacAddress macAddress) + { + Name = name; + Description = description; + MacAddress = macAddress; + } + + public static List EnumerateDevices() + { + List interfaces = new List(); + + foreach (LivePacketDevice device in LivePacketDevice.AllLocalMachine) + { + interfaces.Add(new EthernetInterface(device.Name, device.Description, device.GetMacAddress())); + } + + return interfaces; + } + + public string Name; + public string Description; + public MacAddress MacAddress; + } + + public delegate void ReceivePacketDelegate(MemoryStream data); + + /// + /// Implements the logic for encapsulating a 3mbit ethernet packet into a 10mb packet and sending it over an actual + /// interface controlled by the host operating system. + /// + /// This uses PCap.NET to do the dirty work. + /// + public class HostEthernet + { + public HostEthernet(EthernetInterface iface) + { + AttachInterface(iface); + } + + public HostEthernet(string name) + { + // Find the specified device by name + List interfaces = EthernetInterface.EnumerateDevices(); + + foreach (EthernetInterface i in interfaces) + { + if (name == i.Name) + { + AttachInterface(i); + return; + } + } + + throw new InvalidOperationException("Specified ethernet interface does not exist."); + } + + public void RegisterReceiveCallback(ReceivePacketDelegate callback) + { + _callback = callback; + + // Now that we have a callback we can start receiving stuff. + Open(true /* promiscuous */, int.MaxValue); + BeginReceive(); + } + + + /// + /// Sends an array of bytes over the ethernet as a 3mbit packet encapsulated in a 10mbit packet. + /// + /// + /// + public void Send(ushort[] packet, int length) + { + // Sanity check. + if (length < 1) + { + throw new InvalidOperationException("Raw packet data must contain at least two bytes for addressing."); + } + + + // + // 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); + packetBytes[1] = (byte)((length) >> 8); + + // + // Do this annoying dance to stuff the ushorts into bytes because this is C#. + // + for (int i = 0; i < length; i++) + { + packetBytes[i * 2 + 2] = (byte)(packet[i]); + packetBytes[i * 2 + 3] = (byte)(packet[i] >> 8); + } + + // + // Grab the source and destination host addresses from the packet we're sending + // and build 10mbit versions. + // + byte destinationHost = packetBytes[3]; + byte sourceHost = packetBytes[2]; + + Log.Write(LogComponent.HostEthernet, "Sending packet; source {0} destination {1}, length {2} words.", + Conversion.ToOctal(sourceHost), + Conversion.ToOctal(destinationHost), + length); + + 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. + EthernetLayer ethernetLayer = new EthernetLayer + { + Source = sourceMac, + Destination = destinationMac, + EtherType = (EthernetType)_3mbitFrameType, + }; + + PayloadLayer payloadLayer = new PayloadLayer + { + Data = new Datagram(packetBytes), + }; + + PacketBuilder builder = new PacketBuilder(ethernetLayer, payloadLayer); + + // Send it over the 'net! + _communicator.SendPacket(builder.Build(DateTime.Now)); + + Log.Write(LogComponent.HostEthernet, "Encapsulated 3mbit packet sent."); + } + + private void ReceiveCallback(Packet p) + { + // + // Filter out packets intended for the emulator, forward them on, drop everything else. + // + 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()); + } + else + { + // Not for us, discard the packet. + } + } + + private void AttachInterface(EthernetInterface iface) + { + _interface = null; + + // Find the specified device by name + foreach (LivePacketDevice device in LivePacketDevice.AllLocalMachine) + { + if (device.Name == iface.Name && device.GetMacAddress() == iface.MacAddress) + { + _interface = device; + break; + } + } + + if (_interface == null) + { + throw new InvalidOperationException("Requested interface not found."); + } + + Log.Write(LogComponent.HostEthernet, "Attached to host interface {0}", iface.Name); + } + + private void Open(bool promiscuous, int 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); + + Log.Write(LogComponent.HostEthernet, "Host interface opened and receiving packets."); + } + + /// + /// Begin receiving packets, forever. + /// + private void BeginReceive() + { + // Kick off receive thread. + _receiveThread = new Thread(ReceiveThread); + _receiveThread.Start(); + } + + private void ReceiveThread() + { + // Just call ReceivePackets, that's it. This will never return. + // (probably need to make this more elegant so we can tear down the thread + // properly.) + Log.Write(LogComponent.HostEthernet, "Receiver thread started."); + _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; + + + // Thread used for receive + private Thread _receiveThread; + + private const int _3mbitFrameType = 0xbeef; // easy to identify, ostensibly unused by anything of any import + + /// + /// 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 + /// + 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; + } +} diff --git a/Contralto/IO/HostEthernetEncapsulation.cs b/Contralto/IO/HostEthernetEncapsulation.cs index f045381..3ff7821 100644 --- a/Contralto/IO/HostEthernetEncapsulation.cs +++ b/Contralto/IO/HostEthernetEncapsulation.cs @@ -65,7 +65,7 @@ namespace Contralto.IO foreach (EthernetInterface i in interfaces) { - if (name == i.Name) + if (name == i.Description) { AttachInterface(i); return; @@ -183,7 +183,7 @@ namespace Contralto.IO // Find the specified device by name foreach (LivePacketDevice device in LivePacketDevice.AllLocalMachine) { - if (device.Description == iface.Name) + if (device.Description == iface.Description) { _interface = device; break; diff --git a/Contralto/IO/Keyboard.cs b/Contralto/IO/Keyboard.cs index 1d34665..d9c25f5 100644 --- a/Contralto/IO/Keyboard.cs +++ b/Contralto/IO/Keyboard.cs @@ -119,8 +119,7 @@ namespace Contralto.IO // If we had been holding boot keys, release them now that a real user is pressing a key. if (_bootKeysPressed) { - Reset(); - _bootKeysPressed = false; + Reset(); } AltoKeyBit bits = _keyMap[key]; diff --git a/Contralto/IO/UDPEncapsulation.cs b/Contralto/IO/UDPEncapsulation.cs index fc571e1..3ced3ee 100644 --- a/Contralto/IO/UDPEncapsulation.cs +++ b/Contralto/IO/UDPEncapsulation.cs @@ -21,6 +21,8 @@ namespace Contralto.IO { _udpClient = new UdpClient(_udpPort, AddressFamily.InterNetwork); _udpClient.EnableBroadcast = true; + _udpClient.Client.Blocking = true; + _udpClient.Client.MulticastLoopback = false; // // Grab the broadcast address for the interface so that we know what broadcast address to use @@ -31,7 +33,7 @@ namespace Contralto.IO IPInterfaceProperties props = null; foreach(NetworkInterface nic in nics) { - if (nic.Description.ToLowerInvariant() == interfaceName.ToLowerInvariant()) + if (nic.Description == interfaceName) { props = nic.GetIPProperties(); break; @@ -49,7 +51,8 @@ namespace Contralto.IO // go with it. if (unicast.Address.AddressFamily == AddressFamily.InterNetwork) { - _broadcastEndpoint = new IPEndPoint(GetBroadcastAddress(unicast.Address, unicast.IPv4Mask), _udpPort); + _thisIPAddress = unicast.Address; + _broadcastEndpoint = new IPEndPoint(GetBroadcastAddress(_thisIPAddress, unicast.IPv4Mask), _udpPort); break; } } @@ -173,8 +176,12 @@ namespace Contralto.IO // TODO: sanitize data before handing it off. - Log.Write(LogComponent.HostNetworkInterface, "Received UDP-encapsulated 3mbit packet."); - _callback(new System.IO.MemoryStream(data)); + // Drop our own UDP packets. + if (!groupEndPoint.Address.Equals(_thisIPAddress)) + { + Log.Write(LogComponent.HostNetworkInterface, "Received UDP-encapsulated 3mbit packet."); + _callback(new System.IO.MemoryStream(data)); + } } } @@ -204,5 +211,7 @@ namespace Contralto.IO private UdpClient _udpClient; private IPEndPoint _broadcastEndpoint; + // The IP address (unicast address) of the interface we're using to send UDP datagrams. + private IPAddress _thisIPAddress; } } diff --git a/Contralto/Program.cs b/Contralto/Program.cs index b52c998..224e2f7 100644 --- a/Contralto/Program.cs +++ b/Contralto/Program.cs @@ -21,12 +21,28 @@ namespace Contralto if (!String.IsNullOrEmpty(Configuration.Drive0Image)) { - system.LoadDrive(0, Configuration.Drive0Image); + try + { + system.LoadDrive(0, Configuration.Drive0Image); + } + catch(Exception e) + { + Console.WriteLine("Could not load image '{0}' for drive 0. Error '{1}'.", Configuration.Drive0Image, e.Message); + system.UnloadDrive(0); + } } if (!String.IsNullOrEmpty(Configuration.Drive1Image)) { - system.LoadDrive(1, Configuration.Drive1Image); + try + { + system.LoadDrive(1, Configuration.Drive0Image); + } + catch (Exception e) + { + Console.WriteLine("Could not load image '{0}' for drive 1. Error '{1}'.", Configuration.Drive1Image, e.Message); + system.UnloadDrive(1); + } } AltoWindow mainWindow = new AltoWindow(); @@ -57,7 +73,7 @@ namespace Contralto catch { Console.WriteLine("WARNING: WinPCAP does not appear to be properly installed."); - Console.WriteLine(" Ethernet functionality is disabled."); + Console.WriteLine(" Raw Ethernet functionality will be disabled."); Console.WriteLine(" Please install WinPCAP from: http://www.winpcap.org/"); Configuration.HostRawEthernetInterfacesAvailable = false; diff --git a/Contralto/UI/AlternateBootWindow.Designer.cs b/Contralto/UI/AlternateBootWindow.Designer.cs index d4bf01e..cc2c973 100644 --- a/Contralto/UI/AlternateBootWindow.Designer.cs +++ b/Contralto/UI/AlternateBootWindow.Designer.cs @@ -28,45 +28,41 @@ /// private void InitializeComponent() { - this.EthernetBootEnabled = new System.Windows.Forms.CheckBox(); - this.BootFileGroup = new System.Windows.Forms.GroupBox(); + this.EthernetBootFileGroup = 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.groupBox1 = new System.Windows.Forms.GroupBox(); + this.EthernetBootRadioButton = new System.Windows.Forms.RadioButton(); + this.DiskBootRadioButton = new System.Windows.Forms.RadioButton(); + this.DiskBootGroupBox = new System.Windows.Forms.GroupBox(); + this.DiskBootAddressTextBox = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.EthernetBootFileGroup.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.DiskBootGroupBox.SuspendLayout(); this.SuspendLayout(); // - // EthernetBootEnabled + // EthernetBootFileGroup // - 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"; + this.EthernetBootFileGroup.Controls.Add(this.label1); + this.EthernetBootFileGroup.Controls.Add(this.BootFileComboBox); + this.EthernetBootFileGroup.Location = new System.Drawing.Point(4, 106); + this.EthernetBootFileGroup.Name = "EthernetBootFileGroup"; + this.EthernetBootFileGroup.Size = new System.Drawing.Size(397, 62); + this.EthernetBootFileGroup.TabIndex = 1; + this.EthernetBootFileGroup.TabStop = false; + this.EthernetBootFileGroup.Text = "Ethernet Boot File"; // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(6, 16); + this.label1.Location = new System.Drawing.Point(3, 16); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(359, 13); + this.label1.Size = new System.Drawing.Size(356, 13); this.label1.TabIndex = 1; - this.label1.Text = "Select a standard boot file number below, or enter a custom value in octal. "; + this.label1.Text = "Select a standard boot file number below, or enter a custom value in octal:"; // // BootFileComboBox // @@ -81,7 +77,7 @@ // // OKButton // - this.OKButton.Location = new System.Drawing.Point(245, 103); + this.OKButton.Location = new System.Drawing.Point(245, 174); this.OKButton.Name = "OKButton"; this.OKButton.Size = new System.Drawing.Size(75, 23); this.OKButton.TabIndex = 2; @@ -91,7 +87,7 @@ // // CancelButton // - this.CancelButton.Location = new System.Drawing.Point(326, 103); + this.CancelButton.Location = new System.Drawing.Point(326, 174); this.CancelButton.Name = "CancelButton"; this.CancelButton.Size = new System.Drawing.Size(75, 23); this.CancelButton.TabIndex = 3; @@ -99,35 +95,105 @@ this.CancelButton.UseVisualStyleBackColor = true; this.CancelButton.Click += new System.EventHandler(this.CancelButton_Click); // + // groupBox1 + // + this.groupBox1.Controls.Add(this.EthernetBootRadioButton); + this.groupBox1.Controls.Add(this.DiskBootRadioButton); + this.groupBox1.Location = new System.Drawing.Point(4, 9); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(397, 43); + this.groupBox1.TabIndex = 4; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Alternate Boot Type"; + // + // EthernetBootRadioButton + // + this.EthernetBootRadioButton.AutoSize = true; + this.EthernetBootRadioButton.Location = new System.Drawing.Point(86, 20); + this.EthernetBootRadioButton.Name = "EthernetBootRadioButton"; + this.EthernetBootRadioButton.Size = new System.Drawing.Size(90, 17); + this.EthernetBootRadioButton.TabIndex = 1; + this.EthernetBootRadioButton.TabStop = true; + this.EthernetBootRadioButton.Text = "Ethernet Boot"; + this.EthernetBootRadioButton.UseVisualStyleBackColor = true; + + // + // DiskBootRadioButton + // + this.DiskBootRadioButton.AutoSize = true; + this.DiskBootRadioButton.Location = new System.Drawing.Point(9, 20); + this.DiskBootRadioButton.Name = "DiskBootRadioButton"; + this.DiskBootRadioButton.Size = new System.Drawing.Size(71, 17); + this.DiskBootRadioButton.TabIndex = 0; + this.DiskBootRadioButton.TabStop = true; + this.DiskBootRadioButton.Text = "Disk Boot"; + this.DiskBootRadioButton.UseVisualStyleBackColor = true; + + // + // DiskBootGroupBox + // + this.DiskBootGroupBox.Controls.Add(this.DiskBootAddressTextBox); + this.DiskBootGroupBox.Controls.Add(this.label2); + this.DiskBootGroupBox.Location = new System.Drawing.Point(4, 58); + this.DiskBootGroupBox.Name = "DiskBootGroupBox"; + this.DiskBootGroupBox.Size = new System.Drawing.Size(397, 42); + this.DiskBootGroupBox.TabIndex = 2; + this.DiskBootGroupBox.TabStop = false; + this.DiskBootGroupBox.Text = "Disk Boot Address"; + // + // DiskBootAddressTextBox + // + this.DiskBootAddressTextBox.Location = new System.Drawing.Point(186, 13); + this.DiskBootAddressTextBox.Name = "DiskBootAddressTextBox"; + this.DiskBootAddressTextBox.Size = new System.Drawing.Size(94, 20); + this.DiskBootAddressTextBox.TabIndex = 2; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(3, 16); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(177, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Enter the octal disk address to boot:"; + // // AlternateBootOptions // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(403, 128); + this.ClientSize = new System.Drawing.Size(406, 201); + this.Controls.Add(this.DiskBootGroupBox); + this.Controls.Add(this.groupBox1); this.Controls.Add(this.CancelButton); this.Controls.Add(this.OKButton); - this.Controls.Add(this.BootFileGroup); - this.Controls.Add(this.EthernetBootEnabled); + this.Controls.Add(this.EthernetBootFileGroup); this.Name = "AlternateBootOptions"; 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.Text = "Alternate Boot Options"; + this.EthernetBootFileGroup.ResumeLayout(false); + this.EthernetBootFileGroup.PerformLayout(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.DiskBootGroupBox.ResumeLayout(false); + this.DiskBootGroupBox.PerformLayout(); this.ResumeLayout(false); - this.PerformLayout(); } #endregion - - private System.Windows.Forms.CheckBox EthernetBootEnabled; - private System.Windows.Forms.GroupBox BootFileGroup; + private System.Windows.Forms.GroupBox EthernetBootFileGroup; private System.Windows.Forms.Label label1; private System.Windows.Forms.ComboBox BootFileComboBox; private System.Windows.Forms.Button OKButton; private System.Windows.Forms.Button CancelButton; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.RadioButton EthernetBootRadioButton; + private System.Windows.Forms.RadioButton DiskBootRadioButton; + private System.Windows.Forms.GroupBox DiskBootGroupBox; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox DiskBootAddressTextBox; } } \ No newline at end of file diff --git a/Contralto/UI/AlternateBootWindow.cs b/Contralto/UI/AlternateBootWindow.cs index cf5bbc8..9b65f7c 100644 --- a/Contralto/UI/AlternateBootWindow.cs +++ b/Contralto/UI/AlternateBootWindow.cs @@ -14,16 +14,22 @@ namespace Contralto { public AlternateBootOptions() { - InitializeComponent(); - + InitializeComponent(); + LoadBootEntries(); - BootFileGroup.Enabled = EthernetBootEnabled.Checked = Configuration.EthernetBootEnabled; - - SelectBootFile(Configuration.BootAddress); - - } + if (Configuration.AlternateBootType == AlternateBootType.Disk) + { + DiskBootRadioButton.Checked = true; + } + else + { + EthernetBootRadioButton.Checked = true; + } + SetBootAddress(Configuration.BootAddress); + SelectBootFile(Configuration.BootFile); + } private void LoadBootEntries() { @@ -55,18 +61,33 @@ namespace Contralto } } + private void SetBootAddress(ushort address) + { + DiskBootAddressTextBox.Text = Conversion.ToOctal(address); + } + private void BootFileComboBox_SelectedIndexChanged(object sender, EventArgs e) { - _selectedBoot = ((BootFileEntry)BootFileComboBox.SelectedItem).FileNumber; - } + _selectedBootFile = ((BootFileEntry)BootFileComboBox.SelectedItem).FileNumber; + } private void OKButton_Click(object sender, EventArgs e) { + try + { + _selectedBootAddress = Convert.ToUInt16(DiskBootAddressTextBox.Text, 8); + } + catch + { + MessageBox.Show("The disk boot address must be an octal value between 0 and 177777."); + return; + } + if (BootFileComboBox.SelectedItem == null) { try { - _selectedBoot = Convert.ToUInt16(BootFileComboBox.Text, 8); + _selectedBootFile = Convert.ToUInt16(BootFileComboBox.Text, 8); } catch { @@ -76,11 +97,20 @@ namespace Contralto } else { - _selectedBoot = ((BootFileEntry)BootFileComboBox.SelectedItem).FileNumber; + _selectedBootFile = ((BootFileEntry)BootFileComboBox.SelectedItem).FileNumber; } + + Configuration.BootAddress = _selectedBootAddress; + Configuration.BootFile = _selectedBootFile; - Configuration.BootAddress = _selectedBoot; - Configuration.EthernetBootEnabled = _bootEnabled; + if (DiskBootRadioButton.Checked) + { + Configuration.AlternateBootType = AlternateBootType.Disk; + } + else + { + Configuration.AlternateBootType = AlternateBootType.Ethernet; + } this.Close(); } @@ -88,12 +118,7 @@ namespace Contralto 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[] { @@ -118,8 +143,8 @@ namespace Contralto - private ushort _selectedBoot; - private bool _bootEnabled; + private ushort _selectedBootFile; + private ushort _selectedBootAddress; } diff --git a/Contralto/UI/AltoWindow.Designer.cs b/Contralto/UI/AltoWindow.Designer.cs index 1777900..c27cdf9 100644 --- a/Contralto/UI/AltoWindow.Designer.cs +++ b/Contralto/UI/AltoWindow.Designer.cs @@ -44,7 +44,7 @@ this.loadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.unloadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.Drive1ImageName = new System.Windows.Forms.ToolStripMenuItem(); - this.enableAlternateBootToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.AlternateBootToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.SystemEthernetBootMenu = new System.Windows.Forms.ToolStripMenuItem(); this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.SystemShowDebuggerMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -88,7 +88,7 @@ this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.exitToolStripMenuItem}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; - this.fileToolStripMenuItem.Size = new System.Drawing.Size(35, 20); + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); this.fileToolStripMenuItem.Text = "File"; // // exitToolStripMenuItem @@ -105,12 +105,12 @@ this.SystemResetMenuItem, this.drive0ToolStripMenuItem, this.drive1ToolStripMenuItem, - this.enableAlternateBootToolStripMenuItem, + this.AlternateBootToolStripMenuItem, this.SystemEthernetBootMenu, this.optionsToolStripMenuItem, this.SystemShowDebuggerMenuItem}); this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem"; - this.settingsToolStripMenuItem.Size = new System.Drawing.Size(54, 20); + this.settingsToolStripMenuItem.Size = new System.Drawing.Size(57, 20); this.settingsToolStripMenuItem.Text = "System"; // // SystemStartMenuItem @@ -118,7 +118,7 @@ this.SystemStartMenuItem.Name = "SystemStartMenuItem"; this.SystemStartMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Alt) | System.Windows.Forms.Keys.S))); - this.SystemStartMenuItem.Size = new System.Drawing.Size(210, 22); + this.SystemStartMenuItem.Size = new System.Drawing.Size(223, 22); this.SystemStartMenuItem.Text = "Start"; this.SystemStartMenuItem.Click += new System.EventHandler(this.OnSystemStartMenuClick); // @@ -128,7 +128,7 @@ this.SystemResetMenuItem.Name = "SystemResetMenuItem"; this.SystemResetMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Alt) | System.Windows.Forms.Keys.R))); - this.SystemResetMenuItem.Size = new System.Drawing.Size(210, 22); + this.SystemResetMenuItem.Size = new System.Drawing.Size(223, 22); this.SystemResetMenuItem.Text = "Reset"; this.SystemResetMenuItem.Click += new System.EventHandler(this.OnSystemResetMenuClick); // @@ -139,7 +139,7 @@ this.unloadToolStripMenuItem1, this.Drive0ImageName}); this.drive0ToolStripMenuItem.Name = "drive0ToolStripMenuItem"; - this.drive0ToolStripMenuItem.Size = new System.Drawing.Size(210, 22); + this.drive0ToolStripMenuItem.Size = new System.Drawing.Size(223, 22); this.drive0ToolStripMenuItem.Text = "Drive 0"; // // loadToolStripMenuItem1 @@ -147,14 +147,14 @@ this.loadToolStripMenuItem1.Name = "loadToolStripMenuItem1"; this.loadToolStripMenuItem1.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Alt) | System.Windows.Forms.Keys.L))); - this.loadToolStripMenuItem1.Size = new System.Drawing.Size(167, 22); + this.loadToolStripMenuItem1.Size = new System.Drawing.Size(172, 22); this.loadToolStripMenuItem1.Text = "Load..."; this.loadToolStripMenuItem1.Click += new System.EventHandler(this.OnSystemDrive0LoadClick); // // unloadToolStripMenuItem1 // this.unloadToolStripMenuItem1.Name = "unloadToolStripMenuItem1"; - this.unloadToolStripMenuItem1.Size = new System.Drawing.Size(167, 22); + this.unloadToolStripMenuItem1.Size = new System.Drawing.Size(172, 22); this.unloadToolStripMenuItem1.Text = "Unload..."; this.unloadToolStripMenuItem1.Click += new System.EventHandler(this.OnSystemDrive0UnloadClick); // @@ -162,7 +162,7 @@ // this.Drive0ImageName.Enabled = false; this.Drive0ImageName.Name = "Drive0ImageName"; - this.Drive0ImageName.Size = new System.Drawing.Size(167, 22); + this.Drive0ImageName.Size = new System.Drawing.Size(172, 22); this.Drive0ImageName.Text = "Image Name"; // // drive1ToolStripMenuItem @@ -172,20 +172,20 @@ this.unloadToolStripMenuItem, this.Drive1ImageName}); this.drive1ToolStripMenuItem.Name = "drive1ToolStripMenuItem"; - this.drive1ToolStripMenuItem.Size = new System.Drawing.Size(210, 22); + this.drive1ToolStripMenuItem.Size = new System.Drawing.Size(223, 22); this.drive1ToolStripMenuItem.Text = "Drive 1"; // // loadToolStripMenuItem // this.loadToolStripMenuItem.Name = "loadToolStripMenuItem"; - this.loadToolStripMenuItem.Size = new System.Drawing.Size(134, 22); + this.loadToolStripMenuItem.Size = new System.Drawing.Size(142, 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(142, 22); this.unloadToolStripMenuItem.Text = "Unload..."; this.unloadToolStripMenuItem.Click += new System.EventHandler(this.OnSystemDrive1UnloadClick); // @@ -193,27 +193,28 @@ // this.Drive1ImageName.Enabled = false; this.Drive1ImageName.Name = "Drive1ImageName"; - this.Drive1ImageName.Size = new System.Drawing.Size(134, 22); + this.Drive1ImageName.Size = new System.Drawing.Size(142, 22); this.Drive1ImageName.Text = "Image Name"; // - // enableAlternateBootToolStripMenuItem + // AlternateBootToolStripMenuItem // - this.enableAlternateBootToolStripMenuItem.Name = "enableAlternateBootToolStripMenuItem"; - this.enableAlternateBootToolStripMenuItem.Size = new System.Drawing.Size(210, 22); - this.enableAlternateBootToolStripMenuItem.Text = "Enable Alternate Boot"; + this.AlternateBootToolStripMenuItem.Name = "AlternateBootToolStripMenuItem"; + this.AlternateBootToolStripMenuItem.Size = new System.Drawing.Size(223, 22); + this.AlternateBootToolStripMenuItem.Text = "Start with Alternate Boot"; + this.AlternateBootToolStripMenuItem.Click += new System.EventHandler(this.OnStartWithAlternateBootClicked); // // SystemEthernetBootMenu // this.SystemEthernetBootMenu.Name = "SystemEthernetBootMenu"; - this.SystemEthernetBootMenu.Size = new System.Drawing.Size(210, 22); + this.SystemEthernetBootMenu.Size = new System.Drawing.Size(223, 22); this.SystemEthernetBootMenu.Text = "Alternate Boot Options..."; this.SystemEthernetBootMenu.Click += new System.EventHandler(this.OnAlternateBootOptionsClicked); // // optionsToolStripMenuItem // this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem"; - this.optionsToolStripMenuItem.Size = new System.Drawing.Size(210, 22); - this.optionsToolStripMenuItem.Text = "Options..."; + this.optionsToolStripMenuItem.Size = new System.Drawing.Size(223, 22); + this.optionsToolStripMenuItem.Text = "System Configuration..."; this.optionsToolStripMenuItem.Click += new System.EventHandler(this.OnSystemOptionsClick); // // SystemShowDebuggerMenuItem @@ -221,7 +222,7 @@ this.SystemShowDebuggerMenuItem.Name = "SystemShowDebuggerMenuItem"; this.SystemShowDebuggerMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Alt) | System.Windows.Forms.Keys.D))); - this.SystemShowDebuggerMenuItem.Size = new System.Drawing.Size(210, 22); + this.SystemShowDebuggerMenuItem.Size = new System.Drawing.Size(223, 22); this.SystemShowDebuggerMenuItem.Text = "Show Debugger"; this.SystemShowDebuggerMenuItem.Click += new System.EventHandler(this.OnDebuggerShowClick); // @@ -230,13 +231,13 @@ this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.aboutToolStripMenuItem}); this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; - this.helpToolStripMenuItem.Size = new System.Drawing.Size(40, 20); + this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20); this.helpToolStripMenuItem.Text = "Help"; // // aboutToolStripMenuItem // this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; - this.aboutToolStripMenuItem.Size = new System.Drawing.Size(103, 22); + this.aboutToolStripMenuItem.Size = new System.Drawing.Size(107, 22); this.aboutToolStripMenuItem.Text = "About"; this.aboutToolStripMenuItem.Click += new System.EventHandler(this.OnHelpAboutClick); // @@ -256,19 +257,19 @@ // CaptureStatusLabel // this.CaptureStatusLabel.Name = "CaptureStatusLabel"; - this.CaptureStatusLabel.Size = new System.Drawing.Size(102, 17); + this.CaptureStatusLabel.Size = new System.Drawing.Size(109, 17); this.CaptureStatusLabel.Text = "CaptureStatusLabel"; // // SystemStatusLabel // this.SystemStatusLabel.Name = "SystemStatusLabel"; - this.SystemStatusLabel.Size = new System.Drawing.Size(98, 17); + this.SystemStatusLabel.Size = new System.Drawing.Size(105, 17); this.SystemStatusLabel.Text = "SystemStatusLabel"; // // DiskStatusLabel // this.DiskStatusLabel.Name = "DiskStatusLabel"; - this.DiskStatusLabel.Size = new System.Drawing.Size(82, 17); + this.DiskStatusLabel.Size = new System.Drawing.Size(89, 17); this.DiskStatusLabel.Text = "DiskStatusLabel"; // // AltoWindow @@ -328,6 +329,6 @@ private System.Windows.Forms.ToolStripStatusLabel SystemStatusLabel; private System.Windows.Forms.ToolStripStatusLabel DiskStatusLabel; private System.Windows.Forms.ToolStripMenuItem SystemEthernetBootMenu; - private System.Windows.Forms.ToolStripMenuItem enableAlternateBootToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem AlternateBootToolStripMenuItem; } } \ No newline at end of file diff --git a/Contralto/UI/AltoWindow.cs b/Contralto/UI/AltoWindow.cs index 41e5597..25acab9 100644 --- a/Contralto/UI/AltoWindow.cs +++ b/Contralto/UI/AltoWindow.cs @@ -47,8 +47,8 @@ namespace Contralto _controller.ErrorCallback += OnExecutionError; // Update disk image UI info - Drive0ImageName.Text = _system.DiskController.Drives[0].IsLoaded ? System.IO.Path.GetFileName(_system.DiskController.Drives[0].Pack.PackName) : _noImageLoadedText; - Drive1ImageName.Text = _system.DiskController.Drives[1].IsLoaded ? System.IO.Path.GetFileName(_system.DiskController.Drives[1].Pack.PackName) : _noImageLoadedText; + Drive0ImageName.Text = _system.DiskController.Drives[0].IsLoaded ? Path.GetFileName(_system.DiskController.Drives[0].Pack.PackName) : _noImageLoadedText; + Drive1ImageName.Text = _system.DiskController.Drives[1].IsLoaded ? Path.GetFileName(_system.DiskController.Drives[1].Pack.PackName) : _noImageLoadedText; } /// @@ -58,21 +58,25 @@ namespace Contralto /// private void OnSystemStartMenuClick(object sender, EventArgs e) { - // Disable "Start" menu item - SystemStartMenuItem.Enabled = false; + StartSystem(AlternateBootType.None); + } - // Enable "Reset" menu item - SystemResetMenuItem.Enabled = true; + private void OnStartWithAlternateBootClicked(object sender, EventArgs e) + { + if (_controller.IsRunning) + { + _controller.Reset(Configuration.AlternateBootType); + } + else + { + StartSystem(Configuration.AlternateBootType); + } - _controller.StartExecution(); - - SystemStatusLabel.Text = _systemRunningText; - - } + } private void OnSystemResetMenuClick(object sender, EventArgs e) { - _controller.Reset(); + _controller.Reset(AlternateBootType.None); } private void OnSystemDrive0LoadClick(object sender, EventArgs e) @@ -90,6 +94,7 @@ namespace Contralto CommitDiskPack(0); _system.LoadDrive(0, path); Drive0ImageName.Text = System.IO.Path.GetFileName(path); + Configuration.Drive0Image = path; } catch(Exception ex) { @@ -104,6 +109,7 @@ namespace Contralto CommitDiskPack(0); _system.UnloadDrive(0); Drive0ImageName.Text = _noImageLoadedText; + Configuration.Drive0Image = String.Empty; } private void OnSystemDrive1LoadClick(object sender, EventArgs e) @@ -121,6 +127,7 @@ namespace Contralto CommitDiskPack(1); _system.LoadDrive(1, path); Drive1ImageName.Text = System.IO.Path.GetFileName(path); + Configuration.Drive1Image = path; } catch (Exception ex) { @@ -135,17 +142,13 @@ namespace Contralto CommitDiskPack(1); _system.UnloadDrive(1); Drive1ImageName.Text = _noImageLoadedText; + Configuration.Drive1Image = String.Empty; } private void OnAlternateBootOptionsClicked(object sender, EventArgs e) { AlternateBootOptions bootWindow = new AlternateBootOptions(); - bootWindow.ShowDialog(); - - // - // Apply settings to system. - // - _system.PressBootKeys(); + bootWindow.ShowDialog(); } private void OnSystemOptionsClick(object sender, EventArgs e) @@ -206,6 +209,9 @@ namespace Contralto CommitDiskPack(0); CommitDiskPack(1); + // Commit current configuration to disk + Configuration.WriteConfiguration(); + this.Dispose(); Application.Exit(); } @@ -268,6 +274,19 @@ namespace Contralto } } + private void StartSystem(AlternateBootType bootType) + { + // Disable "Start" menu item + SystemStartMenuItem.Enabled = false; + + // Enable "Reset" menu item + SystemResetMenuItem.Enabled = true; + + _controller.StartExecution(bootType); + + SystemStatusLabel.Text = _systemRunningText; + } + // // Display handling // diff --git a/Contralto/UI/Debugger.cs b/Contralto/UI/Debugger.cs index 73f0401..f67d78e 100644 --- a/Contralto/UI/Debugger.cs +++ b/Contralto/UI/Debugger.cs @@ -718,7 +718,7 @@ namespace Contralto { _execType = ExecutionType.Step; SetExecutionState(ExecutionState.SingleStep); - _controller.StartExecution(); + _controller.StartExecution(AlternateBootType.None); } private void OnAutoStepButtonClicked(object sender, EventArgs e) @@ -729,7 +729,7 @@ namespace Contralto // _execType = ExecutionType.Auto; SetExecutionState(ExecutionState.AutoStep); - _controller.StartExecution(); + _controller.StartExecution(AlternateBootType.None); } private void RunButton_Click(object sender, EventArgs e) @@ -740,14 +740,14 @@ namespace Contralto // _execType = ExecutionType.Normal; SetExecutionState(ExecutionState.Running); - _controller.StartExecution(); + _controller.StartExecution(AlternateBootType.None); } private void RunToNextTaskButton_Click(object sender, EventArgs e) { _execType = ExecutionType.NextTask; SetExecutionState(ExecutionState.Running); - _controller.StartExecution(); + _controller.StartExecution(AlternateBootType.None); } /// @@ -762,7 +762,7 @@ namespace Contralto { _execType = ExecutionType.NextNovaInstruction; SetExecutionState(ExecutionState.Running); - _controller.StartExecution(); + _controller.StartExecution(AlternateBootType.None); } @@ -775,7 +775,7 @@ namespace Contralto private void ResetButton_Click(object sender, EventArgs e) { - _controller.Reset(); + _controller.Reset(AlternateBootType.None); Refresh(); } diff --git a/Contralto/UI/SystemOptions.Designer.cs b/Contralto/UI/SystemOptions.Designer.cs index 7df345f..fe1b9a4 100644 --- a/Contralto/UI/SystemOptions.Designer.cs +++ b/Contralto/UI/SystemOptions.Designer.cs @@ -48,6 +48,7 @@ this.InterlaceDisplayCheckBox = new System.Windows.Forms.CheckBox(); this.OKButton = new System.Windows.Forms.Button(); this.CancelButton = new System.Windows.Forms.Button(); + this.NoEncapsulationRadioButton = new System.Windows.Forms.RadioButton(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); this.tabPage2.SuspendLayout(); @@ -142,6 +143,7 @@ // // groupBox1 // + this.groupBox1.Controls.Add(this.NoEncapsulationRadioButton); this.groupBox1.Controls.Add(this.RawEthernetRadioButton); this.groupBox1.Controls.Add(this.UDPRadioButton); this.groupBox1.Location = new System.Drawing.Point(10, 30); @@ -154,7 +156,7 @@ // RawEthernetRadioButton // this.RawEthernetRadioButton.AutoSize = true; - this.RawEthernetRadioButton.Location = new System.Drawing.Point(77, 16); + this.RawEthernetRadioButton.Location = new System.Drawing.Point(63, 16); this.RawEthernetRadioButton.Name = "RawEthernetRadioButton"; this.RawEthernetRadioButton.Size = new System.Drawing.Size(186, 17); this.RawEthernetRadioButton.TabIndex = 1; @@ -271,6 +273,17 @@ this.CancelButton.UseVisualStyleBackColor = true; this.CancelButton.Click += new System.EventHandler(this.CancelButton_Click); // + // NoEncapsulation + // + this.NoEncapsulationRadioButton.AutoSize = true; + this.NoEncapsulationRadioButton.Location = new System.Drawing.Point(255, 16); + this.NoEncapsulationRadioButton.Name = "NoEncapsulation"; + this.NoEncapsulationRadioButton.Size = new System.Drawing.Size(51, 17); + this.NoEncapsulationRadioButton.TabIndex = 2; + this.NoEncapsulationRadioButton.TabStop = true; + this.NoEncapsulationRadioButton.Text = "None"; + this.NoEncapsulationRadioButton.UseVisualStyleBackColor = true; + // // SystemOptions // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -320,5 +333,6 @@ private System.Windows.Forms.GroupBox groupBox1; private System.Windows.Forms.RadioButton RawEthernetRadioButton; private System.Windows.Forms.RadioButton UDPRadioButton; + private System.Windows.Forms.RadioButton NoEncapsulationRadioButton; } } \ No newline at end of file diff --git a/Contralto/UI/SystemOptions.cs b/Contralto/UI/SystemOptions.cs index 2288b80..dc4eacd 100644 --- a/Contralto/UI/SystemOptions.cs +++ b/Contralto/UI/SystemOptions.cs @@ -54,55 +54,82 @@ namespace Contralto.UI { // If PCAP isn't installed, the RAW Ethernet option is not available. RawEthernetRadioButton.Enabled = false; - UDPRadioButton.Checked = true; - } - else - { - if (Configuration.HostPacketInterfaceType == PacketInterfaceType.UDPEncapsulation) - { - UDPRadioButton.Checked = true; - } - else - { - RawEthernetRadioButton.Checked = true; - } - } - PopulateNetworkAdapterList(UDPRadioButton.Checked); + // Ensure the option isn't set in the configuration. + if (Configuration.HostPacketInterfaceType == PacketInterfaceType.EthernetEncapsulation) + { + Configuration.HostPacketInterfaceType = PacketInterfaceType.None; + } + } + + switch(Configuration.HostPacketInterfaceType) + { + case PacketInterfaceType.UDPEncapsulation: + UDPRadioButton.Checked = true; + break; + + case PacketInterfaceType.EthernetEncapsulation: + RawEthernetRadioButton.Checked = true; + break; + + case PacketInterfaceType.None: + NoEncapsulationRadioButton.Checked = true; + break; + } + + PopulateNetworkAdapterList(Configuration.HostPacketInterfaceType); } - private void PopulateNetworkAdapterList(bool udpEncapsulation) + private void PopulateNetworkAdapterList(PacketInterfaceType encapType) { // // Populate the list with the interfaces available on the machine, for the // type of encapsulation being used. - // + // + HostInterfaceGroupBox.Enabled = encapType != PacketInterfaceType.None; + EthernetInterfaceListBox.Items.Clear(); - NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces(); - + // Add the "Use no interface" option EthernetInterfaceListBox.Items.Add( new EthernetInterface("None", "No network adapter")); - foreach (NetworkInterface iface in interfaces) + + switch (encapType) { // For UDP we show all interfaces that support IPV4, for Raw Ethernet we show only Ethernet interfaces. - if (udpEncapsulation) - { - if (iface.Supports(NetworkInterfaceComponent.IPv4)) + case PacketInterfaceType.UDPEncapsulation: { - EthernetInterfaceListBox.Items.Add(new EthernetInterface(iface.Name, iface.Description)); + NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces(); + + foreach (NetworkInterface iface in interfaces) + { + if (iface.Supports(NetworkInterfaceComponent.IPv4)) + { + EthernetInterfaceListBox.Items.Add(new EthernetInterface(iface.Name, iface.Description)); + } + } } - } - else - { - if (iface.NetworkInterfaceType == NetworkInterfaceType.Ethernet) + break; + + // Add all interfaces that PCAP knows about. + case PacketInterfaceType.EthernetEncapsulation: { - EthernetInterfaceListBox.Items.Add(new EthernetInterface(iface.Name, iface.Description)); - } - } - } + List ifaces = EthernetInterface.EnumerateDevices(); + + foreach (EthernetInterface iface in ifaces) + { + EthernetInterfaceListBox.Items.Add(iface); + } + } + break; + + case PacketInterfaceType.None: + // Add nothing. + break; + } + // // Select the one that is already selected (if any) @@ -115,7 +142,7 @@ namespace Contralto.UI { EthernetInterface iface = (EthernetInterface)EthernetInterfaceListBox.Items[i]; - if (iface.Description.ToLowerInvariant() == Configuration.HostPacketInterfaceName.ToLowerInvariant()) + if (iface.Description == Configuration.HostPacketInterfaceName) { EthernetInterfaceListBox.SelectedIndex = i; break; @@ -146,12 +173,16 @@ namespace Contralto.UI { _selectedInterfaceType = PacketInterfaceType.UDPEncapsulation; } - else + else if (RawEthernetRadioButton.Checked) { _selectedInterfaceType = PacketInterfaceType.EthernetEncapsulation; } + else + { + _selectedInterfaceType = PacketInterfaceType.None; + } - PopulateNetworkAdapterList(UDPRadioButton.Checked); + PopulateNetworkAdapterList(_selectedInterfaceType); } private void OKButton_Click(object sender, EventArgs e) @@ -180,14 +211,14 @@ namespace Contralto.UI // // First warn the user of changes that require a restart. // - if (Configuration.HostPacketInterfaceName.ToLowerInvariant() != iface.Description.ToLowerInvariant() || + if (Configuration.HostPacketInterfaceName != iface.Description || Configuration.HostPacketInterfaceType != _selectedInterfaceType || Configuration.SystemType != _selectedSystemType) { MessageBox.Show("Changes to CPU or Ethernet configuration will not take effect until ContrAlto is restarted."); } - //System + // System Configuration.SystemType = _selectedSystemType; // Ethernet @@ -197,9 +228,7 @@ namespace Contralto.UI // Display Configuration.InterlaceDisplay = InterlaceDisplayCheckBox.Checked; - Configuration.ThrottleSpeed = ThrottleSpeedCheckBox.Checked; - - Configuration.WriteConfiguration(); + Configuration.ThrottleSpeed = ThrottleSpeedCheckBox.Checked; this.Close();