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
+