mirror of
https://github.com/livingcomputermuseum/ContrAlto.git
synced 2026-01-11 23:52:43 +00:00
445 lines
14 KiB
C#
445 lines
14 KiB
C#
/*
|
|
This file is part of ContrAlto.
|
|
|
|
ContrAlto is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
ContrAlto is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with ContrAlto. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
using System;
|
|
using System.Text;
|
|
|
|
namespace Contralto.CPU
|
|
{
|
|
/// <summary>
|
|
/// Provides a facility for doing a (crude) disassembly of microcode.
|
|
/// </summary>
|
|
public static class UCodeDisassembler
|
|
{
|
|
|
|
/// <summary>
|
|
/// Disassembles the specified microinstruction for the specified Task type.
|
|
/// </summary>
|
|
/// <param name="instruction">The microinstruction to disassemble</param>
|
|
/// <param name="task">The task to interpret the microinstruction for</param>
|
|
public static string DisassembleInstruction(MicroInstruction instruction, TaskType task)
|
|
{
|
|
StringBuilder disassembly = new StringBuilder();
|
|
|
|
uint rSelect = instruction.RSELECT;
|
|
bool loadR = false;
|
|
bool loadS = false;
|
|
string source = string.Empty;
|
|
string operation = string.Empty;
|
|
string f1 = string.Empty;
|
|
string f2 = string.Empty;
|
|
string load = string.Empty;
|
|
|
|
// Select BUS data.
|
|
if (instruction.F1 != SpecialFunction1.Constant &&
|
|
instruction.F2 != SpecialFunction2.Constant)
|
|
{
|
|
// Normal BUS data (not constant ROM access).
|
|
switch (instruction.BS)
|
|
{
|
|
case BusSource.ReadR:
|
|
source = String.Format("$R{0} ", Conversion.ToOctal((int)rSelect));
|
|
break;
|
|
|
|
case BusSource.LoadR:
|
|
source = "L ";
|
|
loadR = true;
|
|
break;
|
|
|
|
case BusSource.None:
|
|
// nothing
|
|
break;
|
|
|
|
case BusSource.TaskSpecific1:
|
|
case BusSource.TaskSpecific2:
|
|
source = DisassembleBusSource(instruction, task, out loadS); // task specific -- call into specific implementation
|
|
break;
|
|
|
|
case BusSource.ReadMD:
|
|
source = "MD ";
|
|
break;
|
|
|
|
case BusSource.ReadMouse:
|
|
source = "MOUSE ";
|
|
break;
|
|
|
|
case BusSource.ReadDisp:
|
|
source = "DISP ";
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((int)instruction.BS > 4 ||
|
|
instruction.F1 == SpecialFunction1.Constant ||
|
|
instruction.F2 == SpecialFunction2.Constant)
|
|
{
|
|
source += String.Format("C({0})",
|
|
Conversion.ToOctal(ControlROM.ConstantROM[(instruction.RSELECT << 3) | ((uint)instruction.BS)]));
|
|
}
|
|
|
|
switch (instruction.ALUF)
|
|
{
|
|
case AluFunction.Bus:
|
|
operation = source;
|
|
break;
|
|
|
|
case AluFunction.T:
|
|
operation = "T ";
|
|
break;
|
|
|
|
case AluFunction.BusOrT:
|
|
operation = String.Format("{0} or T ", source);
|
|
break;
|
|
|
|
case AluFunction.BusAndT:
|
|
operation = String.Format("{0} and T ", source);
|
|
break;
|
|
|
|
case AluFunction.BusXorT:
|
|
operation = String.Format("{0} xor T ", source);
|
|
break;
|
|
|
|
case AluFunction.BusPlus1:
|
|
operation = String.Format("{0} + 1 ", source);
|
|
break;
|
|
|
|
case AluFunction.BusMinus1:
|
|
operation = String.Format("{0} - 1 ", source);
|
|
break;
|
|
|
|
case AluFunction.BusPlusT:
|
|
operation = String.Format("{0} + T ", source);
|
|
break;
|
|
|
|
case AluFunction.BusMinusT:
|
|
operation = String.Format("{0} - T ", source);
|
|
break;
|
|
|
|
case AluFunction.BusMinusTMinus1:
|
|
operation = String.Format("{0} - T - 1 ", source);
|
|
break;
|
|
|
|
case AluFunction.BusPlusTPlus1:
|
|
operation = String.Format("{0} + T + 1 ", source);
|
|
break;
|
|
|
|
case AluFunction.BusPlusSkip:
|
|
operation = String.Format("{0} + SKIP ", source);
|
|
break;
|
|
|
|
case AluFunction.AluBusAndT:
|
|
operation = String.Format("{0}.T ", source);
|
|
break;
|
|
|
|
case AluFunction.BusAndNotT:
|
|
operation = String.Format("{0} and not T ", source);
|
|
break;
|
|
|
|
default:
|
|
operation = "Undefined ALU operation ";
|
|
break;
|
|
}
|
|
|
|
switch (instruction.F1)
|
|
{
|
|
case SpecialFunction1.None:
|
|
f1 = string.Empty;
|
|
break;
|
|
|
|
case SpecialFunction1.LoadMAR:
|
|
f1 = "MAR<- ";
|
|
break;
|
|
|
|
case SpecialFunction1.Task:
|
|
f1 = "TASK ";
|
|
break;
|
|
|
|
case SpecialFunction1.Block:
|
|
f1 = "BLOCK ";
|
|
break;
|
|
|
|
case SpecialFunction1.LLSH1:
|
|
f1 = "<-L LSH 1 ";
|
|
break;
|
|
|
|
case SpecialFunction1.LRSH1:
|
|
f1 = "<-L RSH 1 ";
|
|
break;
|
|
|
|
case SpecialFunction1.LLCY8:
|
|
f1 = "<-L LCY 8 ";
|
|
break;
|
|
|
|
case SpecialFunction1.Constant:
|
|
// Ignored here; handled by Constant ROM access logic above.
|
|
break;
|
|
|
|
default:
|
|
// Let the specific task implementation take a crack at this.
|
|
f1 = DisassembleSpecialFunction1(instruction, task);
|
|
break;
|
|
}
|
|
|
|
switch (instruction.F2)
|
|
{
|
|
case SpecialFunction2.None:
|
|
f2 = string.Empty;
|
|
break;
|
|
|
|
case SpecialFunction2.BusEq0:
|
|
f2 = "BUS=0 ";
|
|
break;
|
|
|
|
case SpecialFunction2.ShLt0:
|
|
f2 = "SH<0 ";
|
|
break;
|
|
|
|
case SpecialFunction2.ShEq0:
|
|
f2 = "SH=0 ";
|
|
break;
|
|
|
|
case SpecialFunction2.Bus:
|
|
f2 = "BUS ";
|
|
break;
|
|
|
|
case SpecialFunction2.ALUCY:
|
|
f2 = "ALUCY ";
|
|
break;
|
|
|
|
case SpecialFunction2.StoreMD:
|
|
f2 = "MD<- ";
|
|
break;
|
|
|
|
case SpecialFunction2.Constant:
|
|
// Ignored here; handled by Constant ROM access logic above.
|
|
break;
|
|
|
|
default:
|
|
// Let the specific task implementation take a crack at this.
|
|
f2 = DisassembleSpecialFunction2(instruction, task);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Write back to registers:
|
|
//
|
|
|
|
// Load T
|
|
if (instruction.LoadT)
|
|
{
|
|
// Does this operation change the source for T?
|
|
bool loadTFromALU = false;
|
|
switch (instruction.ALUF)
|
|
{
|
|
case AluFunction.Bus:
|
|
case AluFunction.BusOrT:
|
|
case AluFunction.BusPlus1:
|
|
case AluFunction.BusMinus1:
|
|
case AluFunction.BusPlusTPlus1:
|
|
case AluFunction.BusPlusSkip:
|
|
case AluFunction.AluBusAndT:
|
|
loadTFromALU = true;
|
|
break;
|
|
}
|
|
|
|
load = String.Format("T<- {0}", loadTFromALU ? operation : source);
|
|
}
|
|
|
|
// Load L (and M) from ALU
|
|
if (instruction.LoadL)
|
|
{
|
|
if (string.IsNullOrEmpty(load))
|
|
{
|
|
load = String.Format("L<- {0}", operation);
|
|
}
|
|
else
|
|
{
|
|
load = String.Format("L<- {0}", load);
|
|
}
|
|
}
|
|
|
|
// Do writeback to selected R register from shifter output
|
|
if (loadR)
|
|
{
|
|
load = String.Format("$R{0}<- {1}",
|
|
Conversion.ToOctal((int)rSelect),
|
|
load != String.Empty ? load : operation);
|
|
}
|
|
|
|
// Do writeback to selected S register from M
|
|
if (loadS)
|
|
{
|
|
if (string.IsNullOrEmpty(load))
|
|
{
|
|
load = String.Format("$S{0}<- M",
|
|
Conversion.ToOctal((int)rSelect));
|
|
}
|
|
else
|
|
{
|
|
load = String.Format("$S{0}<- M, {1}",
|
|
Conversion.ToOctal((int)rSelect),
|
|
load);
|
|
}
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(load))
|
|
{
|
|
disassembly.AppendFormat("{0}{1}{2} :{3}",
|
|
f1,
|
|
f2,
|
|
load,
|
|
Conversion.ToOctal(instruction.NEXT));
|
|
}
|
|
else
|
|
{
|
|
disassembly.AppendFormat("{0}{1}{2} :{3}",
|
|
f1,
|
|
f2,
|
|
operation,
|
|
Conversion.ToOctal(instruction.NEXT));
|
|
}
|
|
|
|
|
|
return disassembly.ToString();
|
|
}
|
|
|
|
private static string DisassembleBusSource(MicroInstruction instruction, TaskType task, out bool loadS)
|
|
{
|
|
switch(task)
|
|
{
|
|
case TaskType.Emulator:
|
|
return DisassembleEmulatorBusSource(instruction, out loadS);
|
|
|
|
default:
|
|
loadS = false;
|
|
return String.Format("BS {0}", Conversion.ToOctal((int)instruction.BS));
|
|
}
|
|
}
|
|
|
|
private static string DisassembleSpecialFunction1(MicroInstruction instruction, TaskType task)
|
|
{
|
|
switch (task)
|
|
{
|
|
case TaskType.Emulator:
|
|
return DisassembleEmulatorSpecialFunction1(instruction);
|
|
|
|
default:
|
|
return String.Format("F1 {0}", Conversion.ToOctal((int)instruction.F1));
|
|
}
|
|
}
|
|
|
|
private static string DisassembleSpecialFunction2(MicroInstruction instruction, TaskType task)
|
|
{
|
|
switch (task)
|
|
{
|
|
case TaskType.Emulator:
|
|
return DisassembleEmulatorSpecialFunction2(instruction);
|
|
|
|
default:
|
|
return String.Format("F2 {0}", Conversion.ToOctal((int)instruction.F2));
|
|
}
|
|
}
|
|
|
|
private static string DisassembleEmulatorBusSource(MicroInstruction instruction, out bool loadS)
|
|
{
|
|
EmulatorBusSource bs = (EmulatorBusSource)instruction.BS;
|
|
|
|
switch(bs)
|
|
{
|
|
case EmulatorBusSource.ReadSLocation:
|
|
loadS = false;
|
|
return String.Format("$S{0}", Conversion.ToOctal((int)instruction.RSELECT));
|
|
|
|
case EmulatorBusSource.LoadSLocation:
|
|
loadS = true;
|
|
return String.Empty;
|
|
|
|
default:
|
|
loadS = false;
|
|
throw new InvalidOperationException(String.Format("Unhandled Emulator BS {0}", bs));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private static string DisassembleEmulatorSpecialFunction1(MicroInstruction instruction)
|
|
{
|
|
EmulatorF1 ef1 = (EmulatorF1)instruction.F1;
|
|
|
|
switch(ef1)
|
|
{
|
|
case EmulatorF1.SWMODE:
|
|
return "SWMODE ";
|
|
|
|
case EmulatorF1.WRTRAM:
|
|
return "WRTRAM ";
|
|
|
|
case EmulatorF1.RDRAM:
|
|
return "RDRAM ";
|
|
|
|
case EmulatorF1.LoadRMR:
|
|
return "RMR<- ";
|
|
|
|
case EmulatorF1.LoadESRB:
|
|
return "ESRB<- ";
|
|
|
|
case EmulatorF1.RSNF:
|
|
return "RSNF ";
|
|
|
|
case EmulatorF1.STARTF:
|
|
return "STARTF ";
|
|
|
|
default:
|
|
return String.Format("F1 {0}", Conversion.ToOctal((int)ef1));
|
|
}
|
|
|
|
}
|
|
|
|
private static string DisassembleEmulatorSpecialFunction2(MicroInstruction instruction)
|
|
{
|
|
EmulatorF2 ef2 = (EmulatorF2)instruction.F2;
|
|
|
|
switch (ef2)
|
|
{
|
|
case EmulatorF2.ACDEST:
|
|
return "ACDEST ";
|
|
|
|
case EmulatorF2.ACSOURCE:
|
|
return "ACSOURCE ";
|
|
|
|
case EmulatorF2.MAGIC:
|
|
return "MAGIC ";
|
|
|
|
case EmulatorF2.LoadDNS:
|
|
return "DNS<- ";
|
|
|
|
case EmulatorF2.BUSODD:
|
|
return "BUSODD ";
|
|
|
|
case EmulatorF2.LoadIR:
|
|
return "IR<- ";
|
|
|
|
case EmulatorF2.IDISP:
|
|
return "IDISP ";
|
|
|
|
default:
|
|
return String.Format("F2 {0}", Conversion.ToOctal((int)ef2));
|
|
}
|
|
}
|
|
}
|
|
}
|