diff --git a/Contralto/CPU/CPU.cs b/Contralto/CPU/CPU.cs index 528b3b4..13fdeb7 100644 --- a/Contralto/CPU/CPU.cs +++ b/Contralto/CPU/CPU.cs @@ -1,5 +1,7 @@ using System.Timers; +using Contralto.Logging; + namespace Contralto.CPU { public enum TaskType @@ -145,22 +147,30 @@ namespace Contralto.CPU /// public void SoftReset() { - // Reset tasks. + // Soft-Reset tasks. for (int i = 0; i < _tasks.Length; i++) { if (_tasks[i] != null) { - _tasks[i].Reset(); + _tasks[i].SoftReset(); } } UCodeMemory.LoadBanksFromRMR(_rmr); + _rmr = 0xffff; // Reset RMR (all tasks start in ROM0) + + // Start in Emulator + _currentTask = _tasks[0]; - // Execute the initial task switch. - TaskSwitch(); - - _currentTask = _nextTask; - _nextTask = null; + // + // TODO: + // This is a hack of sorts, it ensures that the sector task initializes + // itself as soon as the Emulator task yields after the reset. (CopyDisk is broken otherwise due to the + // sector task stomping over the KBLK CopyDisk sets up after the reset. This is a race of sorts.) + // Unsure if there is a deeper issue here or if there are other reset semantics + // in play here. + // + WakeupTask(CPU.TaskType.DiskSector); Logging.Log.Write(Logging.LogComponent.CPU, "Silent Boot; microcode banks initialized to {0}", Conversion.ToOctal(_rmr)); } @@ -173,7 +183,8 @@ namespace Contralto.CPU public void WakeupTask(TaskType task) { if (_tasks[(int)task] != null) - { + { + Log.Write(LogComponent.TaskSwitch, "Wakeup enabled for Task {0}", task); _tasks[(int)task].WakeupTask(); } } @@ -186,7 +197,8 @@ namespace Contralto.CPU public void BlockTask(TaskType task) { if (_tasks[(int)task] != null) - { + { + Log.Write(LogComponent.TaskSwitch, "Removed wakeup for Task {0}", task); _tasks[(int)task].BlockTask(); } } @@ -218,8 +230,15 @@ namespace Contralto.CPU for (int i = _tasks.Length - 1; i >= 0; i--) { if (_tasks[i] != null && _tasks[i].Wakeup) - { + { _nextTask = _tasks[i]; + + if (_nextTask != _currentTask && _currentTask != null) + { + Log.Write(LogComponent.TaskSwitch, "TASK: Next task will be {0} (pri {1}); current task {2} (pri {3})", + (TaskType)_nextTask.Priority, _nextTask.Priority, + (TaskType)_currentTask.Priority, _currentTask.Priority); + } break; } } diff --git a/Contralto/CPU/Tasks/DiskTask.cs b/Contralto/CPU/Tasks/DiskTask.cs index 4188b70..9b1eb8b 100644 --- a/Contralto/CPU/Tasks/DiskTask.cs +++ b/Contralto/CPU/Tasks/DiskTask.cs @@ -1,4 +1,5 @@ using Contralto.IO; +using Contralto.Logging; using System; namespace Contralto.CPU @@ -22,6 +23,8 @@ namespace Contralto.CPU protected override bool ExecuteInstruction(MicroInstruction instruction) { + // Log.Write(LogComponent.Debug, "{0}: {1}", Conversion.ToOctal(_mpc), UCodeDisassembler.DisassembleInstruction(instruction, _taskType)); + bool task = base.ExecuteInstruction(instruction); // Deal with SECLATE semantics: If the Disk Sector task wakes up and runs before @@ -32,13 +35,7 @@ namespace Contralto.CPU { // Sector task is running; clear enable for seclate signal _diskController.DisableSeclate(); - } - - /* - if (_taskType == TaskType.DiskWord) - { - _wakeup = false; - } */ + } return task; } @@ -170,32 +167,32 @@ namespace Contralto.CPU // "NEXT <- NEXT OR (IF fatal error in latches THEN 0 ELSE 1)" _nextModifier |= GetInitModifier(instruction); - if (true) //!_diskController.FatalError) + if (!_diskController.FatalError) { _nextModifier |= 0x1; } else { - Console.WriteLine("fatal disk error"); + Console.WriteLine("fatal disk error on disk {0}", _diskController.Drive); } break; case DiskF2.STROBON: // "NEXT <- NEXT OR (IF seek strobe still on THEN 1 ELSE 0)" _nextModifier |= GetInitModifier(instruction); - if ((_diskController.KSTAT & 0x0040) == 0x0040) + if ((_diskController.KSTAT & DiskController.STROBE) != 0) { _nextModifier |= 0x1; } break; case DiskF2.SWRNRDY: - // "NEXT <- NEXT OR (IF disk not ready to accept command THEN 1 ELSE 0) - // for now, always zero (not sure when this would be 1 yet) + // "NEXT <- NEXT OR (IF disk not ready to accept command THEN 1 ELSE 0) _nextModifier |= GetInitModifier(instruction); if (!_diskController.Ready) { - _nextModifier |= 1; + Console.WriteLine("disk {0} not ready", _diskController.Drive); + _nextModifier |= 0x1; } break; diff --git a/Contralto/CPU/Tasks/EmulatorTask.cs b/Contralto/CPU/Tasks/EmulatorTask.cs index 96fdb00..44c33e6 100644 --- a/Contralto/CPU/Tasks/EmulatorTask.cs +++ b/Contralto/CPU/Tasks/EmulatorTask.cs @@ -105,6 +105,11 @@ namespace Contralto.CPU // BOOT (soft-reset) operation. // Reset the CPU using the current RMR (start tasks in RAM or ROM as specified.) _cpu.SoftReset(); + + // Since this is a soft reset, we don't want MPC to be taken from the NEXT + // field at the end of the cycle, setting this flag causes the main Task + // implementation to skip updating _mpc at the end of this instruction. + _softReset = true; } else if(_busData != 0) { @@ -139,11 +144,17 @@ namespace Contralto.CPU break; case EmulatorF1.LoadESRB: - // For now, this is always 0; we do not yet support the 3K RAM system with 8 banks of S registers. - _rb = 0; - Logging.Log.Write(Logging.LogType.Warning, Logging.LogComponent.EmulatorTask, "ESRB<- ({0}) not fully implemented.", - Conversion.ToOctal((_busData & 0xe) >> 1)); - //_rb = (ushort)((_busData & 0xe) >> 1); + // For now, this is always 0; we do not yet support the 3K RAM system with 8 banks of S registers. + _rb = (ushort)((_busData & 0xe) >> 1); + + if (_rb != 0) + { + _rb = 0; + Logging.Log.Write(Logging.LogType.Warning, Logging.LogComponent.EmulatorTask, "ESRB<- ({0}) not fully implemented.", + Conversion.ToOctal((_busData & 0xe) >> 1)); + + throw new NotImplementedException("ESRB<-"); + } break; default: diff --git a/Contralto/CPU/Tasks/Task.cs b/Contralto/CPU/Tasks/Task.cs index 2f0f232..3fa1ada 100644 --- a/Contralto/CPU/Tasks/Task.cs +++ b/Contralto/CPU/Tasks/Task.cs @@ -56,6 +56,14 @@ namespace Contralto.CPU _rb = 0; } + public virtual void SoftReset() + { + // + // As above but we leave all other state alone. + // + _mpc = (ushort)_taskType; + } + public virtual void BlockTask() { _wakeup = false; @@ -98,6 +106,7 @@ namespace Contralto.CPU _rSelect = 0; _srSelect = 0; _busData = 0; + _softReset = false; Shifter.SetMagic(false); @@ -414,9 +423,8 @@ namespace Contralto.CPU // this depends on the value of the NEXT field in this instruction // if (swMode) - { - //Console.WriteLine("SWMODE NEXT {0} Modifier {1}", Conversion.ToOctal(instruction.NEXT), Conversion.ToOctal(nextModifier)); - UCodeMemory.SwitchMode((ushort)(instruction.NEXT), _taskType); + { + UCodeMemory.SwitchMode(instruction.NEXT, _taskType); Logging.Log.Write(Logging.LogComponent.Microcode, "SWMODE: uPC {0}, next uPC {1}", Conversion.ToOctal(_mpc), Conversion.ToOctal(instruction.NEXT | nextModifier)); } @@ -430,8 +438,12 @@ namespace Contralto.CPU // // Select next address, using the address modifier from the last instruction. + // (Unless a soft reset occurred during this instruction) // - _mpc = (ushort)(instruction.NEXT | nextModifier); + if (!_softReset) + { + _mpc = (ushort)(instruction.NEXT | nextModifier); + } return nextTask; } @@ -486,15 +498,16 @@ namespace Contralto.CPU // // TODO: maybe instead of these being shared (which feels kinda bad) // these could be encapsulated in an object and passed to subclass implementations? - protected ushort _busData; // Data placed onto the bus (ANDed from multiple sources) - protected ushort _nextModifier; // Bits ORed onto the NEXT field of the current instruction - protected uint _rSelect; // RSELECT field from current instruction, potentially modified by task - protected uint _srSelect; // RSELECT field as used by S register access (not modified in the same way as normal _rSelect). - protected bool _loadS; // Whether to load S from M at and of cycle - protected bool _loadR; // Whether to load R from shifter at end of cycle. - protected bool _rdRam; // Whether to load uCode RAM onto the bus during the next cycle. - protected bool _wrtRam; // Whether to write uCode RAM from M and ALU outputs during the next cycle. - protected bool _swMode; // Whether to switch uCode banks during the next cycle. + protected ushort _busData; // Data placed onto the bus (ANDed from multiple sources) + protected ushort _nextModifier; // Bits ORed onto the NEXT field of the current instruction + protected uint _rSelect; // RSELECT field from current instruction, potentially modified by task + protected uint _srSelect; // RSELECT field as used by S register access (not modified in the same way as normal _rSelect). + protected bool _loadS; // Whether to load S from M at and of cycle + protected bool _loadR; // Whether to load R from shifter at end of cycle. + protected bool _rdRam; // Whether to load uCode RAM onto the bus during the next cycle. + protected bool _wrtRam; // Whether to write uCode RAM from M and ALU outputs during the next cycle. + protected bool _swMode; // Whether to switch uCode banks during the next cycle. + protected bool _softReset; // Whether this instruction caused a soft reset (so MPC should not come from instruction's NEXT field) // diff --git a/Contralto/CPU/UCodeMemory.cs b/Contralto/CPU/UCodeMemory.cs index 61be085..c8ff2ac 100644 --- a/Contralto/CPU/UCodeMemory.cs +++ b/Contralto/CPU/UCodeMemory.cs @@ -72,7 +72,7 @@ namespace Contralto.CPU public static void LoadBanksFromRMR(ushort rmr) { for(int i=0;i<16;i++) - { + { _microcodeBank[i] = (rmr & (1 << i)) == 0 ? MicrocodeBank.RAM0 : MicrocodeBank.ROM0; } } diff --git a/Contralto/Contralto.csproj b/Contralto/Contralto.csproj index 986efde..24dac31 100644 --- a/Contralto/Contralto.csproj +++ b/Contralto/Contralto.csproj @@ -160,7 +160,7 @@ PreserveNewest - PreserveNewest + Always PreserveNewest diff --git a/Contralto/Debugger.Designer.cs b/Contralto/Debugger.Designer.cs index d9f283f..b18af4a 100644 --- a/Contralto/Debugger.Designer.cs +++ b/Contralto/Debugger.Designer.cs @@ -97,6 +97,8 @@ this.Reg = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.RegValue = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.MemoryJumpToAddress = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); this._memoryData = new System.Windows.Forms.DataGridView(); this.Bkpt = new System.Windows.Forms.DataGridViewCheckBoxColumn(); this.Address = new System.Windows.Forms.DataGridViewTextBoxColumn(); @@ -116,8 +118,7 @@ this.dataGridViewTextBoxColumn9 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.dataGridViewTextBoxColumn10 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.dataGridViewTextBoxColumn11 = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.label3 = new System.Windows.Forms.Label(); - this.MemoryJumpToAddress = new System.Windows.Forms.TextBox(); + this.HackButton = new System.Windows.Forms.Button(); this.Microcode.SuspendLayout(); this.SourceTabs.SuspendLayout(); this.Rom0Page.SuspendLayout(); @@ -270,7 +271,7 @@ this.Rom1Page.Location = new System.Drawing.Point(4, 22); this.Rom1Page.Name = "Rom1Page"; this.Rom1Page.Padding = new System.Windows.Forms.Padding(3); - this.Rom1Page.Size = new System.Drawing.Size(582, 545); + this.Rom1Page.Size = new System.Drawing.Size(582, 554); this.Rom1Page.TabIndex = 1; this.Rom1Page.Text = "ROM1"; this.Rom1Page.UseVisualStyleBackColor = true; @@ -369,7 +370,7 @@ this.Rom2Page.Location = new System.Drawing.Point(4, 22); this.Rom2Page.Name = "Rom2Page"; this.Rom2Page.Padding = new System.Windows.Forms.Padding(3); - this.Rom2Page.Size = new System.Drawing.Size(582, 545); + this.Rom2Page.Size = new System.Drawing.Size(582, 554); this.Rom2Page.TabIndex = 2; this.Rom2Page.Text = "RAM0"; this.Rom2Page.UseVisualStyleBackColor = true; @@ -750,6 +751,24 @@ this.groupBox4.TabStop = false; this.groupBox4.Text = "Memory"; // + // MemoryJumpToAddress + // + this.MemoryJumpToAddress.Location = new System.Drawing.Point(53, 276); + this.MemoryJumpToAddress.Name = "MemoryJumpToAddress"; + this.MemoryJumpToAddress.Size = new System.Drawing.Size(48, 20); + this.MemoryJumpToAddress.TabIndex = 15; + this.MemoryJumpToAddress.TabStop = false; + this.MemoryJumpToAddress.KeyDown += new System.Windows.Forms.KeyEventHandler(this.OnMemoryJumpAddressKeyDown); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 279); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(47, 13); + this.label3.TabIndex = 14; + this.label3.Text = "Jump to:"; + // // _memoryData // this._memoryData.AllowUserToAddRows = false; @@ -1026,29 +1045,22 @@ this.dataGridViewTextBoxColumn11.Resizable = System.Windows.Forms.DataGridViewTriState.False; this.dataGridViewTextBoxColumn11.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; // - // label3 + // HackButton // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(6, 279); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(47, 13); - this.label3.TabIndex = 14; - this.label3.Text = "Jump to:"; - // - // MemoryJumpToAddress - // - this.MemoryJumpToAddress.Location = new System.Drawing.Point(53, 276); - this.MemoryJumpToAddress.Name = "MemoryJumpToAddress"; - this.MemoryJumpToAddress.Size = new System.Drawing.Size(48, 20); - this.MemoryJumpToAddress.TabIndex = 15; - this.MemoryJumpToAddress.TabStop = false; - this.MemoryJumpToAddress.KeyDown += new System.Windows.Forms.KeyEventHandler(this.OnMemoryJumpAddressKeyDown); + this.HackButton.Location = new System.Drawing.Point(295, 955); + this.HackButton.Name = "HackButton"; + this.HackButton.Size = new System.Drawing.Size(36, 23); + this.HackButton.TabIndex = 15; + this.HackButton.Text = "hack"; + this.HackButton.UseVisualStyleBackColor = true; + this.HackButton.Click += new System.EventHandler(this.HackButton_Click); // // Debugger // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(949, 997); + this.Controls.Add(this.HackButton); this.Controls.Add(this.groupBox6); this.Controls.Add(this.NovaStep); this.Controls.Add(this.RunToNextTaskButton); @@ -1165,5 +1177,6 @@ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn11; private System.Windows.Forms.TextBox MemoryJumpToAddress; private System.Windows.Forms.Label label3; + private System.Windows.Forms.Button HackButton; } } \ No newline at end of file diff --git a/Contralto/Debugger.cs b/Contralto/Debugger.cs index 8b9e341..046d996 100644 --- a/Contralto/Debugger.cs +++ b/Contralto/Debugger.cs @@ -919,6 +919,10 @@ namespace Contralto // Nova Debugger breakpoints; same as above private bool[] _novaBreakpointEnabled; - + private void HackButton_Click(object sender, EventArgs e) + { + Logging.Log.LogComponents |= Logging.LogComponent.TaskSwitch; + Logging.Log.Write(Logging.LogComponent.Debug, "***** HACK HIT ******"); + } } } diff --git a/Contralto/Disk/Clark-Games.dsk b/Contralto/Disk/Clark-Games.dsk index f029879..9cd6130 100644 Binary files a/Contralto/Disk/Clark-Games.dsk and b/Contralto/Disk/Clark-Games.dsk differ diff --git a/Contralto/Disk/bravox.dsk b/Contralto/Disk/bravox.dsk index f4349ca..cdee65b 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 79ce944..9a5ba19 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 c901c5e..a2b05df 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 e4d8068..e3f86b3 100644 Binary files a/Contralto/Disk/gamesb.dsk and b/Contralto/Disk/gamesb.dsk differ diff --git a/Contralto/Disk/nonprog.dsk b/Contralto/Disk/nonprog.dsk index ed40c82..7724991 100644 Binary files a/Contralto/Disk/nonprog.dsk and b/Contralto/Disk/nonprog.dsk differ diff --git a/Contralto/Disk/st76boot.dsk b/Contralto/Disk/st76boot.dsk index eb44786..30c5abf 100644 Binary files a/Contralto/Disk/st76boot.dsk and b/Contralto/Disk/st76boot.dsk differ diff --git a/Contralto/Disk/tdisk4.dsk b/Contralto/Disk/tdisk4.dsk index 2f4e05d..385d482 100644 Binary files a/Contralto/Disk/tdisk4.dsk and b/Contralto/Disk/tdisk4.dsk differ diff --git a/Contralto/Disk/xmsmall.dsk b/Contralto/Disk/xmsmall.dsk index a56b9d6..b8a7c3b 100644 Binary files a/Contralto/Disk/xmsmall.dsk and b/Contralto/Disk/xmsmall.dsk differ diff --git a/Contralto/IO/DiskController.cs b/Contralto/IO/DiskController.cs index b221b2b..b5a5bcd 100644 --- a/Contralto/IO/DiskController.cs +++ b/Contralto/IO/DiskController.cs @@ -110,9 +110,7 @@ namespace Contralto.IO // Select disk if _sendAdr is true _disk = (_kAdr & 0x1); _seeking = false; - - /* - + // Clear the NOTREADY flag depending on whether the drive is loaded or not if (_drives[_disk].IsLoaded) { @@ -121,7 +119,7 @@ namespace Contralto.IO else { _kStat |= NOTREADY; - } */ + } } } @@ -182,7 +180,7 @@ namespace Contralto.IO public int Drive { - get { return 0; } + get { return _disk; } } public double ClocksUntilNextSector @@ -198,7 +196,7 @@ namespace Contralto.IO // This is true if the drive is: // - powered on, loaded with a disk, spun up // - not actively seeking - return _drives[0].IsLoaded; + return _drives[_disk].IsLoaded && !_seeking; } } @@ -253,7 +251,7 @@ namespace Contralto.IO _drives[0].Reset(); _drives[1].Reset(); - // Create events to be reused during execution + // Create events to be reused during execution // Schedule the first sector immediately. _sectorEvent = new Event(0, null, SectorCallback); @@ -278,7 +276,7 @@ namespace Contralto.IO // // Next sector; move to next sector and wake up Disk Sector task. // - _sector = (_sector + 1) % 12; + _sector = (_sector + 1) % 12; _kStat = (ushort)((_kStat & 0x0fff) | (_sector << 12)); @@ -295,6 +293,8 @@ namespace Contralto.IO if ((_kStat & STROBE) == 0) { Log.Write(LogType.Verbose, LogComponent.DiskController, "Waking up sector task for C/H/S {0}/{1}/{2}", SelectedDrive.Cylinder, SelectedDrive.Head, _sector); + Log.Write(LogType.Verbose, LogComponent.DiskController, "KADR is {0}", Conversion.ToOctal(_kAdr)); + Log.Write(LogType.Verbose, LogComponent.DiskController, "KDATA is {0}", Conversion.ToOctal(_kDataWrite)); _system.CPU.WakeupTask(CPU.TaskType.DiskSector); // Reset SECLATE @@ -403,7 +403,7 @@ namespace Contralto.IO Log.Write(LogComponent.DiskController, "Seek failed, specified cylinder {0} is out of range.", destCylinder); _seeking = false; } - else + else if (destCylinder != SelectedDrive.Cylinder) { // Otherwise, start a seek. _destCylinder = destCylinder; @@ -423,6 +423,12 @@ namespace Contralto.IO Log.Write(LogComponent.DiskController, "Seek to {0} from {1} commencing. Will take {2} nsec.", _destCylinder, SelectedDrive.Cylinder, _seekDuration); } + else + { + // Clear the fail bit. + _kStat &= (ushort)~SEEKFAIL; + Log.Write(LogComponent.DiskController, "Seek is a no op ({0} to {1}).", destCylinder, SelectedDrive.Cylinder); + } } /// @@ -685,7 +691,7 @@ namespace Contralto.IO // SECLATE data. // 8.5uS for seclate delay (approx. 50 clocks) - private static ulong _seclateDuration = (ulong)(85.0 * Conversion.UsecToNsec * _scale); + private static ulong _seclateDuration = (ulong)(20.0 * Conversion.UsecToNsec * _scale); private bool _seclateEnable; private bool _seclate; private Event _seclateEvent; @@ -698,10 +704,10 @@ namespace Contralto.IO private bool _debugRead; // KSTAT bitfields - private readonly ushort SECLATE = 0x10; - private readonly ushort NOTREADY = 0x20; - private readonly ushort STROBE = 0x40; - private readonly ushort SEEKFAIL = 0x80; + public static readonly ushort SECLATE = 0x10; + public static readonly ushort NOTREADY = 0x20; + public static readonly ushort STROBE = 0x40; + public static readonly ushort SEEKFAIL = 0x80; } } diff --git a/Contralto/Logging/Log.cs b/Contralto/Logging/Log.cs index 31c7263..4357653 100644 --- a/Contralto/Logging/Log.cs +++ b/Contralto/Logging/Log.cs @@ -1,4 +1,7 @@ -using System; +#define LOGGING_ENABLED + +using System; +using System.IO; namespace Contralto.Logging { @@ -21,8 +24,10 @@ namespace Contralto.Logging CPU = 0x200, EthernetController = 0x400, EthernetTask = 0x800, + TaskSwitch = 0x1000, - All = 0x7fffffff + Debug = 0x40000000, + All = 0x7fffffff } /// @@ -47,10 +52,19 @@ namespace Contralto.Logging static Log() { // TODO: make configurable - _components = LogComponent.None; // LogComponent.EthernetController; // | LogComponent.Microcode | LogComponent.Memory | LogComponent.CPU; - _type = LogType.Normal | LogType.Warning | LogType.Error; + _components = LogComponent.CPU; // 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"); } + public static LogComponent LogComponents + { + get { return _components; } + set { _components = value; } + } + +#if LOGGING_ENABLED /// /// Logs a message without specifying type/severity for terseness; /// will not log if Type has been set to None. @@ -72,10 +86,28 @@ namespace Contralto.Logging // My log has something to tell you... // TODO: color based on type, etc. Console.WriteLine(component.ToString() + ": " + message, args); + + if (_logStream != null) + { + _logStream.WriteLine(component.ToString() + ": " + message, args); + } } } +#else + public static void Write(LogComponent component, string message, params object[] args) + { + + } + + public static void Write(LogType type, LogComponent component, string message, params object[] args) + { + + } + +#endif private static LogComponent _components; private static LogType _type; + private static StreamWriter _logStream; } } diff --git a/Contralto/Memory/MemoryBus.cs b/Contralto/Memory/MemoryBus.cs index db17e90..39e1c6f 100644 --- a/Contralto/Memory/MemoryBus.cs +++ b/Contralto/Memory/MemoryBus.cs @@ -168,7 +168,7 @@ namespace Contralto.Memory _memoryAddress = address; _extendedMemoryReference = extendedMemoryReference; _task = task; - _memoryCycle = 1; + _memoryCycle = 1; } } @@ -190,6 +190,13 @@ namespace Contralto.Memory case 5: // Single word read //Log.Write(LogType.Verbose, LogComponent.Memory, "Single-word read of {0} from {1} (cycle 5)", Conversion.ToOctal(_memoryData), Conversion.ToOctal(_memoryAddress ^ 1)); + + // debug + /* + if (_memoryAddress == 0xfc90 && _task != TaskType.Emulator) // 176220 -- status word for disk + { + Logging.Log.Write(Logging.LogComponent.Debug, "--> Task {0} read {1} from 176220.", _task, _memoryData); + } */ return _memoryData; // *** @@ -212,11 +219,23 @@ namespace Contralto.Memory //Log.Write(LogType.Verbose, LogComponent.Memory, "Double-word read of {0} from {1} (cycle 6)", Conversion.ToOctal(_memoryData2), Conversion.ToOctal(_memoryAddress ^ 1)); _doubleWordMixed = false; + // debug + /* + if ((_memoryAddress ^ 1) == 0xfc90 && _task != TaskType.Emulator) // 176220 -- status word for disk + { + Logging.Log.Write(Logging.LogComponent.Debug, "--> Task {0} read {1} from 176220.", _task, _memoryData2); + } */ return _memoryData2; } else { _doubleWordMixed = false; + // debug + /* + if (_memoryAddress == 0xfc90 && _task != TaskType.Emulator) // 176220 -- status word for disk + { + Logging.Log.Write(Logging.LogComponent.Debug, "--> Task {0} read {1} from 176220.", _task, _memoryData); + } */ //Log.Write(LogType.Verbose, LogComponent.Memory, "Single-word read of {0} from {1} (post cycle 6)", Conversion.ToOctal(_memoryData), Conversion.ToOctal(_memoryAddress)); return _memoryData; } @@ -236,12 +255,21 @@ namespace Contralto.Memory throw new InvalidOperationException("Unexpected microcode behavior -- LoadMD during incorrect memory cycle."); case 3: + + // debug + if (_memoryAddress == 0xfc90 || _memoryAddress == 0xfc91 || _memoryAddress == 0x151) // 176220 -- status word for disk + { + Logging.Log.Write(Logging.LogComponent.Debug, "++> Task {0} wrote {1} to {3} (was {2}).", _task, Conversion.ToOctal(data), Conversion.ToOctal(DebugReadWord(_task, _memoryAddress)), Conversion.ToOctal(_memoryAddress)); + } + _memoryData = data; // Only really necessary to show in debugger // Start of doubleword write: WriteToBus(_memoryAddress, data, _task, _extendedMemoryReference); _doubleWordStore = true; _doubleWordMixed = true; + + /* Log.Write( LogType.Verbose, @@ -262,7 +290,22 @@ namespace Contralto.Memory Conversion.ToOctal(data), _doubleWordStore ? Conversion.ToOctal(_memoryAddress ^ 1) : Conversion.ToOctal(_memoryAddress)); */ - WriteToBus(_doubleWordStore ? (ushort)(_memoryAddress ^ 1) : _memoryAddress, data, _task, _extendedMemoryReference); + // debug + ushort actualAddress = _doubleWordStore ? (ushort)(_memoryAddress ^ 1) : _memoryAddress; + + /* + if (actualAddress == 0xfc90 || actualAddress == 0xfc91 || _memoryAddress == 0x151) // 176220 -- status word for disk + { + Logging.Log.Write(Logging.LogComponent.Debug, "--> Task {0} wrote {1} to {4} (was {2}). Extd {3}", _task, Conversion.ToOctal(data), Conversion.ToOctal(DebugReadWord(_task, actualAddress)), _extendedMemoryReference, Conversion.ToOctal(actualAddress)); + } */ + + WriteToBus(actualAddress, data, _task, _extendedMemoryReference); + + /* + if (actualAddress == 0xfc90 || actualAddress == 0xfc91 || _memoryAddress == 0x151) // 176220 -- status word for disk + { + Logging.Log.Write(Logging.LogComponent.Debug, "--> Now {0}.", Conversion.ToOctal(DebugReadWord(_task, actualAddress))); + } */ break; }