From a9428a91d88dd0ecbf36f3e18c18872906105af6 Mon Sep 17 00:00:00 2001 From: Josh Dersch Date: Tue, 5 Apr 2016 15:22:30 -0700 Subject: [PATCH] Small optimizations, updates to installer, and new UI for FPS and disk activity. --- Contralto/AltoSystem.cs | 19 +---- Contralto/CPU/MicroInstruction.cs | 11 +++ Contralto/CPU/Shifter.cs | 19 ++--- Contralto/CPU/Tasks/Task.cs | 78 +++++++++++++-------- Contralto/Contralto.csproj | 4 ++ Contralto/Display/DisplayController.cs | 4 +- Contralto/IO/DiabloDrive.cs | 2 +- Contralto/IO/DiskController.cs | 42 +++++++++-- Contralto/Properties/Resources.Designer.cs | 40 +++++++++++ Contralto/Properties/Resources.resx | 12 ++++ Contralto/Resources/DiskNoAccess.bmp | Bin 0 -> 3382 bytes Contralto/Resources/DiskRead.bmp | Bin 0 -> 3382 bytes Contralto/Resources/DiskSeek.bmp | Bin 0 -> 3382 bytes Contralto/Resources/DiskWrite.bmp | Bin 0 -> 3382 bytes Contralto/UI/AboutBox.Designer.cs | 5 +- Contralto/UI/AltoWindow.Designer.cs | 63 ++++++++++------- Contralto/UI/AltoWindow.cs | 75 +++++++++++++++++++- Contralto/readme.txt | 6 ++ ContraltoSetup/ContraltoSetup.wixproj | 11 +++ ContraltoSetup/EULA.rtf | Bin 0 -> 207 bytes ContraltoSetup/Product.wxs | 11 ++- 21 files changed, 310 insertions(+), 92 deletions(-) create mode 100644 Contralto/Resources/DiskNoAccess.bmp create mode 100644 Contralto/Resources/DiskRead.bmp create mode 100644 Contralto/Resources/DiskSeek.bmp create mode 100644 Contralto/Resources/DiskWrite.bmp create mode 100644 ContraltoSetup/EULA.rtf diff --git a/Contralto/AltoSystem.cs b/Contralto/AltoSystem.cs index 4904311..f210436 100644 --- a/Contralto/AltoSystem.cs +++ b/Contralto/AltoSystem.cs @@ -41,13 +41,7 @@ namespace Contralto _clockableDevices.Add(_memBus); _clockableDevices.Add(_cpu); - Reset(); - - Timer t = new Timer(); - t.AutoReset = true; - t.Interval = 1000; - t.Elapsed += T_Elapsed; - //t.Start(); + Reset(); } public void Reset() @@ -226,16 +220,7 @@ namespace Contralto get { return _scheduler; } } - public int _novaInst; - - 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} nova instructions/sec.", _novaInst); - _clocks = 0; - _novaInst = 0; - _displayController.Fields = 0; - } + public int _novaInst; private AltoCPU _cpu; private MemoryBus _memBus; diff --git a/Contralto/CPU/MicroInstruction.cs b/Contralto/CPU/MicroInstruction.cs index 8365d7b..b8dc9e2 100644 --- a/Contralto/CPU/MicroInstruction.cs +++ b/Contralto/CPU/MicroInstruction.cs @@ -198,6 +198,15 @@ namespace Contralto.CPU F1 == SpecialFunction1.Constant || F2 == SpecialFunction2.Constant; + ConstantAccessOrBS4 = ConstantAccess || (int)BS > 4; + + // Whether this instruction needs the Shifter output + // This is the only task-specific thing we cache, even if this isn't + // the right task, worst-case we'll do an operation we didn't need to. + NeedShifterOutput = (EmulatorF2)F2 == EmulatorF2.LoadDNS || + F2 == SpecialFunction2.ShEq0 || + F2 == SpecialFunction2.ShLt0; + // Whether this instruction accesses memory MemoryAccess = (BS == BusSource.ReadMD && !ConstantAccess) || // ReadMD only occurs if not reading from constant ROM. @@ -260,10 +269,12 @@ namespace Contralto.CPU public SpecialFunction2 F2; public bool LoadT; public bool LoadL; + public bool NeedShifterOutput; public ushort NEXT; // Metadata about the instruction that can be precalculated and used during execution public bool ConstantAccess; + public bool ConstantAccessOrBS4; public bool MemoryAccess; public MemoryOperation MemoryOperation; public bool LoadTFromALU; diff --git a/Contralto/CPU/Shifter.cs b/Contralto/CPU/Shifter.cs index 2160a41..d51322e 100644 --- a/Contralto/CPU/Shifter.cs +++ b/Contralto/CPU/Shifter.cs @@ -3,8 +3,7 @@ namespace Contralto.CPU { public enum ShifterOp - { - Invalid = 0, + { None, ShiftLeft, ShiftRight, @@ -27,7 +26,7 @@ namespace Contralto.CPU public static void Reset() { - _op = ShifterOp.Invalid; + _op = ShifterOp.None; _count = 0; _output = 0; _magic = false; @@ -41,6 +40,12 @@ namespace Contralto.CPU public static ushort Output { get { return _output; } + set { _output = value; } + } + + public static ShifterOp Op + { + get { return _op; } } /// @@ -66,7 +71,6 @@ namespace Contralto.CPU _magic = magic; } - /// /// TODO: this is still kind of clumsy. /// @@ -92,10 +96,7 @@ namespace Contralto.CPU public static ushort DoOperation(ushort input, ushort t) { switch(_op) - { - case ShifterOp.Invalid: - throw new InvalidOperationException("Shifter op has not been set."); - + { case ShifterOp.None: _output = input; break; @@ -196,7 +197,7 @@ namespace Contralto.CPU default: throw new InvalidOperationException(String.Format("Unhandled shift operation {0}", _op)); - } + } return _output; } diff --git a/Contralto/CPU/Tasks/Task.cs b/Contralto/CPU/Tasks/Task.cs index 65dd5b0..9f7d480 100644 --- a/Contralto/CPU/Tasks/Task.cs +++ b/Contralto/CPU/Tasks/Task.cs @@ -120,9 +120,7 @@ namespace Contralto.CPU _busData = 0; _softReset = false; - - Shifter.SetMagic(false); - Shifter.SetDNS(false, 0); + Shifter.Reset(); // // Wait for memory state machine if a memory operation is requested by this instruction and @@ -217,8 +215,7 @@ namespace Contralto.CPU // "Note that the [emulator task F2] functions which replace the low bits of RSELECT with IR affect only the // selection of R; they do not affect the address supplied to the constant ROM." // Hence we use the unmodified RSELECT value here and above. - if ((int)instruction.BS > 4 || - instruction.ConstantAccess) + if (instruction.ConstantAccessOrBS4) { _busData &= ControlROM.ConstantROM[(instruction.RSELECT << 3) | ((uint)instruction.BS)]; } @@ -272,10 +269,7 @@ namespace Contralto.CPU _swMode = false; swMode = true; } - - // Reset shifter op - Shifter.SetOperation(ShifterOp.None, 0); - + // // Do Special Functions // @@ -350,25 +344,11 @@ namespace Contralto.CPU break; case SpecialFunction2.ShLt0: - // - // Note: - // "the value of SHIFTER OUTPUT is determined by the value of L as the microinstruction - // *begins* execution and the shifter function specified during the *current* microinstruction. - // - // Since we haven't modifed L yet, and we've selected the shifter function above, we're good to go here. - // - if ((short)Shifter.DoOperation(_cpu._l, _cpu._t) < 0) - { - _nextModifier = 1; - } + // Handled below, after the Shifter runs break; case SpecialFunction2.ShEq0: - // See note above. - if (Shifter.DoOperation(_cpu._l, _cpu._t) == 0) - { - _nextModifier = 1; - } + // Same as above. break; case SpecialFunction2.Bus: @@ -401,10 +381,52 @@ namespace Contralto.CPU ExecuteSpecialFunction2(instruction); break; } - - // We always do the shifter operation; DNS may need its output. + // - Shifter.DoOperation(_cpu._l, _cpu._t); + // Do the shifter operation if we're doing an operation that requires the shifter output (loading R, doing a LoadDNS, + // modifying NEXT based on the shifter output.) + // + if (_loadR || instruction.NeedShifterOutput) + { + // A crude optimization: if there's no shifter operation, + // we bypass the call to DoOperation and stuff L in Shifter.Output ourselves. + if (Shifter.Op == ShifterOp.None) + { + Shifter.Output = _cpu._l; + } + else + { + Shifter.DoOperation(_cpu._l, _cpu._t); + } + } + + // + // Handle NEXT modifiers that rely on the Shifter output. + // + switch(instruction.F2) + { + case SpecialFunction2.ShLt0: + // + // Note: + // "the value of SHIFTER OUTPUT is determined by the value of L as the microinstruction + // *begins* execution and the shifter function specified during the *current* microinstruction. + // + // Since we haven't modifed L yet, and we've calculated the shifter output above, we're good to go here. + // + if ((short)Shifter.Output < 0) + { + _nextModifier = 1; + } + break; + + case SpecialFunction2.ShEq0: + // See note above. + if (Shifter.Output == 0) + { + _nextModifier = 1; + } + break; + } // // Write back to registers: diff --git a/Contralto/Contralto.csproj b/Contralto/Contralto.csproj index 6618755..10f5578 100644 --- a/Contralto/Contralto.csproj +++ b/Contralto/Contralto.csproj @@ -392,6 +392,10 @@ + + + + diff --git a/Contralto/Display/DisplayController.cs b/Contralto/Display/DisplayController.cs index e11057e..cfd56c4 100644 --- a/Contralto/Display/DisplayController.cs +++ b/Contralto/Display/DisplayController.cs @@ -379,8 +379,8 @@ namespace Contralto.Display // ~35 scanlines for vblank (1330uS) private const double _scale = 1.0; private const ulong _verticalBlankDuration = (ulong)(665000.0 * _scale); // 665uS - private const ulong _verticalBlankScanlineDuration = (ulong)(38080 * _scale); // 38uS - private const ulong _horizontalBlankDuration = (ulong)(6084 * _scale); // 6uS + private const ulong _verticalBlankScanlineDuration = (ulong)(38080.0 * _scale); // 38uS + private const ulong _horizontalBlankDuration = (ulong)(6084.0 * _scale); // 6uS private const ulong _wordDuration = (ulong)(842.0 * _scale); // 32/38uS private int _vblankScanlineCount; diff --git a/Contralto/IO/DiabloDrive.cs b/Contralto/IO/DiabloDrive.cs index 32147c5..13eda50 100644 --- a/Contralto/IO/DiabloDrive.cs +++ b/Contralto/IO/DiabloDrive.cs @@ -7,7 +7,7 @@ using System.Text; using System.Threading.Tasks; namespace Contralto.IO -{ +{ // The data for the current sector public enum CellType diff --git a/Contralto/IO/DiskController.cs b/Contralto/IO/DiskController.cs index 8337fb5..e937e34 100644 --- a/Contralto/IO/DiskController.cs +++ b/Contralto/IO/DiskController.cs @@ -5,6 +5,16 @@ using Contralto.CPU; namespace Contralto.IO { + public enum DiskActivityType + { + Idle, + Read, + Write, + Seek, + } + + public delegate void DiskActivity(DiskActivityType activity); + public class DiskController { public DiskController(AltoSystem system) @@ -89,7 +99,7 @@ namespace Contralto.IO { // Restore operation to cyl. 0: InitSeek(0); - } + } } } @@ -222,7 +232,18 @@ namespace Contralto.IO public DiabloDrive[] Drives { get { return _drives; } - } + } + + /// + /// Exposes the last activity the disk controller undertook. + /// This is used exclusively so the UI can show a tiny disk + /// access icon, it is not necessary to the functioning of the + /// emulation. + /// + public DiskActivityType LastDiskActivity + { + get { return _lastDiskActivity; } + } public void Reset() { @@ -297,7 +318,7 @@ namespace Contralto.IO _kDataRead = 0; // Load new sector in - SelectedDrive.Sector = _sector; + SelectedDrive.Sector = _sector; // Only wake up if not actively seeking. if ((_kStat & STROBE) == 0) @@ -319,6 +340,8 @@ namespace Contralto.IO // Schedule SECLATE trigger _seclateEvent.TimestampNsec = _seclateDuration; _system.Scheduler.Schedule(_seclateEvent); + + _lastDiskActivity = DiskActivityType.Idle; } else { @@ -399,7 +422,7 @@ namespace Contralto.IO Log.Write(LogComponent.DiskController, "STROBE: Seek initialized."); - InitSeek((_kDataWrite & 0x0ff8) >> 3); + InitSeek((_kDataWrite & 0x0ff8) >> 3); } private void InitSeek(int destCylinder) @@ -413,6 +436,7 @@ namespace Contralto.IO Log.Write(LogComponent.DiskController, "Seek failed, specified cylinder {0} is out of range.", destCylinder); _seeking = false; + _lastDiskActivity = DiskActivityType.Idle; } else if (destCylinder != SelectedDrive.Cylinder) { @@ -433,6 +457,7 @@ namespace Contralto.IO _system.Scheduler.Schedule(_seekEvent); Log.Write(LogComponent.DiskController, "Seek to {0} from {1} commencing. Will take {2} nsec.", _destCylinder, SelectedDrive.Cylinder, _seekDuration); + _lastDiskActivity = DiskActivityType.Seek; } else { @@ -506,6 +531,8 @@ namespace Contralto.IO Log.Write(LogType.Verbose, LogComponent.DiskWordTask, "Sector {0} Word {1} read into KDATA", _sector, Conversion.ToOctal(diskWord.Data)); _kDataRead = diskWord.Data; _debugRead = diskWord.Type == CellType.Data; + + _lastDiskActivity = DiskActivityType.Read; } else { @@ -522,6 +549,7 @@ namespace Contralto.IO { // Commit actual data to disk now that the sync word has been laid down SelectedDrive.WriteWord(_sectorWordIndex, _kDataWrite); + _lastDiskActivity = DiskActivityType.Write; } } } @@ -599,7 +627,7 @@ namespace Contralto.IO { // clear Seek bit _kStat &= (ushort)~STROBE; - _seeking = false; + _seeking = false; Log.Write(LogComponent.DiskController, "Seek to {0} completed.", SelectedDrive.Cylinder); } @@ -609,6 +637,8 @@ namespace Contralto.IO // Schedule next seek step. _seekEvent.TimestampNsec = _seekDuration - skewNsec; _system.Scheduler.Schedule(_seekEvent); + + _lastDiskActivity = DiskActivityType.Seek; } } @@ -712,6 +742,8 @@ namespace Contralto.IO private bool _debugRead; + private DiskActivityType _lastDiskActivity; + // // KSTAT bitfields. // Note that in reality the SECLATE status bit (bit 11) is a bit more nuanced; it's actually the OR of two signals: diff --git a/Contralto/Properties/Resources.Designer.cs b/Contralto/Properties/Resources.Designer.cs index cd06c33..f1afe5c 100644 --- a/Contralto/Properties/Resources.Designer.cs +++ b/Contralto/Properties/Resources.Designer.cs @@ -60,6 +60,46 @@ namespace Contralto.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap DiskNoAccess { + get { + object obj = ResourceManager.GetObject("DiskNoAccess", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap DiskRead { + get { + object obj = ResourceManager.GetObject("DiskRead", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap DiskSeek { + get { + object obj = ResourceManager.GetObject("DiskSeek", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap DiskWrite { + get { + object obj = ResourceManager.GetObject("DiskWrite", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/Contralto/Properties/Resources.resx b/Contralto/Properties/Resources.resx index 2c3c270..f616cb2 100644 --- a/Contralto/Properties/Resources.resx +++ b/Contralto/Properties/Resources.resx @@ -118,6 +118,18 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\DiskNoAccess.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\DiskRead.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\resources\diskseek.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\DiskWrite.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\dragon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a diff --git a/Contralto/Resources/DiskNoAccess.bmp b/Contralto/Resources/DiskNoAccess.bmp new file mode 100644 index 0000000000000000000000000000000000000000..3cd683070de82b36c561e9df8487a00753f5a7d2 GIT binary patch literal 3382 zcmZ?rHDh4_12Z700mK4O%*dbsWI@0YJ_ZI5hJpV6{{NKX|6~G~y<}>KyL-6kzjW!+ ze`E~v7qS?L4Fl-mhf5tU@xi7a<}YGtboUdh52kLo=!f}(92yoDqx5J9jE2By2#kin PXb6mkz-S1Jln?*_Zk3lI literal 0 HcmV?d00001 diff --git a/Contralto/Resources/DiskRead.bmp b/Contralto/Resources/DiskRead.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1462ad083f1567e27a380f507bd966a299d48340 GIT binary patch literal 3382 zcmeHE!41MN3=9&FybvSsWP%RB9|`rD4wWUGUnG`bf{v4qiD_LqQB_ri2daFnlV0p| zlI!i>9L)z!9{aMR1_vrf` zW$?Pxv!+@k>4RoZFk$*X&Pq1nx1gTOj|`PR8M|JV#f;$2FPIn}$AI_8vj8IsEr%=MRfh>{`NP;!W2dh*q6b^Nke SnL3~jr~~SNI-m~h(}6e2TRXV` literal 0 HcmV?d00001 diff --git a/Contralto/Resources/DiskSeek.bmp b/Contralto/Resources/DiskSeek.bmp new file mode 100644 index 0000000000000000000000000000000000000000..55143d03541028e2e97d87c700fe1dac82573214 GIT binary patch literal 3382 zcmZ?rHDh4_12Z700mK4O%*dbsWI@0YJ_ZI5hJpV6{{NKX|6~G~z3AE%6&2Biu=26# z2kFI!kqyG8A6Xumjm=G@=tnjS#zxnF>C&bD$QY&$Sq#L6f#Ief<}YGtbpI2p52kLo z=!f}(92yoDG^9aA&Hw+gv2$V}mO%J(fBr<_$Nu~|7ezjHE>xa|P8&6PGz3ONU^E0q OLtr!nMnhmEh5!IyMrOPK literal 0 HcmV?d00001 diff --git a/Contralto/Resources/DiskWrite.bmp b/Contralto/Resources/DiskWrite.bmp new file mode 100644 index 0000000000000000000000000000000000000000..cfd4cbc6a5a2a3aaf0bbf475850aedfc13576414 GIT binary patch literal 3382 zcmZ?rHDh4_12Z700mK4O%*dbsWI@0YJ_ZI5hJpV6{{NKX|6~G~y<}>KyL%|;XJFX+ zAB2$sy8ka-y7V6z!_>m`!f2Q{G5TS8&}onv^w1Bo2b<5YA0x&a><KQ?wwEW{uPf9}tpDE!!;Kj)&z$IgYyQ)vCD_R$a+4S~@R R7!85Z5Eu=C(GWll0RUVAQg8qO literal 0 HcmV?d00001 diff --git a/Contralto/UI/AboutBox.Designer.cs b/Contralto/UI/AboutBox.Designer.cs index a01c55a..1b298d5 100644 --- a/Contralto/UI/AboutBox.Designer.cs +++ b/Contralto/UI/AboutBox.Designer.cs @@ -98,10 +98,11 @@ // // pictureBox1 // + this.pictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.pictureBox1.Image = global::Contralto.Properties.Resources.dragon; - this.pictureBox1.Location = new System.Drawing.Point(48, 79); + this.pictureBox1.Location = new System.Drawing.Point(44, 79); this.pictureBox1.Name = "pictureBox1"; - this.pictureBox1.Size = new System.Drawing.Size(153, 238); + this.pictureBox1.Size = new System.Drawing.Size(156, 238); this.pictureBox1.TabIndex = 6; this.pictureBox1.TabStop = false; // diff --git a/Contralto/UI/AltoWindow.Designer.cs b/Contralto/UI/AltoWindow.Designer.cs index b173f45..c371a72 100644 --- a/Contralto/UI/AltoWindow.Designer.cs +++ b/Contralto/UI/AltoWindow.Designer.cs @@ -29,9 +29,9 @@ private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AltoWindow)); - this.DisplayBox = new System.Windows.Forms.PictureBox(); this.menuStrip1 = new System.Windows.Forms.MenuStrip(); this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.saveScreenshotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.SystemStartMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -54,24 +54,13 @@ this.CaptureStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); this.SystemStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); this.DiskStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); - this.saveScreenshotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - ((System.ComponentModel.ISupportInitialize)(this.DisplayBox)).BeginInit(); + this.FPSLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this.DisplayBox = new System.Windows.Forms.PictureBox(); this.menuStrip1.SuspendLayout(); this.StatusLine.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.DisplayBox)).BeginInit(); this.SuspendLayout(); // - // DisplayBox - // - this.DisplayBox.BackColor = System.Drawing.SystemColors.Window; - this.DisplayBox.Location = new System.Drawing.Point(0, 27); - this.DisplayBox.Name = "DisplayBox"; - this.DisplayBox.Size = new System.Drawing.Size(606, 808); - this.DisplayBox.TabIndex = 1; - this.DisplayBox.TabStop = false; - this.DisplayBox.MouseDown += new System.Windows.Forms.MouseEventHandler(this.OnDisplayMouseDown); - this.DisplayBox.MouseMove += new System.Windows.Forms.MouseEventHandler(this.OnDisplayMouseMove); - this.DisplayBox.MouseUp += new System.Windows.Forms.MouseEventHandler(this.OnDisplayMouseUp); - // // menuStrip1 // this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -93,6 +82,15 @@ this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); this.fileToolStripMenuItem.Text = "File"; // + // saveScreenshotToolStripMenuItem + // + this.saveScreenshotToolStripMenuItem.Name = "saveScreenshotToolStripMenuItem"; + this.saveScreenshotToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Alt) + | System.Windows.Forms.Keys.P))); + this.saveScreenshotToolStripMenuItem.Size = new System.Drawing.Size(232, 22); + this.saveScreenshotToolStripMenuItem.Text = "Save Screenshot..."; + this.saveScreenshotToolStripMenuItem.Click += new System.EventHandler(this.OnFileSaveScreenshotClick); + // // exitToolStripMenuItem // this.exitToolStripMenuItem.Name = "exitToolStripMenuItem"; @@ -248,7 +246,8 @@ this.StatusLine.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.CaptureStatusLabel, this.SystemStatusLabel, - this.DiskStatusLabel}); + this.DiskStatusLabel, + this.FPSLabel}); this.StatusLine.Location = new System.Drawing.Point(0, 837); this.StatusLine.Name = "StatusLine"; this.StatusLine.Size = new System.Drawing.Size(608, 22); @@ -270,18 +269,31 @@ // // DiskStatusLabel // + this.DiskStatusLabel.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.DiskStatusLabel.Image = global::Contralto.Properties.Resources.DiskNoAccess; + this.DiskStatusLabel.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.DiskStatusLabel.Name = "DiskStatusLabel"; - this.DiskStatusLabel.Size = new System.Drawing.Size(89, 17); + this.DiskStatusLabel.Overflow = System.Windows.Forms.ToolStripItemOverflow.Never; + this.DiskStatusLabel.Size = new System.Drawing.Size(16, 17); this.DiskStatusLabel.Text = "DiskStatusLabel"; // - // saveScreenshotToolStripMenuItem + // FPSLabel // - this.saveScreenshotToolStripMenuItem.Name = "saveScreenshotToolStripMenuItem"; - this.saveScreenshotToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Alt) - | System.Windows.Forms.Keys.P))); - this.saveScreenshotToolStripMenuItem.Size = new System.Drawing.Size(232, 22); - this.saveScreenshotToolStripMenuItem.Text = "Save Screenshot..."; - this.saveScreenshotToolStripMenuItem.Click += new System.EventHandler(this.OnFileSaveScreenshotClick); + this.FPSLabel.Name = "FPSLabel"; + this.FPSLabel.Size = new System.Drawing.Size(54, 17); + this.FPSLabel.Text = "FPSLabel"; + // + // DisplayBox + // + this.DisplayBox.BackColor = System.Drawing.SystemColors.Window; + this.DisplayBox.Location = new System.Drawing.Point(0, 27); + this.DisplayBox.Name = "DisplayBox"; + this.DisplayBox.Size = new System.Drawing.Size(606, 808); + this.DisplayBox.TabIndex = 1; + this.DisplayBox.TabStop = false; + this.DisplayBox.MouseDown += new System.Windows.Forms.MouseEventHandler(this.OnDisplayMouseDown); + this.DisplayBox.MouseMove += new System.Windows.Forms.MouseEventHandler(this.OnDisplayMouseMove); + this.DisplayBox.MouseUp += new System.Windows.Forms.MouseEventHandler(this.OnDisplayMouseUp); // // AltoWindow // @@ -304,11 +316,11 @@ this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.OnKeyDown); this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.OnKeyUp); this.Leave += new System.EventHandler(this.OnWindowLeave); - ((System.ComponentModel.ISupportInitialize)(this.DisplayBox)).EndInit(); this.menuStrip1.ResumeLayout(false); this.menuStrip1.PerformLayout(); this.StatusLine.ResumeLayout(false); this.StatusLine.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.DisplayBox)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -342,5 +354,6 @@ private System.Windows.Forms.ToolStripMenuItem SystemEthernetBootMenu; private System.Windows.Forms.ToolStripMenuItem AlternateBootToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem saveScreenshotToolStripMenuItem; + private System.Windows.Forms.ToolStripStatusLabel FPSLabel; } } \ No newline at end of file diff --git a/Contralto/UI/AltoWindow.cs b/Contralto/UI/AltoWindow.cs index 16b9a3e..42b275a 100644 --- a/Contralto/UI/AltoWindow.cs +++ b/Contralto/UI/AltoWindow.cs @@ -1,12 +1,14 @@ using Contralto.CPU; using Contralto.Display; using Contralto.IO; +using Contralto.Properties; using Contralto.UI; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; +using System.Timers; using System.Windows.Forms; namespace Contralto @@ -34,7 +36,25 @@ namespace Contralto SystemStatusLabel.Text = _systemStoppedText; DiskStatusLabel.Text = String.Empty; - this.DoubleBuffered = true; + _diskIdleImage = Resources.DiskNoAccess; + _diskReadImage = Resources.DiskRead; + _diskWriteImage = Resources.DiskWrite; + _diskSeekImage = Resources.DiskSeek; + + this.DoubleBuffered = true; + + System.Timers.Timer fpsTimer = new System.Timers.Timer(); + fpsTimer.AutoReset = true; + fpsTimer.Interval = 1000; + fpsTimer.Elapsed += OnFPSTimerElapsed; + fpsTimer.Start(); + + + System.Timers.Timer diskTimer = new System.Timers.Timer(); + diskTimer.AutoReset = true; + diskTimer.Interval = 25; + diskTimer.Elapsed += OnDiskTimerElapsed; + diskTimer.Start(); } public void AttachSystem(AltoSystem system) @@ -49,7 +69,7 @@ namespace Contralto // Update disk image UI info 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; - } + } /// /// Handler for "System->Start" menu. Start the Alto system running. @@ -606,6 +626,11 @@ namespace Contralto private void OnDisplayMouseDown(object sender, MouseEventArgs e) { + if (!_mouseCaptured) + { + return; + } + AltoMouseButton button = AltoMouseButton.None; switch (e.Button) @@ -715,6 +740,46 @@ namespace Contralto ReleaseMouse(); } + private void OnFPSTimerElapsed(object sender, ElapsedEventArgs e) + { + string fpsMessage = String.Format("{0} fields/sec", _system.DisplayController.Fields); + + FPSLabel.Text = fpsMessage; + + _system.DisplayController.Fields = 0; + } + + private void OnDiskTimerElapsed(object sender, ElapsedEventArgs e) + { + BeginInvoke(new DisplayDelegate(RefreshDiskStatus)); + } + + private void RefreshDiskStatus() + { + if (_lastActivity != _system.DiskController.LastDiskActivity) + { + _lastActivity = _system.DiskController.LastDiskActivity; + switch (_lastActivity) + { + case DiskActivityType.Idle: + DiskStatusLabel.Image = _diskIdleImage; + break; + + case DiskActivityType.Read: + DiskStatusLabel.Image = _diskReadImage; + break; + + case DiskActivityType.Write: + DiskStatusLabel.Image = _diskWriteImage; + break; + + case DiskActivityType.Seek: + DiskStatusLabel.Image = _diskSeekImage; + break; + } + } + } + private void InitKeymap() { _keyMap = new Dictionary(); @@ -837,5 +902,11 @@ namespace Contralto private const string _systemRunningText = "Alto Running."; private const string _systemErrorText = "Alto Stopped due to error. See Debugger."; + private DiskActivityType _lastActivity; + private Image _diskIdleImage; + private Image _diskReadImage; + private Image _diskWriteImage; + private Image _diskSeekImage; + } } diff --git a/Contralto/readme.txt b/Contralto/readme.txt index 88536e1..d27f0d5 100644 --- a/Contralto/readme.txt +++ b/Contralto/readme.txt @@ -202,6 +202,12 @@ get you started: writing an Alto emulator of your own. If you're into that sort of thing. http://bitsavers.org/pdf/xerox/alto/AltoHWRef.part1.pdf http://bitsavers.org/pdf/xerox/alto/AltoHWRef.part2.pdf + +- "A Field Guide to Alto-Land" is a casual perspective on Alto use (and + the culture that grew around it) at Xerox. + http://xeroxalto.computerhistory.org/_cd8_/altodocs/.fieldguide.press!2.pdf + + 4.0 Configuration diff --git a/ContraltoSetup/ContraltoSetup.wixproj b/ContraltoSetup/ContraltoSetup.wixproj index f8b6c52..2cd3ec1 100644 --- a/ContraltoSetup/ContraltoSetup.wixproj +++ b/ContraltoSetup/ContraltoSetup.wixproj @@ -33,6 +33,17 @@ INSTALLFOLDER + + + $(WixExtDir)\WixUIExtension.dll + WixUIExtension + + + + + Always + +