From 38124350fbc77d290c180ec396ca51260dcb645f Mon Sep 17 00:00:00 2001 From: Josh Dersch Date: Thu, 31 Aug 2017 12:23:46 -0700 Subject: [PATCH] Fixed Trident drive select issues, corrected issue with extended memory bank registers. IFS now runs. --- Contralto/AltoSystem.cs | 34 ++++---- Contralto/CPU/CPU.cs | 3 + Contralto/CPU/Tasks/Task.cs | 17 ++-- Contralto/CPU/UCodeDisassembler.cs | 68 ++++++++-------- Contralto/Configuration.cs | 5 ++ Contralto/IO/DiskPack.cs | 7 +- Contralto/IO/TridentController.cs | 121 ++++++++++++----------------- Contralto/IO/TridentDrive.cs | 65 ++++++++++++++++ Contralto/Memory/Memory.cs | 39 ++++++++-- Contralto/Program.cs | 2 +- Contralto/SdlUI/SdlConsole.cs | 2 +- Contralto/UI/AltoWindow.cs | 2 +- 12 files changed, 227 insertions(+), 138 deletions(-) diff --git a/Contralto/AltoSystem.cs b/Contralto/AltoSystem.cs index 989f06a..58d523d 100644 --- a/Contralto/AltoSystem.cs +++ b/Contralto/AltoSystem.cs @@ -94,7 +94,7 @@ namespace Contralto _displayController.DetachDisplay(); } - public void Shutdown() + public void Shutdown(bool commitDisks) { // Kill any host interface threads that are running. if (_ethernetController.HostInterface != null) @@ -107,15 +107,18 @@ namespace Contralto // _audioDAC.Shutdown(); - // - // Save disk contents - // - _diskController.CommitDisk(0); - _diskController.CommitDisk(1); - - for (int i = 0; i < 8; i++) + if (commitDisks) { - _tridentController.CommitDisk(i); + // + // Save disk contents + // + _diskController.CommitDisk(0); + _diskController.CommitDisk(1); + + for (int i = 0; i < 8; i++) + { + _tridentController.CommitDisk(i); + } } } @@ -210,11 +213,11 @@ namespace Contralto // switch (Path.GetExtension(path).ToLowerInvariant()) { - case ".t80": + case ".dsk80": geometry = DiskGeometry.TridentT80; break; - case ".t300": + case ".dsk300": geometry = DiskGeometry.TridentT300; break; @@ -228,11 +231,11 @@ namespace Contralto if (newImage) { - newPack = FileBackedDiskPack.CreateEmpty(geometry, path); + newPack = InMemoryDiskPack.CreateEmpty(geometry, path); } else { - newPack = FileBackedDiskPack.Load(geometry, path); + newPack = InMemoryDiskPack.Load(geometry, path); } _tridentController.Drives[drive].LoadPack(newPack); @@ -273,6 +276,11 @@ namespace Contralto get { return _cpu; } } + public Memory.Memory Memory + { + get { return _mem; } + } + public MemoryBus MemoryBus { get { return _memBus; } diff --git a/Contralto/CPU/CPU.cs b/Contralto/CPU/CPU.cs index 22201f8..124ffda 100644 --- a/Contralto/CPU/CPU.cs +++ b/Contralto/CPU/CPU.cs @@ -190,6 +190,9 @@ namespace Contralto.CPU Log.Write(LogComponent.CPU, "Silent Boot; microcode banks initialized to {0}", Conversion.ToOctal(_rmr)); UCodeMemory.LoadBanksFromRMR(_rmr); + // Booting / soft-reset of the Alto resets the XM bank registers to zero. + _system.Memory.SoftReset(); + // Reset RMR after reset. _rmr = 0xffff; diff --git a/Contralto/CPU/Tasks/Task.cs b/Contralto/CPU/Tasks/Task.cs index 3b01a14..cdde852 100644 --- a/Contralto/CPU/Tasks/Task.cs +++ b/Contralto/CPU/Tasks/Task.cs @@ -126,7 +126,14 @@ namespace Contralto.CPU /// An InstructionCompletion indicating whether this instruction calls for a task switch or not. public InstructionCompletion ExecuteNext() { - MicroInstruction instruction = UCodeMemory.GetInstruction(_mpc, _taskType); + MicroInstruction instruction = UCodeMemory.GetInstruction(_mpc, _taskType); + + /* + if (_taskType == TaskType.Emulator && UCodeMemory.GetBank(_taskType) == MicrocodeBank.RAM0) + { + Console.WriteLine("{0}: {1}", Conversion.ToOctal(_mpc), UCodeDisassembler.DisassembleInstruction(instruction, _taskType)); + }*/ + return ExecuteInstruction(instruction); } @@ -313,12 +320,12 @@ namespace Contralto.CPU // Do nothing. Well, that was easy. break; - case SpecialFunction1.LoadMAR: + case SpecialFunction1.LoadMAR: // Do MAR or XMAR reference based on whether F2 is MD<- (for Alto IIs), indicating an extended memory reference. _cpu._system.MemoryBus.LoadMAR( - aluData, - _taskType, - _systemType == SystemType.AltoI ? false : instruction.F2 == SpecialFunction2.StoreMD); + aluData, + _taskType, + _systemType == SystemType.AltoI ? false : instruction.F2 == SpecialFunction2.StoreMD); break; case SpecialFunction1.Task: diff --git a/Contralto/CPU/UCodeDisassembler.cs b/Contralto/CPU/UCodeDisassembler.cs index e082ecf..5d81da5 100644 --- a/Contralto/CPU/UCodeDisassembler.cs +++ b/Contralto/CPU/UCodeDisassembler.cs @@ -70,15 +70,15 @@ namespace Contralto.CPU break; case BusSource.ReadMD: - source = "←MD "; + source = "<-MD "; break; case BusSource.ReadMouse: - source = "←MOUSE "; + source = "<-MOUSE "; break; case BusSource.ReadDisp: - source = "←DISP "; + source = "<-DISP "; break; } } @@ -164,11 +164,11 @@ namespace Contralto.CPU if (instruction.F2 == SpecialFunction2.StoreMD) { - f1 = "XMAR← "; + f1 = "XMAR<- "; } else { - f1 = "MAR← "; + f1 = "MAR<- "; } break; @@ -181,15 +181,15 @@ namespace Contralto.CPU break; case SpecialFunction1.LLSH1: - f1 = "←L LSH 1 "; + f1 = "<-L LSH 1 "; break; case SpecialFunction1.LRSH1: - f1 = "←L RSH 1 "; + f1 = "<-L RSH 1 "; break; case SpecialFunction1.LLCY8: - f1 = "←L LCY 8 "; + f1 = "<-L LCY 8 "; break; case SpecialFunction1.Constant: @@ -233,11 +233,11 @@ namespace Contralto.CPU if ((task == TaskType.TridentInput || task == TaskType.TridentOutput) && instruction.BS == BusSource.None) { - f2 = "MD← KDTA "; + f2 = "MD<- KDTA "; } else if (instruction.F1 != SpecialFunction1.LoadMAR) { - f2 = "MD← "; + f2 = "MD<- "; } break; @@ -273,7 +273,7 @@ namespace Contralto.CPU break; } - load = String.Format("T← {0}", loadTFromALU ? operation : source); + load = String.Format("T<- {0}", loadTFromALU ? operation : source); } // Load L (and M) from ALU @@ -282,24 +282,24 @@ namespace Contralto.CPU if (string.IsNullOrEmpty(load)) { // T not loaded at all, L loaded from ALU - load = String.Format("L← {0}", operation); + load = String.Format("L<- {0}", operation); } else if (loadTFromALU) { // T loaded from ALU, L loaded from ALU - load = String.Format("L← {0}", load); + load = String.Format("L<- {0}", load); } else { // T loaded from bus source, L loaded from ALU - load = String.Format("L← {0}, {1}", operation, load); + load = String.Format("L<- {0}, {1}", operation, load); } } // Do writeback to selected R register from shifter output if (loadR) { - load = String.Format("$R{0}← {1}", + load = String.Format("$R{0}<- {1}", Conversion.ToOctal((int)rSelect), !string.IsNullOrEmpty(load) ? load : operation); } @@ -309,12 +309,12 @@ namespace Contralto.CPU { if (string.IsNullOrEmpty(load)) { - load = String.Format("$S{0}← M", + load = String.Format("$S{0}<- M", Conversion.ToOctal((int)rSelect)); } else { - load = String.Format("$S{0}← M, {1}", + load = String.Format("$S{0}<- M, {1}", Conversion.ToOctal((int)rSelect), load); } @@ -448,10 +448,10 @@ namespace Contralto.CPU return "RDRAM "; case EmulatorF1.LoadRMR: - return "RMR← "; + return "RMR<- "; case EmulatorF1.LoadESRB: - return "ESRB← "; + return "ESRB<- "; case EmulatorF1.RSNF: return "RSNF "; @@ -481,13 +481,13 @@ namespace Contralto.CPU return "MAGIC "; case EmulatorF2.LoadDNS: - return "DNS← "; + return "DNS<- "; case EmulatorF2.BUSODD: return "BUSODD "; case EmulatorF2.LoadIR: - return "IR← "; + return "IR<- "; case EmulatorF2.IDISP: return "IDISP "; @@ -507,13 +507,13 @@ namespace Contralto.CPU return "OrbitBlock "; case OrbitF1.OrbitDeltaWC: - return "←OrbitDeltaWC "; + return "<-OrbitDeltaWC "; case OrbitF1.OrbitDBCWidthRead: - return "←OrbitDBCWidthRead "; + return "<-OrbitDBCWidthRead "; case OrbitF1.OrbitStatus: - return "←OrbitStatus "; + return "<-OrbitStatus "; default: return String.Format("Orbit F1 {0}", Conversion.ToOctal((int)of1)); @@ -527,25 +527,25 @@ namespace Contralto.CPU switch (of2) { case OrbitF2.OrbitDBCWidthSet: - return "OrbitDBCWidthSet← "; + return "OrbitDBCWidthSet<- "; case OrbitF2.OrbitXY: - return "OrbitXY← "; + return "OrbitXY<- "; case OrbitF2.OrbitHeight: - return "OrbitHeight← "; + return "OrbitHeight<- "; case OrbitF2.OrbitFontData: - return "OrbitFontData← "; + return "OrbitFontData<- "; case OrbitF2.OrbitInk: - return "OrbitInk← "; + return "OrbitInk<- "; case OrbitF2.OrbitControl: - return "OrbitControl← "; + return "OrbitControl<- "; case OrbitF2.OrbitROSCommand: - return "OrbitROSCommand← "; + return "OrbitROSCommand<- "; default: return String.Format("Orbit F2 {0}", Conversion.ToOctal((int)of2)); @@ -562,10 +562,10 @@ namespace Contralto.CPU return "EMPTY "; case TridentF2.KTAG: - return "KTAG← "; + return "KTAG<- "; case TridentF2.ReadKDTA: - return "←KDTA "; + return "<-KDTA "; case TridentF2.RESET: return "RESET "; @@ -578,7 +578,7 @@ namespace Contralto.CPU return "WAIT "; case TridentF2.WriteKDTA: - return "KDTA← "; + return "KDTA<- "; default: return String.Format("Trident F2 {0}", Conversion.ToOctal((int)tf2)); diff --git a/Contralto/Configuration.cs b/Contralto/Configuration.cs index 7df5fbc..d805586 100644 --- a/Contralto/Configuration.cs +++ b/Contralto/Configuration.cs @@ -134,6 +134,11 @@ namespace Contralto // // If configuration specifies fewer than 8 Trident disks, we need to pad the list out to 8 with empty entries. // + if (TridentImages == null) + { + TridentImages = new StringCollection(); + } + int start = TridentImages.Count; for (int i = start; i < 8; i++) { diff --git a/Contralto/IO/DiskPack.cs b/Contralto/IO/DiskPack.cs index 8f89854..ce09d44 100644 --- a/Contralto/IO/DiskPack.cs +++ b/Contralto/IO/DiskPack.cs @@ -447,7 +447,7 @@ namespace Contralto.IO for (int head = 0; head < _geometry.Heads; head++) { for (int sector = 0; sector < _geometry.Sectors; sector++) - { + { _sectors[cylinder, head, sector].WriteToStream(imageStream); } } @@ -601,9 +601,8 @@ namespace Contralto.IO private long GetOffsetForSector(int cylinder, int head, int sector) { - int sectorNumber = (cylinder * _geometry.Heads * _geometry.Sectors) + - (head * _geometry.Sectors) + - sector; + int sectorNumber = (cylinder * _geometry.Heads + head) * _geometry.Sectors + // total sectors for current track + sector; // + current sector return sectorNumber * _geometry.SectorGeometry.GetSectorSizeBytes(); } diff --git a/Contralto/IO/TridentController.cs b/Contralto/IO/TridentController.cs index f2f2504..1007bc8 100644 --- a/Contralto/IO/TridentController.cs +++ b/Contralto/IO/TridentController.cs @@ -38,6 +38,11 @@ namespace Contralto.IO { _system = system; + // + // We initialize 16 drives even though the + // controller only technically supports 8. + // TODO: detail + // _drives = new TridentDrive[16]; for(int i=0;i<_drives.Length;i++) @@ -55,9 +60,7 @@ namespace Contralto.IO _seekIncomplete = false; _headOverflow = false; _deviceCheck = false; - _notSelected = false; - _notOnline = false; - _notReady = false; + _notSelected = false; _sectorOverflow = false; _outputLate = false; _inputLate = false; @@ -79,7 +82,6 @@ namespace Contralto.IO _sectorEvent = new Event(0, null, SectorCallback); _outputFifoEvent = new Event(0, null, OutputFifoCallback); - _seekEvent = new Event(0, null, SeekCallback); _readWordEvent = new Event(0, null, ReadWordCallback); // And schedule the first sector pulse. @@ -95,8 +97,6 @@ namespace Contralto.IO _headOverflow = false; _deviceCheck = false; _notSelected = false; - _notOnline = false; - _notReady = false; _sectorOverflow = false; _outputLate = false; _inputLate = false; @@ -249,7 +249,7 @@ namespace Contralto.IO (_headOverflow ? 0x4000 : 0) | (_deviceCheck ? 0x2000 : 0) | (_notSelected ? 0x1000 : 0) | - (_notOnline ? 0x0800 : 0) | + (NotOnline() ? 0x0800 : 0) | (NotReady() ? 0x0400 : 0) | (_sectorOverflow ? 0x0200 : 0) | (_outputLate ? 0x0100 : 0) | @@ -287,7 +287,14 @@ namespace Contralto.IO private bool NotReady() { - return _notReady | !SelectedDrive.IsLoaded; + return SelectedDrive.NotReady | + !SelectedDrive.IsLoaded | + _selectedDrive > 7; + } + + private bool NotOnline() + { + return _selectedDrive < 8 ? !SelectedDrive.IsLoaded : true; } private void WriteOutputFifo(int value) @@ -550,7 +557,21 @@ namespace Contralto.IO break; case 3: // Set Drive + // We take all four drive-select bits even though only 8 drives are actually supported. + // The high bit is used by many trident utilities to select an invalid drive to test for + // the presence of the 8-drive multiplexer. _selectedDrive = fifoWord & 0xf; + + if (_selectedDrive > 7) + { + _system.CPU.BlockTask(TaskType.TridentOutput); + _notSelected = true; + } + else + { + _notSelected = false; + } + Log.Write(LogComponent.TridentController, "Command is Set Drive {0}", _selectedDrive); break; } @@ -636,48 +657,7 @@ namespace Contralto.IO private void InitSeek(int destCylinder) { - if (destCylinder > SelectedDrive.Pack.Geometry.Cylinders - 1) - { - Log.Write(LogType.Error, LogComponent.TridentController, "Specified cylinder {0} is out of range. Seek aborted.", destCylinder); - _deviceCheck = true; - return; - } - - int currentCylinder = SelectedDrive.Cylinder; - if (destCylinder != currentCylinder) - { - // Do a seek. - _notReady = true; - - _destCylinder = destCylinder; - - // - // I can't find a specific formula for seek timing; the Century manual says: - // "Positioning time for seeking to the next cylinder is normally 6ms, and - // for full seeks (814 cylinder differerence) it is 55ms." - // - // I'm just going to fudge this for now and assume a linear ramp; this is not - // accurate but it's not all that important. - // - _seekDuration = (ulong)((6.0 + 0.602 * Math.Abs(currentCylinder - destCylinder)) * Conversion.MsecToNsec); - - Log.Write(LogComponent.TridentController, "Commencing seek from {0} to {1}. Seek time is {2}ns", destCylinder, currentCylinder, _seekDuration); - - _seekEvent.TimestampNsec = _seekDuration; - _system.Scheduler.Schedule(_seekEvent); - } - else - { - Log.Write(LogComponent.TridentController, "Seek is a no-op."); - } - } - - private void SeekCallback(ulong timeNsec, ulong skewNsec, object context) - { - Log.Write(LogComponent.TridentDisk, "Seek to {0} complete.", _destCylinder); - - SelectedDrive.Cylinder = _destCylinder; - _notReady = false; + _deviceCheck = !SelectedDrive.Seek(destCylinder); } private void InitRead() @@ -786,7 +766,7 @@ namespace Contralto.IO } else { - Log.Write(LogComponent.TridentController, "CHS {0}/{1}/{2} {3} read complete.", SelectedDrive.Cylinder, SelectedDrive.Head, _sector, _sectorBlock); + Log.Write(LogComponent.TridentController, "CHS {0}/{1}/{2} {3} read from drive {4} complete.", SelectedDrive.Cylinder, SelectedDrive.Head, _sector, _sectorBlock, _selectedDrive); _readState = ReadState.Idle; _sectorBlock++; @@ -847,7 +827,7 @@ namespace Contralto.IO _writeWordCount--; if (_writeWordCount <= 0) { - Log.Write(LogComponent.TridentController, "CHS {0}/{1}/{2} {3} write complete. {4} words written.", SelectedDrive.Cylinder, SelectedDrive.Head, _sector, _sectorBlock, _writeIndex); + Console.WriteLine( "CHS {0}/{1}/{2} {3} write to drive {4} complete. {5} words written.", SelectedDrive.Cylinder, SelectedDrive.Head, _sector, _sectorBlock, _selectedDrive, _writeIndex); _writeState = WriteState.Idle; _writeIndex = 0; @@ -857,19 +837,24 @@ namespace Contralto.IO } private void SectorCallback(ulong timeNsec, ulong skewNsec, object context) - { + { // Move to the next sector. - _sector = (_sector + 1) % 9; - SelectedDrive.Sector = _sector; - - // Reset to the first block (header) in the sector. - _sectorBlock = SectorBlock.Header; - - // Wake up the Output task if RunEnable is true and the drive is ready. if (_runEnable && !NotReady()) { + _sector = (_sector + 1) % 9; + SelectedDrive.Sector = _sector; + + // Reset to the first block (header) in the sector. + _sectorBlock = SectorBlock.Header; + + // Wake up the Output task _system.CPU.WakeupTask(TaskType.TridentOutput); } + else + { + // Keep the output task asleep. + _system.CPU.BlockTask(TaskType.TridentOutput); + } // // Schedule the next sector pulse @@ -894,6 +879,7 @@ namespace Contralto.IO { get { return _drives[_selectedDrive]; } } + // // Input FIFO semantics @@ -1033,9 +1019,7 @@ namespace Contralto.IO private bool _seekIncomplete; private bool _headOverflow; private bool _deviceCheck; - private bool _notSelected; - private bool _notOnline; - private bool _notReady; + private bool _notSelected; private bool _sectorOverflow; private bool _outputLate; private bool _inputLate; @@ -1044,20 +1028,13 @@ namespace Contralto.IO private bool _offset; // Current sector - private int _sector; + private int _sector; /// /// Drive timings /// private static ulong _sectorDuration = (ulong)((16.66666 / 9.0) * Conversion.MsecToNsec); // time in nsec for one sector -- 9 sectors, 16.66ms per rotation - private Event _sectorEvent; - - // - // Seek timings - // - private static ulong _seekDuration = (6 * Conversion.MsecToNsec); - private Event _seekEvent; - private int _destCylinder; + private Event _sectorEvent; // Output FIFO. This is actually 17-bits wide (the 17th bit is the Tag bit). private Queue _outputFifo; diff --git a/Contralto/IO/TridentDrive.cs b/Contralto/IO/TridentDrive.cs index d256cac..e9e7788 100644 --- a/Contralto/IO/TridentDrive.cs +++ b/Contralto/IO/TridentDrive.cs @@ -29,6 +29,8 @@ namespace Contralto.IO public TridentDrive(AltoSystem system) { _system = system; + + _seekEvent = new Event(0, null, SeekCallback); Reset(); } @@ -38,6 +40,8 @@ namespace Contralto.IO _cylinder = 0; _head = 0; + _notReady = false; + UpdateTrackCache(); } @@ -82,6 +86,11 @@ namespace Contralto.IO get { return _pack != null; } } + public bool NotReady + { + get { return _notReady; } + } + public IDiskPack Pack { get { return _pack; } @@ -124,6 +133,45 @@ namespace Contralto.IO get { return false; } } + public bool Seek(int destCylinder) + { + if (destCylinder > _pack.Geometry.Cylinders - 1) + { + Log.Write(LogType.Error, LogComponent.TridentController, "Specified cylinder {0} is out of range. Seek aborted, device check raised.", destCylinder); + return false; + } + + int currentCylinder = _cylinder; + if (destCylinder != currentCylinder) + { + // Do a seek. + _notReady = true; + + _destCylinder = destCylinder; + + // + // I can't find a specific formula for seek timing; the Century manual says: + // "Positioning time for seeking to the next cylinder is normally 6ms, and + // for full seeks (814 cylinder differerence) it is 55ms." + // + // I'm just going to fudge this for now and assume a linear ramp; this is not + // accurate but it's not all that important. + // + _seekDuration = (ulong)((6.0 + 0.602 * Math.Abs(currentCylinder - destCylinder)) * Conversion.MsecToNsec); + + Log.Write(LogComponent.TridentController, "Commencing seek from {0} to {1}. Seek time is {2}ns", destCylinder, currentCylinder, _seekDuration); + + _seekEvent.TimestampNsec = _seekDuration; + _system.Scheduler.Schedule(_seekEvent); + } + else + { + Log.Write(LogComponent.TridentController, "Seek is a no-op."); + } + + return true; + } + public ushort ReadHeader(int wordOffset) { if (wordOffset >= SectorGeometry.Trident.HeaderSize) @@ -223,6 +271,14 @@ namespace Contralto.IO } } + private void SeekCallback(ulong timeNsec, ulong skewNsec, object context) + { + Log.Write(LogComponent.TridentDisk, "Seek to {0} complete.", _destCylinder); + + Cylinder = _destCylinder; + _notReady = false; + } + // // Sector management. We load in an entire track's worth of sectors at a time. // When the head or cylinder changes, UpdateTrackCache must be called. @@ -276,6 +332,15 @@ namespace Contralto.IO // The pack loaded into the drive IDiskPack _pack; + // Drive status + private bool _notReady; + + // Seek status and control + private static ulong _seekDuration; + private Event _seekEvent; + private int _destCylinder; + + // // The track cache // diff --git a/Contralto/Memory/Memory.cs b/Contralto/Memory/Memory.cs index 8cf4274..950bcd3 100644 --- a/Contralto/Memory/Memory.cs +++ b/Contralto/Memory/Memory.cs @@ -56,24 +56,42 @@ namespace Contralto.Memory get { return _memTop; } } + /// + /// Full reset, clears all memory. + /// public void Reset() { // 4 64K banks, regardless of system type. (Alto Is just won't use the extra memory.) _mem = new ushort[0x40000]; _xmBanks = new ushort[16]; + _xmBanksAlternate = new int[16]; + _xmBanksNormal = new int[16]; + } + + /// + /// Soft reset, clears XM bank registers. + /// + public void SoftReset() + { + _xmBanks = new ushort[16]; + _xmBanksAlternate = new int[16]; + _xmBanksNormal = new int[16]; } public ushort Read(int address, TaskType task, bool extendedMemory) { // Check for XM registers; this occurs regardless of XM flag since it's in the I/O page. if (address >= _xmBanksStart && address < _xmBanksStart + 16) - { + { + // NB: While not specified in documentatino, some code (IFS in particular) relies on the fact that + // the upper 12 bits of the bank registers are all 1s. return (ushort)(0xfff0 | _xmBanks[address - _xmBanksStart]); } else { address += 0x10000 * GetBankNumber(task, extendedMemory); - return _mem[address]; + + return _mem[address]; } } @@ -81,17 +99,22 @@ namespace Contralto.Memory { // Check for XM registers; this occurs regardless of XM flag since it's in the I/O page. if (address >= _xmBanksStart && address < _xmBanksStart + 16) - { + { _xmBanks[address - _xmBanksStart] = data; + + // Precalc bank numbers to speed memory accesses that use them + _xmBanksAlternate[address - _xmBanksStart] = data & 0x3; + _xmBanksNormal[address - _xmBanksStart] = (data & 0xc) >> 2; + Log.Write(LogComponent.Memory, "XM register for task {0} set to bank {1} (normal), {2} (xm)", (TaskType)(address - _xmBanksStart), (data & 0xc) >> 2, - (data & 0x3)); + (data & 0x3)); } else { address += 0x10000 * GetBankNumber(task, extendedMemory); - _mem[address] = data; + _mem[address] = data; } } @@ -102,7 +125,7 @@ namespace Contralto.Memory private int GetBankNumber(TaskType task, bool extendedMemory) { - return extendedMemory ? (_xmBanks[(int)task]) & 0x3 : ((_xmBanks[(int)task]) & 0xc) >> 2; + return extendedMemory ? _xmBanksAlternate[(int)task] : _xmBanksNormal[(int)task]; } private readonly MemoryRange[] _addresses; @@ -112,6 +135,8 @@ namespace Contralto.Memory private ushort[] _mem; - private ushort[] _xmBanks; + private ushort[] _xmBanks; + private int[] _xmBanksAlternate; + private int[] _xmBanksNormal; } } diff --git a/Contralto/Program.cs b/Contralto/Program.cs index 1e35f04..20cbf01 100644 --- a/Contralto/Program.cs +++ b/Contralto/Program.cs @@ -128,7 +128,7 @@ namespace Contralto { Console.WriteLine("Exiting..."); - _system.Shutdown(); + _system.Shutdown(false /* don't commit disks */); // // Commit current configuration to disk diff --git a/Contralto/SdlUI/SdlConsole.cs b/Contralto/SdlUI/SdlConsole.cs index f1f7d85..cdd1f2b 100644 --- a/Contralto/SdlUI/SdlConsole.cs +++ b/Contralto/SdlUI/SdlConsole.cs @@ -87,7 +87,7 @@ namespace Contralto.SdlUI // _controller.StopExecution(); - _system.Shutdown(); + _system.Shutdown(true /* commit disk contents */); // // The Alto window was closed, shut down the CLI. diff --git a/Contralto/UI/AltoWindow.cs b/Contralto/UI/AltoWindow.cs index 0a6b702..4459231 100644 --- a/Contralto/UI/AltoWindow.cs +++ b/Contralto/UI/AltoWindow.cs @@ -408,7 +408,7 @@ namespace Contralto // Halt the system and detach our display _controller.StopExecution(); _system.DetachDisplay(); - _system.Shutdown(); + _system.Shutdown(true /* commit disk contents */); // // Commit current configuration to disk