diff --git a/Contralto/AltoSystem.cs b/Contralto/AltoSystem.cs index 38ff51f..b2f0c85 100644 --- a/Contralto/AltoSystem.cs +++ b/Contralto/AltoSystem.cs @@ -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(); } /// @@ -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; } diff --git a/Contralto/Configuration.cs b/Contralto/Configuration.cs index 40a6b5e..616dd23 100644 --- a/Contralto/Configuration.cs +++ b/Contralto/Configuration.cs @@ -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; } } diff --git a/Contralto/Contralto.csproj b/Contralto/Contralto.csproj index 30ccf79..d47c7c7 100644 --- a/Contralto/Contralto.csproj +++ b/Contralto/Contralto.csproj @@ -99,17 +99,17 @@ - + Form - + AboutBox.cs - + Form - + AltoWindow.cs @@ -131,15 +131,21 @@ - + Form - + Debugger.cs + + Form + + + EthernetBootWindow.cs + @@ -167,6 +173,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -200,6 +209,9 @@ Always + + PreserveNewest + PreserveNewest @@ -322,53 +334,32 @@ - + AboutBox.cs - + AltoWindow.cs - + Debugger.cs + + EthernetBootWindow.cs + - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - + + + + + + + + + + + + diff --git a/Contralto/Disk/Clark-Games.dsk b/Contralto/Disk/Clark-Games.dsk index 9cd6130..ba15870 100644 Binary files a/Contralto/Disk/Clark-Games.dsk and b/Contralto/Disk/Clark-Games.dsk differ diff --git a/Contralto/Disk/Josh.dsk b/Contralto/Disk/Josh.dsk new file mode 100644 index 0000000..cd6f8db Binary files /dev/null and b/Contralto/Disk/Josh.dsk differ diff --git a/Contralto/Disk/allgames.dsk b/Contralto/Disk/allgames.dsk new file mode 100644 index 0000000..2412dce Binary files /dev/null and b/Contralto/Disk/allgames.dsk differ diff --git a/Contralto/Disk/bcpl.dsk b/Contralto/Disk/bcpl.dsk index ec2357e..4484bf3 100644 Binary files a/Contralto/Disk/bcpl.dsk and b/Contralto/Disk/bcpl.dsk differ diff --git a/Contralto/Disk/bravox.dsk b/Contralto/Disk/bravox.dsk index cdee65b..b5d669b 100644 Binary files a/Contralto/Disk/bravox.dsk and b/Contralto/Disk/bravox.dsk differ diff --git a/Contralto/Disk/diag.dsk b/Contralto/Disk/diag.dsk index 2e34b67..0f0cbdb 100644 Binary files a/Contralto/Disk/diag.dsk and b/Contralto/Disk/diag.dsk differ diff --git a/Contralto/Disk/games.dsk b/Contralto/Disk/games.dsk index a8af94b..0fe02c2 100644 Binary files a/Contralto/Disk/games.dsk and b/Contralto/Disk/games.dsk differ diff --git a/Contralto/Disk/gamesb.dsk b/Contralto/Disk/gamesb.dsk index e73ba3e..d6b9cc6 100644 Binary files a/Contralto/Disk/gamesb.dsk and b/Contralto/Disk/gamesb.dsk differ diff --git a/Contralto/Disk/gsl.dsk b/Contralto/Disk/gsl.dsk index e936bab..e8812c7 100644 Binary files a/Contralto/Disk/gsl.dsk and b/Contralto/Disk/gsl.dsk differ diff --git a/Contralto/Disk/nonprog.dsk b/Contralto/Disk/nonprog.dsk index 7724991..64930dd 100644 Binary files a/Contralto/Disk/nonprog.dsk and b/Contralto/Disk/nonprog.dsk differ diff --git a/Contralto/Disk/os12.5.empty.dsk b/Contralto/Disk/os12.5.empty.dsk new file mode 100644 index 0000000..d3f6e6c Binary files /dev/null and b/Contralto/Disk/os12.5.empty.dsk differ diff --git a/Contralto/Disk/os20.16.empty.dsk b/Contralto/Disk/os20.16.empty.dsk new file mode 100644 index 0000000..a47b8cc Binary files /dev/null and b/Contralto/Disk/os20.16.empty.dsk differ diff --git a/Contralto/Disk/st76boot.dsk b/Contralto/Disk/st76boot.dsk index 30c5abf..335cbd3 100644 Binary files a/Contralto/Disk/st76boot.dsk and b/Contralto/Disk/st76boot.dsk differ diff --git a/Contralto/Disk/st76new.dsk b/Contralto/Disk/st76new.dsk new file mode 100644 index 0000000..a47b8cc Binary files /dev/null and b/Contralto/Disk/st76new.dsk differ diff --git a/Contralto/Disk/tdisk4.dsk b/Contralto/Disk/tdisk4.dsk index 385d482..8e4a8ed 100644 Binary files a/Contralto/Disk/tdisk4.dsk and b/Contralto/Disk/tdisk4.dsk differ diff --git a/Contralto/Disk/tdisk8.dsk b/Contralto/Disk/tdisk8.dsk index 24e685f..3b67268 100644 Binary files a/Contralto/Disk/tdisk8.dsk and b/Contralto/Disk/tdisk8.dsk differ diff --git a/Contralto/Disk/xmsmall.dsk b/Contralto/Disk/xmsmall.dsk index b8a7c3b..2805a9a 100644 Binary files a/Contralto/Disk/xmsmall.dsk and b/Contralto/Disk/xmsmall.dsk differ diff --git a/Contralto/IO/EthernetController.cs b/Contralto/IO/EthernetController.cs index 6188918..5aa8310 100644 --- a/Contralto/IO/EthernetController.cs +++ b/Contralto/IO/EthernetController.cs @@ -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(); } + /// + /// 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 + /// + /// + /// + /// 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; } diff --git a/Contralto/IO/HostEthernet.cs b/Contralto/IO/HostEthernet.cs index f26812e..e169930 100644 --- a/Contralto/IO/HostEthernet.cs +++ b/Contralto/IO/HostEthernet.cs @@ -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 /// /// 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 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; } } diff --git a/Contralto/IO/Keyboard.cs b/Contralto/IO/Keyboard.cs index 6522cc0..1d34665 100644 --- a/Contralto/IO/Keyboard.cs +++ b/Contralto/IO/Keyboard.cs @@ -84,21 +84,22 @@ namespace Contralto.IO public ushort Bitmask; } - /// - /// 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. /// 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 _keyMap; + + /// + /// The keys used to specify a 16-bit boot address, from MSB to LSB + /// + 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; } } diff --git a/Contralto/Logging/Log.cs b/Contralto/Logging/Log.cs index c409644..c7e2012 100644 --- a/Contralto/Logging/Log.cs +++ b/Contralto/Logging/Log.cs @@ -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"); diff --git a/Contralto/Program.cs b/Contralto/Program.cs index dd18c94..76c3a85 100644 --- a/Contralto/Program.cs +++ b/Contralto/Program.cs @@ -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 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 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 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; + } + } } } diff --git a/Contralto/AboutBox.Designer.cs b/Contralto/UI/AboutBox.Designer.cs similarity index 100% rename from Contralto/AboutBox.Designer.cs rename to Contralto/UI/AboutBox.Designer.cs diff --git a/Contralto/AboutBox.cs b/Contralto/UI/AboutBox.cs similarity index 100% rename from Contralto/AboutBox.cs rename to Contralto/UI/AboutBox.cs diff --git a/Contralto/AboutBox.resx b/Contralto/UI/AboutBox.resx similarity index 100% rename from Contralto/AboutBox.resx rename to Contralto/UI/AboutBox.resx diff --git a/Contralto/AltoWindow.Designer.cs b/Contralto/UI/AltoWindow.Designer.cs similarity index 96% rename from Contralto/AltoWindow.Designer.cs rename to Contralto/UI/AltoWindow.Designer.cs index 556d7f3..d60d8e0 100644 --- a/Contralto/AltoWindow.Designer.cs +++ b/Contralto/UI/AltoWindow.Designer.cs @@ -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; } } \ No newline at end of file diff --git a/Contralto/AltoWindow.cs b/Contralto/UI/AltoWindow.cs similarity index 98% rename from Contralto/AltoWindow.cs rename to Contralto/UI/AltoWindow.cs index 6bc9635..72bd622 100644 --- a/Contralto/AltoWindow.cs +++ b/Contralto/UI/AltoWindow.cs @@ -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(); - + _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); diff --git a/Contralto/AltoWindow.resx b/Contralto/UI/AltoWindow.resx similarity index 100% rename from Contralto/AltoWindow.resx rename to Contralto/UI/AltoWindow.resx diff --git a/Contralto/Debugger.Designer.cs b/Contralto/UI/Debugger.Designer.cs similarity index 100% rename from Contralto/Debugger.Designer.cs rename to Contralto/UI/Debugger.Designer.cs diff --git a/Contralto/Debugger.cs b/Contralto/UI/Debugger.cs similarity index 100% rename from Contralto/Debugger.cs rename to Contralto/UI/Debugger.cs diff --git a/Contralto/Debugger.resx b/Contralto/UI/Debugger.resx similarity index 100% rename from Contralto/Debugger.resx rename to Contralto/UI/Debugger.resx diff --git a/Contralto/UI/EthernetBootWindow.Designer.cs b/Contralto/UI/EthernetBootWindow.Designer.cs new file mode 100644 index 0000000..3850640 --- /dev/null +++ b/Contralto/UI/EthernetBootWindow.Designer.cs @@ -0,0 +1,133 @@ +namespace Contralto +{ + partial class EthernetBootWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + 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; + } +} \ No newline at end of file diff --git a/Contralto/UI/EthernetBootWindow.cs b/Contralto/UI/EthernetBootWindow.cs new file mode 100644 index 0000000..c7964a8 --- /dev/null +++ b/Contralto/UI/EthernetBootWindow.cs @@ -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; + } +} diff --git a/Contralto/UI/EthernetBootWindow.resx b/Contralto/UI/EthernetBootWindow.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Contralto/UI/EthernetBootWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file