diff --git a/Contralto.sln b/Contralto.sln index 6833d96..d83d932 100644 --- a/Contralto.sln +++ b/Contralto.sln @@ -8,6 +8,9 @@ EndProject Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "ContraltoSetup", "ContraltoSetup\ContraltoSetup.wixproj", "{47BBC195-80C5-43F3-B691-7D27B0803B84}" EndProject Global + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 diff --git a/Contralto/CPU/MicroInstruction.cs b/Contralto/CPU/MicroInstruction.cs index 05ed1d9..bc3b178 100644 --- a/Contralto/CPU/MicroInstruction.cs +++ b/Contralto/CPU/MicroInstruction.cs @@ -220,7 +220,7 @@ namespace Contralto.CPU F1 == SpecialFunction1.Constant || F2 == SpecialFunction2.Constant; - ConstantAccessOrBS4 = ConstantAccess || (int)BS > 4; + BS4 = ((int)BS > 4); // Constant ROM access: // "The constant memory is gated to the bus by F1=7, F2=7, or BS>4. The constant memory is addressed by the @@ -308,7 +308,7 @@ namespace Contralto.CPU // Metadata about the instruction that can be precalculated and used during execution public bool ConstantAccess; - public bool ConstantAccessOrBS4; + public bool BS4; public ushort ConstantValue; public bool MemoryAccess; public MemoryOperation MemoryOperation; diff --git a/Contralto/CPU/Tasks/DiskTask.cs b/Contralto/CPU/Tasks/DiskTask.cs index 2f5db63..b35263b 100644 --- a/Contralto/CPU/Tasks/DiskTask.cs +++ b/Contralto/CPU/Tasks/DiskTask.cs @@ -128,7 +128,7 @@ namespace Contralto.CPU switch (df2) { case DiskF2.INIT: - _nextModifier |= GetInitModifier(instruction); + _nextModifier |= GetInitModifier(); break; case DiskF2.RWC: @@ -138,7 +138,7 @@ namespace Contralto.CPU // by INCREC by the microcode to present the next set of bits. int command = (_diskController.KADR & 0x00c0) >> 6; - _nextModifier |= GetInitModifier(instruction); + _nextModifier |= GetInitModifier(); switch (command) { @@ -161,7 +161,7 @@ namespace Contralto.CPU case DiskF2.XFRDAT: // "NEXT <- NEXT OR (IF current command wants data transfer THEN 1 ELSE 0) - _nextModifier |= GetInitModifier(instruction); + _nextModifier |= GetInitModifier(); if (_diskController.DataXfer) { @@ -170,13 +170,13 @@ namespace Contralto.CPU break; case DiskF2.RECNO: - _nextModifier |= GetInitModifier(instruction); + _nextModifier |= GetInitModifier(); _nextModifier |= _diskController.RECNO; break; case DiskF2.NFER: // "NEXT <- NEXT OR (IF fatal error in latches THEN 0 ELSE 1)" - _nextModifier |= GetInitModifier(instruction); + _nextModifier |= GetInitModifier(); if (!_diskController.FatalError) { @@ -186,7 +186,7 @@ namespace Contralto.CPU case DiskF2.STROBON: // "NEXT <- NEXT OR (IF seek strobe still on THEN 1 ELSE 0)" - _nextModifier |= GetInitModifier(instruction); + _nextModifier |= GetInitModifier(); if ((_diskController.KSTAT & DiskController.STROBE) != 0) { _nextModifier |= 0x1; @@ -195,7 +195,7 @@ namespace Contralto.CPU case DiskF2.SWRNRDY: // "NEXT <- NEXT OR (IF disk not ready to accept command THEN 1 ELSE 0) - _nextModifier |= GetInitModifier(instruction); + _nextModifier |= GetInitModifier(); if (!_diskController.Ready) { _nextModifier |= 0x1; @@ -224,7 +224,7 @@ namespace Contralto.CPU /// The status of the INIT flag /// /// - private ushort GetInitModifier(MicroInstruction instruction) + private ushort GetInitModifier() { // // "NEXT<-NEXT OR (if WDTASKACT AND WDINIT) then 37B else 0." diff --git a/Contralto/CPU/Tasks/EmulatorTask.cs b/Contralto/CPU/Tasks/EmulatorTask.cs index 67866fc..30ecb2a 100644 --- a/Contralto/CPU/Tasks/EmulatorTask.cs +++ b/Contralto/CPU/Tasks/EmulatorTask.cs @@ -261,7 +261,7 @@ namespace Contralto.CPU // Conditions ORed onto NEXT Comment // // if IR[0] = 1 3-IR[8-9] complement of SH field of IR - // if IR[1-2] = 3 IR[5] the Indirect bit of R + // if IR[1-2] != 3 IR[5] the Indirect bit of R // if IR[3-7] = 0 2 CYCLE // if IR[3-7] = 1 5 RAMTRAP // if IR[3-7] = 2 3 NOPAR -- parameterless opcode group @@ -273,21 +273,18 @@ namespace Contralto.CPU // if IR[3-7] = 37B 17B ROMTRAP -- used by Swat, the debugger // else 16B ROMTRAP - // - // NOTE: the above table from the Hardware Manual is incorrect - // (or at least incomplete / out of date / misleading). - // There is considerably more that goes into determining the dispatch, which is controlled by a 256x8 - // PROM. We just use the PROM rather than implementing the above logic (because it works.) - // + // + // NOTE: The above table is accurate and functions correctly; using the PROM is faster. + // if ((_cpu._ir & 0x8000) != 0) { // 3-IR[8-9] (shift field of arithmetic instruction) _nextModifier = (ushort)(3 - ((_cpu._ir & 0xc0) >> 6)); } else - { + { // Use the PROM. - _nextModifier = ControlROM.ACSourceROM[((_cpu._ir & 0x7f00) >> 8)]; + _nextModifier = ControlROM.ACSourceROM[((_cpu._ir & 0x7f00) >> 8)]; } break; @@ -309,10 +306,15 @@ namespace Contralto.CPU // DNS<- does the following: // - modifies the normal shift operations to perform Nova-style shifts (done here) // - addresses R from 3-IR[3-4] (destination AC) (see Early LoadDNS handler) - // - stores into R unless IR[12] is set (done here) + // - stores into R unless IR[12] is set (done here) + // [NOTE: This overrides a LoadR BS field if present -- that is, if IR[12] is set and + // BS=LoadR, no load into R will take place. Note also that the standard + // microcode apparently always specifies a LoadR BS for LoadDNS microinstructions. Need to + // look at the schematics more closely to see if this is required or just a convention + // of the PARC microassembler.] // - calculates Nova-style CARRY bit (done here) // - sets the SKIP and CARRY flip-flops appropriately (see Late LoadDNS handler) - int carry = 0; + int carry = 0; // Also indicates modifying CARRY _loadR = (_cpu._ir & 0x0008) == 0; @@ -321,40 +323,40 @@ namespace Contralto.CPU // We need to set the CARRY bit that will be passed through the shifter appropriately. // Select carry input value based on carry control - switch(_cpu._ir & 0x30) + switch((_cpu._ir & 0x30) >> 4) { - case 0x00: + case 0x0: // Nothing; CARRY unaffected. carry = _carry; break; - case 0x10: + case 0x1: carry = 0; // Z break; - case 0x20: + case 0x2: carry = 1; // O break; - case 0x30: + case 0x3: carry = (~_carry) & 0x1; // C break; } // Now modify the result based on the current ALU result - switch (_cpu._ir & 0x700) + switch ((_cpu._ir & 0x700) >> 8) { - case 0x000: - case 0x200: - case 0x700: + case 0x0: + case 0x2: + case 0x7: // COM, MOV, AND - Carry unaffected break; - case 0x100: - case 0x300: - case 0x400: - case 0x500: - case 0x600: + case 0x1: + case 0x3: + case 0x4: + case 0x5: + case 0x6: // NEG, INC, ADC, SUB, ADD - invert the carry bit if (_cpu._aluC0 != 0) { diff --git a/Contralto/CPU/Tasks/Task.cs b/Contralto/CPU/Tasks/Task.cs index 0b520c5..1be4517 100644 --- a/Contralto/CPU/Tasks/Task.cs +++ b/Contralto/CPU/Tasks/Task.cs @@ -138,8 +138,7 @@ namespace Contralto.CPU protected virtual InstructionCompletion ExecuteInstruction(MicroInstruction instruction) { InstructionCompletion completion = InstructionCompletion.Normal; - bool swMode = false; - bool block = false; + bool swMode = false; ushort aluData; ushort nextModifier; _loadR = false; @@ -243,7 +242,7 @@ namespace Contralto.CPU // more than one source is gated to it. Up to 32 such mask contans can be provided for each of the four bus sources // > 4." // This is precached by the MicroInstruction object. - if (instruction.ConstantAccessOrBS4) + if (instruction.BS4) { _busData &= instruction.ConstantValue; } @@ -319,7 +318,7 @@ namespace Contralto.CPU // // If the first uOp executed after a task switch contains a TASK F1, it does not take effect. // This is observed on the real hardware, and does not appear to be documented. - // It also doensn't appear to affect the execution of the standard Alto uCode in any significant + // It also doesn't appear to affect the execution of the standard Alto uCode in any significant // way, but is included here for correctness. // if (!_firstInstructionAfterSwitch) @@ -333,10 +332,7 @@ namespace Contralto.CPU // Technically this is to be invoked by the hardware device associated with a task. // That logic would be circuituous and unless there's a good reason not to that is discovered // later, I'm just going to directly block the current task here. - _cpu.BlockTask(this._taskType); - - // Let task-specific behavior take place at the end of this cycle. - block = true; + _cpu.BlockTask(this._taskType); break; case SpecialFunction1.LLSH1: @@ -520,14 +516,14 @@ namespace Contralto.CPU // if (swMode) { - Log.Write(LogType.Verbose, LogComponent.Microcode, "SWMODE: uPC {0}, next uPC {1} (NEXT is {2})", Conversion.ToOctal(_mpc), Conversion.ToOctal(instruction.NEXT | nextModifier), Conversion.ToOctal(instruction.NEXT)); + //Log.Write(LogType.Verbose, LogComponent.Microcode, "SWMODE: uPC {0}, next uPC {1} (NEXT is {2})", Conversion.ToOctal(_mpc), Conversion.ToOctal(instruction.NEXT | nextModifier), Conversion.ToOctal(instruction.NEXT)); UCodeMemory.SwitchMode((ushort)(instruction.NEXT | nextModifier), _taskType); } // // Do task-specific BLOCK behavior if the last instruction had a BLOCK F1. // - if (block) + if (instruction.F1 == SpecialFunction1.Block) { ExecuteBlock(); } diff --git a/Contralto/CPU/UCodeDisassembler.cs b/Contralto/CPU/UCodeDisassembler.cs index 7db55f9..73855fb 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; } } @@ -161,7 +161,15 @@ namespace Contralto.CPU break; case SpecialFunction1.LoadMAR: - f1 = "MAR<- "; + + if (instruction.F2 == SpecialFunction2.StoreMD) + { + f1 = "XMAR← "; + } + else + { + f1 = "MAR← "; + } break; case SpecialFunction1.Task: @@ -173,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: @@ -221,7 +229,10 @@ namespace Contralto.CPU break; case SpecialFunction2.StoreMD: - f2 = "MD<- "; + if (instruction.F1 != SpecialFunction1.LoadMAR) + { + f2 = "MD← "; + } break; case SpecialFunction2.Constant: @@ -256,7 +267,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 @@ -264,18 +275,18 @@ namespace Contralto.CPU { if (string.IsNullOrEmpty(load)) { - load = String.Format("L<- {0}", operation); + load = String.Format("L← {0}", operation); } else { - load = String.Format("L<- {0}", load); + load = String.Format("L← {0}", 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), load != String.Empty ? load : operation); } @@ -285,12 +296,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); } @@ -392,10 +403,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 "; @@ -425,13 +436,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 "; diff --git a/Contralto/Contralto.csproj b/Contralto/Contralto.csproj index 845ffea..6ab2499 100644 --- a/Contralto/Contralto.csproj +++ b/Contralto/Contralto.csproj @@ -495,6 +495,7 @@ false +