diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..1ff0c42
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln merge=binary
+#*.csproj merge=binary
+#*.vbproj merge=binary
+#*.vcxproj merge=binary
+#*.vcproj merge=binary
+#*.dbproj merge=binary
+#*.fsproj merge=binary
+#*.lsproj merge=binary
+#*.wixproj merge=binary
+#*.modelproj merge=binary
+#*.sqlproj merge=binary
+#*.wwaproj merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg binary
+#*.png binary
+#*.gif binary
+
+###############################################################################
+# diff behavior for common document formats
+#
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the
+# entries below.
+###############################################################################
+#*.doc diff=astextplain
+#*.DOC diff=astextplain
+#*.docx diff=astextplain
+#*.DOCX diff=astextplain
+#*.dot diff=astextplain
+#*.DOT diff=astextplain
+#*.pdf diff=astextplain
+#*.PDF diff=astextplain
+#*.rtf diff=astextplain
+#*.RTF diff=astextplain
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3c4efe2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,261 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+#*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush
+.cr/
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
\ No newline at end of file
diff --git a/D.sln b/D.sln
new file mode 100644
index 0000000..f98b65a
--- /dev/null
+++ b/D.sln
@@ -0,0 +1,73 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26403.7
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Darkstar", "D\Darkstar.csproj", "{0590465E-1D91-4591-946E-EE3F7D82834B}"
+EndProject
+Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "DarkstarSetup", "DSetup\DarkstarSetup.wixproj", "{BCB1273C-6A17-4AFE-88AD-470A3594A009}"
+EndProject
+Global
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|ia64 = Debug|ia64
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|ia64 = Release|ia64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Debug|ia64.ActiveCfg = Debug|Any CPU
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Debug|ia64.Build.0 = Debug|Any CPU
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Debug|x64.ActiveCfg = Debug|x64
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Debug|x64.Build.0 = Debug|x64
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Debug|x86.Build.0 = Debug|Any CPU
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Release|ia64.ActiveCfg = Release|Any CPU
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Release|ia64.Build.0 = Release|Any CPU
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Release|x64.ActiveCfg = Release|x64
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Release|x64.Build.0 = Release|x64
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Release|x86.ActiveCfg = Release|Any CPU
+ {0590465E-1D91-4591-946E-EE3F7D82834B}.Release|x86.Build.0 = Release|Any CPU
+ {BCB1273C-6A17-4AFE-88AD-470A3594A009}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {BCB1273C-6A17-4AFE-88AD-470A3594A009}.Debug|ia64.ActiveCfg = Debug|x86
+ {BCB1273C-6A17-4AFE-88AD-470A3594A009}.Debug|x64.ActiveCfg = Debug|x86
+ {BCB1273C-6A17-4AFE-88AD-470A3594A009}.Debug|x86.ActiveCfg = Debug|x86
+ {BCB1273C-6A17-4AFE-88AD-470A3594A009}.Debug|x86.Build.0 = Debug|x86
+ {BCB1273C-6A17-4AFE-88AD-470A3594A009}.Release|Any CPU.ActiveCfg = Release|x86
+ {BCB1273C-6A17-4AFE-88AD-470A3594A009}.Release|ia64.ActiveCfg = Release|x86
+ {BCB1273C-6A17-4AFE-88AD-470A3594A009}.Release|x64.ActiveCfg = Release|x86
+ {BCB1273C-6A17-4AFE-88AD-470A3594A009}.Release|x86.ActiveCfg = Release|x86
+ {BCB1273C-6A17-4AFE-88AD-470A3594A009}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {DA616BB8-1CC8-43E2-A841-6DB3E9DA4AA8}
+ EndGlobalSection
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
+EndGlobal
diff --git a/D/App.config b/D/App.config
new file mode 100644
index 0000000..2b933e2
--- /dev/null
+++ b/D/App.config
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+
+
+ 1
+
+
+ 2852201285
+
+
+
+
+
+ 1024
+
+
+ True
+
+
+ 1979-12-10
+
+
+ 0
+
+
+ 1955-11-05
+
+
+
+
\ No newline at end of file
diff --git a/D/CP/AM2901.cs b/D/CP/AM2901.cs
new file mode 100644
index 0000000..922129b
--- /dev/null
+++ b/D/CP/AM2901.cs
@@ -0,0 +1,807 @@
+/*
+ BSD 2-Clause License
+
+ Copyright Vulcan Inc. 2017-2018 and Living Computer Museum + Labs 2018
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+using System;
+
+namespace D.CP
+{
+ ///
+ /// This implements an abstraction of the AMD 2901 as seen by the Central Processor --
+ /// that is: as a 16-bit ALU + register file, rather than four 4-bit ALUs hooked together.
+ /// This only implements the signals and operations that the CP actually cares about.
+ ///
+ public class AM2901
+ {
+ static AM2901()
+ {
+ BuildTables();
+ }
+
+ public AM2901()
+ {
+
+ }
+
+ public ushort[] R
+ {
+ get { return _r; }
+ }
+
+ public ushort Q
+ {
+ get { return _q; }
+ }
+
+ ///
+ /// Executes the ALU operation specified by the given microinstruction.
+ ///
+ /// The microinstruction
+ /// The ALU D input
+ /// The ALU Carry in
+ /// Whether this operation is taking place during an MAR<- operation,
+ /// in which case the top half of the ALU needs to be treated specially.
+ public ushort Execute(Microinstruction i, ushort d, bool carryIn, bool loadMAR)
+ {
+ //
+ // Save R[a] for the A-bypass case.
+ // (If the ALU op ends up modifying R[a] in A-Bypass mode (because a == b)
+ // it will happen much later than A-bypass and we want
+ // Y to get the original value of R[a], not the later value.)
+ //
+
+ // Select source data
+ int r, s;
+ switch(i.aS)
+ {
+ case AluSourcePair.AQ:
+ r = _r[i.rA];
+ s = _q;
+ break;
+
+ case AluSourcePair.AB:
+ r = _r[i.rA];
+ s = _r[i.rB];
+ break;
+
+ case AluSourcePair.ZQ:
+ r = 0;
+ s = _q;
+ break;
+
+ case AluSourcePair.ZB:
+ r = 0;
+ s = _r[i.rB];
+ break;
+
+ case AluSourcePair.ZA:
+ r = 0;
+ s = _r[i.rA];
+ break;
+
+ case AluSourcePair.DA:
+ r = d;
+ s = _r[i.rA];
+ break;
+
+ case AluSourcePair.DQ:
+ r = d;
+ s = _q;
+ break;
+
+ case AluSourcePair.D0:
+ r = d;
+ s = 0;
+ break;
+
+ default:
+ throw new InvalidOperationException(
+ String.Format("Unhandled source pair {0}", i.aS));
+ }
+
+ //
+ // Do ALU op
+ //
+ int f;
+ int cIn = (carryIn ? 1 : 0);
+ switch (i.aF)
+ {
+ case AluFunction.RplusS:
+ {
+ f = r + s + cIn;
+ CarryOut = (f > 0xffff);
+ NibCarry = (r & 0xf) + (s & 0xf) + cIn > 0xf;
+ PgCarry = (r & 0xff) + (s & 0xff) + cIn > 0xff;
+ int cn = (r & 0xfff) + (s & 0xfff) + cIn > 0xfff ? 1 : 0;
+ Overflow = _overflowTable[r >> 12, s >> 12, cn];
+ }
+ break;
+
+ case AluFunction.SminusR:
+ {
+ f = s + (~r & 0xffff) + cIn;
+ CarryOut = (f > 0xffff);
+ NibCarry = ((~r & 0xf) + (s & 0xf) + cIn > 0xf);
+ PgCarry = ((~r & 0xff) + (s & 0xff) + cIn > 0xff);
+ int cn = (~r & 0xfff) + (s & 0xfff) + cIn > 0xfff ? 1 : 0;
+ Overflow = _overflowTable[(~r & 0xffff) >> 12, s >> 12, cn];
+ }
+ break;
+
+ case AluFunction.RminusS:
+ {
+ f = r + (~s & 0xffff) + cIn;
+ CarryOut = (f > 0xffff);
+ NibCarry = ((r & 0xf) + (~s & 0xf) + cIn > 0xf);
+ PgCarry = ((r & 0xff) + (~s & 0xff) + cIn > 0xff);
+ int cn = (r & 0xfff) + (~s & 0xfff) + cIn > 0xfff ? 1 : 0;
+ Overflow = _overflowTable[r >> 12, (~s & 0xffff) >> 12, cn];
+ }
+ break;
+
+ case AluFunction.RorS:
+ f = r | s;
+ // A few microinstructions do an MAR<- with RorS and expect PgCarry to be set appropriately.
+ NibCarry = _carryTableOr[r & 0xf, s & 0xf, cIn];
+ PgCarry = _carryTableOr[(r >> 4) & 0xf, (s >> 4) & 0xf, NibCarry ? 1 : 0];
+ CarryOut = false;
+ Overflow = false;
+ break;
+
+ case AluFunction.RandS:
+ f = r & s;
+ NibCarry = false;
+ PgCarry = false;
+ CarryOut = false;
+ Overflow = false;
+ break;
+
+ case AluFunction.notRandS:
+ f = (~r) & s;
+ NibCarry = false;
+ PgCarry = false;
+ CarryOut = false;
+ Overflow = false;
+ break;
+
+ case AluFunction.RxorS:
+ f = r ^ s;
+ NibCarry = false;
+ PgCarry = false;
+ CarryOut = false;
+ Overflow = false;
+ break;
+
+ case AluFunction.notRxorS:
+ f = (~r) ^ s;
+ NibCarry = false;
+ PgCarry = false;
+ CarryOut = false;
+ Overflow = false;
+ break;
+
+ default:
+ throw new InvalidOperationException(
+ String.Format("Unhandled function {0}", i.aF));
+ }
+
+ // Clip F to 16 bits
+ f = f & 0xffff;
+
+ if (loadMAR)
+ {
+ //
+ // If the ALU is being run during a MAR<- operation, the top 8 bits of the ALU are
+ // computed using an operator specified by aF | 3, with the source set to 0,B.
+ // The CarryOut and Overflow flags are clear (since they are not affected by the
+ // OR/notXOR operation), and the carry from the least-significant byte of the ALU does not
+ // carry over to the most-significant byte.
+ //
+ // See page 25 of the microcode ref for details.
+ //
+ // We implement this here by overwriting the upper byte of F with the upper bits of rB
+ // (or its complement). Interlisp microcode expects Overflow and Carry to be set appropriately.
+ //
+ switch ((AluFunction)((int)i.aF | 0x3))
+ {
+ case AluFunction.RorS:
+ {
+ f = (f & 0xff) | (_r[i.rB] & 0xff00);
+ bool midCarry = _carryTableOr[(r >> 8) & 0xf, (s >> 8) & 0xf, PgCarry ? 1 : 0];
+ Overflow = CarryOut = _carryTableOr[(r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ }
+ break;
+
+ case AluFunction.notRxorS:
+ {
+ f = (f & 0xff) | ((~_r[i.rB]) & 0xff00);
+ bool midCarry = _carryTableNotXor[(r >> 8) & 0xf, (s >> 8) & 0xf, PgCarry ? 1 : 0];
+ CarryOut = _carryTableNotXor[(r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ Overflow = _overflowNotXor[(r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ }
+ break;
+ }
+ }
+
+ Zero = (f == 0);
+ Neg = ((f & 0x8000) != 0);
+
+ //
+ // Write outputs, do shifts and cycles as appropriate before writing back.
+ // (Shifts and cycles do not affect the Y output, only the register being written back to.)
+ //
+ switch (i.AluDestination)
+ {
+ case 0:
+ _q = (ushort)f;
+ Y = (ushort)f;
+ break;
+
+ case 1:
+ Y = (ushort)f;
+ break;
+
+ case 2:
+ Y = _r[i.rA];
+ _r[i.rB] = (ushort)f;
+ break;
+
+ case 3:
+ _r[i.rB] = (ushort)f;
+ Y = (ushort)f;
+ break;
+
+ case 4:
+ Y = (ushort)f;
+
+ if (i.Cycle)
+ {
+ // double-word right shift
+ // MSB of Q gets inverted LSB of F.
+ _q = (ushort)((_q >> 1) | ((~f & 0x1) << 15));
+
+ // MSB of F gets Carry in.
+ f = (ushort)((f >> 1) | (carryIn ? 0x8000 : 0x0));
+ }
+ else
+ {
+ // double-word arithmetic right shift.
+ // MSB of Q gets inverted LSB of F.
+ _q = (ushort)((_q >> 1) | ((~f & 0x1) << 15));
+
+ // MSB of F gets Carry out.
+ f = (ushort)((f >> 1) | (CarryOut ? 0x8000 : 0x0));
+ }
+ _r[i.rB] = (ushort)f;
+ break;
+
+ case 5:
+ Y = (ushort)f;
+ if (i.Cycle)
+ {
+ // F: single-word right rotate:
+ f = (ushort)((f >> 1) | ((f & 0x1) << 15));
+ }
+ else
+ {
+ // F: single-word right shift w/carryIn to MSB:
+ f = (ushort)((f >> 1) | (carryIn ? 0x8000 : 0x0));
+ }
+ _r[i.rB] = (ushort)f;
+ break;
+
+ case 6:
+ Y = (ushort)f;
+
+ // double-word left shift (apparently identical for cycle and shift)
+ // LSB of F gets MSB of Q, not inverted.
+ f = (ushort)((f << 1) | ((_q & 0x8000) >> 15));
+
+ // LSB of Q gets Cin, inverted
+ _q = (ushort)((_q << 1) | (1 - cIn));
+
+ _r[i.rB] = (ushort)f;
+ break;
+
+ case 7:
+ Y = (ushort)f;
+ if (i.Cycle)
+ {
+ // F: single-word left rotate:
+ f = (ushort)((f << 1) | ((f & 0x8000) >> 15));
+ }
+ else
+ {
+ // F: single-word left shift w/carryIn to LSB:
+ f = (ushort)((f << 1) | cIn);
+ }
+ _r[i.rB] = (ushort)f;
+ break;
+
+ default:
+ throw new InvalidOperationException(
+ String.Format("Unhandled destination {0}", i.aF));
+ }
+
+ return Y;
+ }
+
+ ///
+ /// Executes the ALU operation specified by the given microinstruction with all condition flags
+ /// calculated, even for logical operations. This is significantly slower than Execute().
+ ///
+ /// The microinstruction
+ /// The ALU D input
+ /// The ALU Carry in
+ /// Whether this operation is taking place during an MAR<- operation,
+ /// in which case the top half of the ALU needs to be treated specially.
+ public ushort ExecuteAccurate(Microinstruction i, ushort d, bool carryIn, bool loadMAR)
+ {
+ // Select source data
+ int r, s;
+ switch (i.aS)
+ {
+ case AluSourcePair.AQ:
+ r = _r[i.rA];
+ s = _q;
+ break;
+
+ case AluSourcePair.AB:
+ r = _r[i.rA];
+ s = _r[i.rB];
+ break;
+
+ case AluSourcePair.ZQ:
+ r = 0;
+ s = _q;
+ break;
+
+ case AluSourcePair.ZB:
+ r = 0;
+ s = _r[i.rB];
+ break;
+
+ case AluSourcePair.ZA:
+ r = 0;
+ s = _r[i.rA];
+ break;
+
+ case AluSourcePair.DA:
+ r = d;
+ s = _r[i.rA];
+ break;
+
+ case AluSourcePair.DQ:
+ r = d;
+ s = _q;
+ break;
+
+ case AluSourcePair.D0:
+ r = d;
+ s = 0;
+ break;
+
+ default:
+ throw new InvalidOperationException(
+ String.Format("Unhandled source pair {0}", i.aS));
+ }
+
+ //
+ // Do ALU op
+ //
+ int f;
+ int cIn = (carryIn ? 1 : 0);
+ switch (i.aF)
+ {
+ case AluFunction.RplusS:
+ {
+ f = r + s + cIn;
+ NibCarry = _carryTableArithmetic[r & 0xf, s & 0xf, cIn];
+ PgCarry = _carryTableArithmetic[(r >> 4) & 0xf, (s >> 4) & 0xf, NibCarry ? 1 : 0];
+ bool midCarry = _carryTableArithmetic[(r >> 8) & 0xf, (s >> 8) & 0xf, PgCarry ? 1 : 0];
+ CarryOut = _carryTableArithmetic[(r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ Overflow = _overflowTable[r >> 12, s >> 12, midCarry ? 1 : 0];
+ }
+ break;
+
+ case AluFunction.SminusR:
+ {
+ f = s + (~r & 0xffff) + cIn;
+ NibCarry = _carryTableArithmetic[~r & 0xf, s & 0xf, cIn];
+ PgCarry = _carryTableArithmetic[(~r >> 4) & 0xf, (s >> 4) & 0xf, NibCarry ? 1 : 0];
+ bool midCarry = _carryTableArithmetic[(~r >> 8) & 0xf, (s >> 8) & 0xf, PgCarry ? 1 : 0];
+ CarryOut = _carryTableArithmetic[(~r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ Overflow = _overflowTable[(~r & 0xffff) >> 12, s >> 12, midCarry ? 1 : 0];
+ }
+ break;
+
+ case AluFunction.RminusS:
+ {
+ f = r + (~s & 0xffff) + cIn;
+ NibCarry = _carryTableArithmetic[r & 0xf, ~s & 0xf, cIn];
+ PgCarry = _carryTableArithmetic[(r >> 4) & 0xf, (~s >> 4) & 0xf, NibCarry ? 1 : 0];
+ bool midCarry = _carryTableArithmetic[(r >> 8) & 0xf, (~s >> 8) & 0xf, PgCarry ? 1 : 0];
+ CarryOut = _carryTableArithmetic[(r >> 12) & 0xf, (~s >> 12) & 0xf, midCarry ? 1 : 0];
+ Overflow = _overflowTable[r >> 12, (~s & 0xffff) >> 12, midCarry ? 1 : 0];
+ }
+ break;
+
+ case AluFunction.RorS:
+ {
+ f = r | s;
+
+ NibCarry = _carryTableOr[r & 0xf, s & 0xf, cIn];
+ PgCarry = _carryTableOr[(r >> 4) & 0xf, (s >> 4) & 0xf, NibCarry ? 1 : 0];
+ bool midCarry = _carryTableOr[(r >> 8) & 0xf, (s >> 8) & 0xf, PgCarry ? 1 : 0];
+ Overflow = CarryOut = _carryTableOr[(r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ }
+ break;
+
+ case AluFunction.RandS:
+ {
+ f = r & s;
+
+ NibCarry = _carryTableAnd[r & 0xf, s & 0xf, cIn];
+ PgCarry = _carryTableAnd[(r >> 4) & 0xf, (s >> 4) & 0xf, NibCarry ? 1 : 0];
+ bool midCarry = _carryTableAnd[(r >> 8) & 0xf, (s >> 8) & 0xf, PgCarry ? 1 : 0];
+ Overflow = CarryOut = _carryTableAnd[(r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ }
+ break;
+
+ case AluFunction.notRandS:
+ {
+ f = (~r) & s;
+
+ NibCarry = _carryTableAnd[~r & 0xf, s & 0xf, cIn];
+ PgCarry = _carryTableAnd[(~r >> 4) & 0xf, (s >> 4) & 0xf, NibCarry ? 1 : 0];
+ bool midCarry = _carryTableAnd[(~r >> 8) & 0xf, (s >> 8) & 0xf, PgCarry ? 1 : 0];
+ Overflow = CarryOut = _carryTableAnd[(~r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ }
+ break;
+
+ case AluFunction.RxorS:
+ {
+ f = r ^ s;
+ NibCarry = _carryTableNotXor[~r & 0xf, s & 0xf, cIn];
+ PgCarry = _carryTableNotXor[(~r >> 4) & 0xf, (s >> 4) & 0xf, NibCarry ? 1 : 0];
+ bool midCarry = _carryTableNotXor[(~r >> 8) & 0xf, (s >> 8) & 0xf, PgCarry ? 1 : 0];
+ CarryOut = _carryTableNotXor[(~r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ Overflow = _overflowNotXor[(~r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ }
+ break;
+
+ case AluFunction.notRxorS:
+ {
+ f = (~r) ^ s;
+ NibCarry = _carryTableNotXor[r & 0xf, s & 0xf, cIn];
+ PgCarry = _carryTableNotXor[(r >> 4) & 0xf, (s >> 4) & 0xf, NibCarry ? 1 : 0];
+ bool midCarry = _carryTableNotXor[(r >> 8) & 0xf, (s >> 8) & 0xf, PgCarry ? 1 : 0];
+ CarryOut = _carryTableNotXor[(r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ Overflow = _overflowNotXor[(r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ }
+ break;
+
+ default:
+ throw new InvalidOperationException(
+ String.Format("Unhandled function {0}", i.aF));
+ }
+
+ // Clip F to 16 bits
+ f = f & 0xffff;
+
+ if (loadMAR)
+ {
+ //
+ // If the ALU is being run during a MAR<- operation, the top 8 bits of the ALU are
+ // computed using an operator specified by aF | 3, with the source set to 0,B.
+ // The CarryOut and Overflow flags are clear (since they are not affected by the
+ // OR/notXOR operation), and the carry from the least-significant byte of the ALU does not
+ // carry over to the most-significant byte.
+ //
+ // See page 25 of the microcode ref for details.
+ //
+ // We implement this here by simply overwriting the upper byte of F with the upper bits of rB
+ // (or its complement), and clearing CarryOut and Overflow.
+ //
+ switch ((AluFunction)((int)i.aF | 0x3))
+ {
+ case AluFunction.RorS:
+ {
+ f = (f & 0xff) | (_r[i.rB] & 0xff00);
+ bool midCarry = _carryTableOr[(r >> 8) & 0xf, (s >> 8) & 0xf, PgCarry ? 1 : 0];
+ Overflow = CarryOut = _carryTableOr[(r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ }
+ break;
+
+ case AluFunction.notRxorS:
+ {
+ f = (f & 0xff) | ((~_r[i.rB]) & 0xff00);
+ bool midCarry = _carryTableNotXor[(r >> 8) & 0xf, (s >> 8) & 0xf, PgCarry ? 1 : 0];
+ CarryOut = _carryTableNotXor[(r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ Overflow = _overflowNotXor[(r >> 12) & 0xf, (s >> 12) & 0xf, midCarry ? 1 : 0];
+ }
+ break;
+ }
+ }
+
+ Zero = (f == 0);
+ Neg = ((f & 0x8000) != 0);
+
+ //
+ // Write outputs, do shifts and cycles as appropriate before writing back.
+ // (Shifts and cycles do not affect the Y output, only the register being written back to.)
+ //
+ switch (i.AluDestination)
+ {
+ case 0:
+ _q = (ushort)f;
+ Y = (ushort)f;
+ break;
+
+ case 1:
+ Y = (ushort)f;
+ break;
+
+ case 2:
+ Y = _r[i.rA];
+ _r[i.rB] = (ushort)f;
+ break;
+
+ case 3:
+ _r[i.rB] = (ushort)f;
+ Y = (ushort)f;
+ break;
+
+ case 4:
+ Y = (ushort)f;
+
+ if (i.Cycle)
+ {
+ // double-word right shift
+ // MSB of Q gets inverted LSB of F.
+ _q = (ushort)((_q >> 1) | ((~f & 0x1) << 15));
+
+ // MSB of F gets Carry in.
+ f = (ushort)((f >> 1) | (carryIn ? 0x8000 : 0x0));
+ }
+ else
+ {
+ // double-word arithmetic right shift.
+ // MSB of Q gets inverted LSB of F.
+ _q = (ushort)((_q >> 1) | ((~f & 0x1) << 15));
+
+ // MSB of F gets Carry out.
+ f = (ushort)((f >> 1) | (CarryOut ? 0x8000 : 0x0));
+ }
+ _r[i.rB] = (ushort)f;
+ break;
+
+ case 5:
+ Y = (ushort)f;
+ if (i.Cycle)
+ {
+ // F: single-word right rotate:
+ f = (ushort)((f >> 1) | ((f & 0x1) << 15));
+ }
+ else
+ {
+ // F: single-word right shift w/carryIn to MSB:
+ f = (ushort)((f >> 1) | (carryIn ? 0x8000 : 0x0));
+ }
+ _r[i.rB] = (ushort)f;
+ break;
+
+ case 6:
+ Y = (ushort)f;
+
+ // double-word left shift (apparently identical for cycle and shift)
+ // LSB of F gets MSB of Q, not inverted.
+ f = (ushort)((f << 1) | ((_q & 0x8000) >> 15));
+
+ // LSB of Q gets Cin, inverted
+ _q = (ushort)((_q << 1) | (1 - cIn));
+
+ _r[i.rB] = (ushort)f;
+ break;
+
+ case 7:
+ Y = (ushort)f;
+ if (i.Cycle)
+ {
+ // F: single-word left rotate:
+ f = (ushort)((f << 1) | ((f & 0x8000) >> 15));
+ }
+ else
+ {
+ // F: single-word left shift w/carryIn to LSB:
+ f = (ushort)((f << 1) | cIn);
+ }
+ _r[i.rB] = (ushort)f;
+ break;
+
+ default:
+ throw new InvalidOperationException(
+ String.Format("Unhandled destination {0}", i.aF));
+ }
+
+ return Y;
+ }
+
+
+ ///
+ /// TODO: replace with a nice table lookup.
+ ///
+ ///
+ ///
+ ///
+ ///
+ private static bool CalcOverflow(int r, int s, int cIn)
+ {
+ int p0 = (r | s) & 0x1;
+ int p1 = ((r | s) & 0x2) >> 1;
+ int p2 = ((r | s) & 0x4) >> 2;
+ int p3 = ((r | s) & 0x8) >> 3;
+
+ int g0 = (r & s & 0x1);
+ int g1 = (r & s & 0x2) >> 1;
+ int g2 = (r & s & 0x4) >> 2;
+ int g3 = (r & s & 0x8) >> 3;
+
+ int c4 = g3 | (p3 & g2) | (p3 & p2 & g1) | (p3 & p2 & p1 & g0) | (p3 & p2 & p1 & p0 & cIn);
+ int c3 = g2 | (p2 & g1) | (p2 & p1 & g0) | (p2 & p1 & p0 & cIn);
+
+ return (c3 ^ c4) != 0;
+ }
+
+ private static bool CalcCarryArithmetic(int r, int s, int cIn)
+ {
+ int p0 = (r | s) & 0x1;
+ int p1 = ((r | s) & 0x2) >> 1;
+ int p2 = ((r | s) & 0x4) >> 2;
+ int p3 = ((r | s) & 0x8) >> 3;
+
+ int g0 = (r & s & 0x1);
+ int g1 = (r & s & 0x2) >> 1;
+ int g2 = (r & s & 0x4) >> 2;
+ int g3 = (r & s & 0x8) >> 3;
+
+ int c4 = g3 | (p3 & g2) | (p3 & p2 & g1) | (p3 & p2 & p1 & g0) | (p3 & p2 & p1 & p0 & cIn);
+
+ return c4 != 0;
+ }
+
+ private static bool CalcCarryOr(int r, int s, int cIn)
+ {
+ int p0 = (r | s) & 0x1;
+ int p1 = ((r | s) & 0x2) >> 1;
+ int p2 = ((r | s) & 0x4) >> 2;
+ int p3 = ((r | s) & 0x8) >> 3;
+
+ int c4 = (~(p3 & p2 & p1 & p0) & 0x1) | cIn;
+
+ return c4 != 0;
+ }
+
+ private static bool CalcCarryAnd(int r, int s, int cIn)
+ {
+ int g0 = (r & s & 0x1);
+ int g1 = (r & s & 0x2) >> 1;
+ int g2 = (r & s & 0x4) >> 2;
+ int g3 = (r & s & 0x8) >> 3;
+
+ int c4 = g3 | g2 | g1 | g0 | cIn;
+
+ return c4 != 0;
+ }
+
+ private static bool CalcCarryNotXor(int r, int s, int cIn)
+ {
+ int p0 = (r | s) & 0x1;
+ int p1 = ((r | s) & 0x2) >> 1;
+ int p2 = ((r | s) & 0x4) >> 2;
+ int p3 = ((r | s) & 0x8) >> 3;
+
+ int g0 = (r & s & 0x1);
+ int g1 = (r & s & 0x2) >> 1;
+ int g2 = (r & s & 0x4) >> 2;
+ int g3 = (r & s & 0x8) >> 3;
+
+ int c4 = ~(g3 | (p3 & g2) | (p3 & p2 & g1) | (p3 & p2 & p1 & p0 & (g0 | ~cIn))) & 0x1;
+
+ return c4 != 0;
+ }
+
+ private static bool CalcOverflowNotXor(int r, int s, int cIn)
+ {
+ int p0 = (r | s) & 0x1;
+ int p1 = ((r | s) & 0x2) >> 1;
+ int p2 = ((r | s) & 0x4) >> 2;
+ int p3 = ((r | s) & 0x8) >> 3;
+
+ int g0 = (r & s & 0x1);
+ int g1 = (r & s & 0x2) >> 1;
+ int g2 = (r & s & 0x4) >> 2;
+ int g3 = (r & s & 0x8) >> 3;
+
+ int ovr = ((~p2 | (~g2 & ~p1) | (~g2 & ~g1 & ~p0) | (~g2 & ~g1 & ~g0 & cIn)) ^
+ (~p3 | (~g3 & ~p2) | (~g3 & ~g2 & ~p1) | (~g3 & ~g2 & ~g1 & ~p0) | (~g3 & ~g2 & ~g1 & ~g0 & cIn))) & 0x1;
+
+ return ovr != 0;
+ }
+
+ private static void BuildTables()
+ {
+ for (int r = 0; r < 16; r++)
+ {
+ for (int s = 0; s < 16; s++)
+ {
+ for (int c = 0; c < 2; c++)
+ {
+ _overflowTable[r, s, c] = CalcOverflow(r, s, c);
+ _carryTableArithmetic[r, s, c] = CalcCarryArithmetic(r, s, c);
+ _carryTableOr[r, s, c] = CalcCarryOr(r, s, c);
+ _carryTableAnd[r, s, c] = CalcCarryAnd(r, s, c);
+ _carryTableNotXor[r, s, c] = CalcCarryNotXor(r, s, c);
+ _overflowNotXor[r, s, c] = CalcOverflowNotXor(r, s, c);
+ }
+ }
+ }
+ }
+
+ //
+ // Overflow lookup table for most-significant nibble.
+ //
+ private static bool[,,] _overflowTable = new bool[16, 16, 2];
+ private static bool[,,] _carryTableArithmetic = new bool[16, 16, 2];
+ private static bool[,,] _carryTableOr = new bool[16, 16, 2];
+ private static bool[,,] _carryTableAnd = new bool[16, 16, 2];
+ private static bool[,,] _carryTableNotXor = new bool[16, 16, 2];
+ private static bool[,,] _overflowNotXor = new bool[16, 16, 2];
+
+ //
+ // Registers
+ //
+ private ushort[] _r = new ushort[16];
+ private ushort _q;
+
+ //
+ // Flags
+ //
+ public bool Zero;
+ public bool Neg;
+ public bool NibCarry;
+ public bool PgCarry;
+ public bool CarryOut;
+ public bool Overflow;
+
+ //
+ // Output
+ //
+ public ushort Y;
+ }
+}
diff --git a/D/CP/CentralProcessor.cs b/D/CP/CentralProcessor.cs
new file mode 100644
index 0000000..13e9764
--- /dev/null
+++ b/D/CP/CentralProcessor.cs
@@ -0,0 +1,1634 @@
+/*
+ BSD 2-Clause License
+
+ Copyright Vulcan Inc. 2017-2018 and Living Computer Museum + Labs 2018
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+using D.IOP;
+using D.Logging;
+using System;
+
+namespace D.CP
+{
+ public enum TaskType
+ {
+ Emulator = 0,
+ Display,
+ Ethernet,
+ Refresh,
+ Disk,
+ IOP,
+ IOPcs, // Used as an address register when reading/writing control store
+ Kernel,
+ }
+
+ public enum ClickType
+ {
+ Ethernet0 = 0,
+ Disk,
+ IOP,
+ Ethernet1,
+ Display
+ }
+
+ ///
+ /// IB state, corresponding to the value of iBPtr
+ ///
+ public enum IBState
+ {
+ Full = 2,
+ Word = 3,
+ Byte = 1,
+ Empty = 0,
+ }
+
+ ///
+ /// The Dandelion Central Processor, processor implementation.
+ /// This partial class implements the logic for the microcode engine.
+ ///
+ public partial class CentralProcessor : IIOPDevice, IDMAInterface
+ {
+ public CentralProcessor(DSystem system)
+ {
+ Reset();
+
+ _system = system;
+ }
+
+ public void Reset()
+ {
+ _currentTask = TaskType.Kernel;
+
+ _cycle = 1; // Start in C1
+ _click = ClickType.Ethernet0;
+
+ // On reset, we need the IOP to wake us up before we
+ // can start running.
+ _iopWait_ = true;
+
+ //
+ // Clear interrupt flags and errors
+ //
+ _mInt = false;
+ _eKErr = 0;
+ _emulatorErrorTrap = false;
+ _emulatorErrorTrapClickCount = 0;
+
+ Array.Clear(_microcode, 0, _microcode.Length);
+ Array.Clear(_microcodeCache, 0, _microcodeCache.Length);
+ Array.Clear(_tpc, 0, _tpc.Length);
+ Array.Clear(_tc, 0, _tc.Length);
+ Array.Clear(_wakeup, 0, _wakeup.Length);
+ Array.Clear(_rh, 0, _rh.Length);
+ Array.Clear(_u, 0, _u.Length);
+ Array.Clear(_link, 0, _link.Length);
+ Array.Clear(_ib, 0, _ib.Length);
+
+ _tpcAddr = 0;
+ _stackP = 0;
+ _ibPtr = IBState.Empty;
+ _ibFront = 0;
+ _ibEmptyCancel = false;
+ _pc16 = false;
+ _niaModifier = 0;
+ _niaModifierType = NiaModiferType.Normal;
+ _marPageCrossBr = false;
+ _altUAddr = false;
+
+ _swTAddr = false;
+ _iopAttn = false;
+ _cpDmaMode = false;
+ _cpDmaIn = false;
+ _cpDmaComplete_ = false;
+ _wakeMode0 = false;
+ _wakeMode1 = false;
+ _cpAttn = false;
+ _emuWake = false;
+ _cpOutIntReq_ = true;
+ _cpInIntReq_ = true;
+ _iopReq = false;
+ _inLatched = false;
+ _outLatched = false;
+
+ _exitKernel = false;
+ }
+
+ public ulong[] MicrocodeRam
+ {
+ get { return _microcode; }
+ }
+
+ public byte[] RH
+ {
+ get { return _rh; }
+ }
+
+ public ushort[] U
+ {
+ get { return _u; }
+ }
+
+ public TaskType CurrentTask
+ {
+ get { return _currentTask; }
+ }
+
+ public int[] TPC
+ {
+ get { return _tpc; }
+ }
+
+ public int NIAModifier
+ {
+ get { return _niaModifier; }
+ }
+
+ public AM2901 ALU
+ {
+ get { return _alu; }
+ }
+
+ public int Cycle
+ {
+ get { return _cycle; }
+ }
+
+ public int StackP
+ {
+ get { return _stackP; }
+ }
+
+ public byte IBFront
+ {
+ get { return _ibFront; }
+ }
+
+ public byte[] IB
+ {
+ get { return _ib; }
+ }
+
+ public IBState IBPtr
+ {
+ get { return _ibPtr; }
+ }
+
+ public bool PC16
+ {
+ get { return _pc16; }
+ }
+
+ ///
+ /// Whether the processor is waiting to be awoken by the IOP.
+ ///
+ public bool IOPWait
+ {
+ get { return _iopWait_; }
+ }
+
+ ///
+ /// Used by debuggers to allow stepping macrocode
+ ///
+ public bool IBDispatch
+ {
+ get
+ {
+ bool value = _ibDispatch;
+ _ibDispatch = false;
+ return value;
+ }
+ }
+
+ ///
+ /// Executes the specified number of microinstructions
+ ///
+ public void ExecuteInstruction(int cycles)
+ {
+ for (int c = 0; c < cycles; c++)
+ {
+ //
+ // Let the scheduler run for one clock.
+ //
+ _system.Scheduler.Clock();
+
+ if (_iopWait_)
+ {
+ // Still waiting for the IOP to wake us.
+ continue;
+ }
+
+ //
+ // TODO: General:
+ // Section 2.3.8 of the Dandelion Hardware manual outlines a set of timing restrictions
+ // for Xbus-related operations. These restrictions are closely related to the mechanisms
+ // of the CP hardware and are tricky to emulate without actually simulating things at close
+ // to the component-level. In particular, some Xbus operations are only valid across a subset
+ // of ALU bits (due to propagation delays between the AM2901s). However: a naive emulation
+ // should likely work for existing microcode since it would be written to meet these timing
+ // restrictions -- said emulation would always return a valid result across all bits but this
+ // satisfies the microcode. Where this falls down is that microcode that would be incorrect
+ // on a real Dandelion might "work" on the emulator.
+ // At this time, the naive implementation is Good Enough (tm) and once that's working, making
+ // a more technically correct implementation can be investigated.
+ //
+
+ //
+ // Grab the next instruction from the cache.
+ //
+ Microinstruction instruction = _microcodeCache[_tpc[(int)_currentTask]];
+
+ bool cIn = instruction.Cin;
+ bool invertPc16 = false;
+
+ //
+ // If the last instruction caused a PageCross branch during a memory operation, we must
+ // cancel any MDR<-, IBDisp, or AlwaysIBDisp in this instruction.
+ //
+ bool pageCrossCancel = _marPageCrossBr;
+ _marPageCrossBr = false;
+
+ //
+ // Latch the NIA modifier bits from the last instruction
+ //
+ int niaModifier = _niaModifier;
+ _niaModifier = 0;
+
+ //
+ // Latch the AltUAddr bit from the last instruction
+ //
+ bool altUAddr = _altUAddr;
+ _altUAddr = false;
+
+ //
+ // Save the previous instruction's Y Bus for AltUAddr.
+ //
+ ushort lastYBus = _yBus;
+
+ //
+ // Latch the IBError cancel bit (cancels an MDR<- operation if an IB read
+ // in c1 failed due to an empty IB).
+ //
+ bool ibEmptyCancel = _ibEmptyCancel;
+ _ibEmptyCancel = false;
+
+ //
+ // Latch the dispatch type from the last instruction so that we can
+ // properly modify INIA at the end of this one.
+ //
+ NiaModiferType niaModifierType = _niaModifierType;
+ _niaModifierType = NiaModiferType.Normal;
+
+ //
+ // Decode XBus sources:
+ //
+
+ //
+ // Byte and/or Nibble constants from the microinstruction fields.
+ // NB: instruction.Byte is set to 0 if this instruction does not specify a Byte or Nibble constant.
+ //
+ _xBus = instruction.Byte;
+
+ switch (instruction.fSfZ)
+ {
+ case FunctionSelectFZ.fzNorm:
+ switch ((ZNormFunction)instruction.fZ)
+ {
+ case ZNormFunction.LoadIBPtr1:
+ if (instruction.AlwaysIBDisp ||
+ instruction.LoadIB)
+ {
+ // This instruction uses IBPtr<-1 as a modifier; leave ibPtr/ibFront alone here; they will get modified later.
+ }
+ else
+ {
+ if (_ibPtr != IBState.Byte)
+ {
+ _ibPtr = IBState.Byte;
+ _ibFront = _ib[1];
+ }
+
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPIB, "ibPtr<-1: ibPtr={0}, ibFront=0x{1:x2}", _ibPtr, _ibFront);
+ }
+ break;
+
+ case ZNormFunction.LoadIBPtr0:
+ if (_ibPtr != IBState.Word)
+ {
+ _ibPtr = IBState.Word;
+ _ibFront = _ib[0];
+ }
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPIB, "ibPtr<-0: ibPtr={0}, ibFront=0x{1:x2}", _ibPtr, _ibFront);
+ break;
+
+ case ZNormFunction.LoadCinFrompc16:
+ //
+ // Fun fact (from microcode ref, pg. 21):
+ // "Due to the way Cin is implemented in the hardware, when the Cin field of the microinstruction is
+ // 0, the fX version of Cin<-pc16 must be used. (If the fZ version is used, Cin will be 0 instead
+ // of pc16.) If Cin=1, then either version of Cin<-pc16 can be used.
+ //
+ if (cIn)
+ {
+ cIn = _pc16;
+ }
+ invertPc16 = true; // Invert pc16 at the end of the cycle.
+ break;
+
+ case ZNormFunction.LoadBank:
+ throw new NotImplementedException("Bank<- not implemented.");
+
+ case ZNormFunction.AltUaddr:
+ _altUAddr = true;
+ break;
+
+ case ZNormFunction.LRot0:
+ if (instruction.ABypass)
+ {
+ _xBus = _alu.R[instruction.rA];
+ }
+ break;
+
+ case ZNormFunction.LRot12:
+ if (instruction.ABypass)
+ {
+ _xBus = (ushort)((_alu.R[instruction.rA] << 12) | (_alu.R[instruction.rA] >> 4));
+ }
+ break;
+
+ case ZNormFunction.LRot8:
+ if (instruction.ABypass)
+ {
+ _xBus = (ushort)((_alu.R[instruction.rA] << 8) | (_alu.R[instruction.rA] >> 8));
+ }
+ break;
+
+ case ZNormFunction.LRot4:
+ if (instruction.ABypass)
+ {
+ _xBus = (ushort)((_alu.R[instruction.rA] << 4) | (_alu.R[instruction.rA] >> 12));
+ }
+ break;
+ }
+ break;
+
+ case FunctionSelectFZ.IOXIn:
+ switch ((ZIOXIn)instruction.fZ)
+ {
+ case ZIOXIn.ReadEIdata:
+ _xBus = _system.EthernetController.EIData(_cycle);
+ break;
+
+ case ZIOXIn.ReadEStatus:
+ _xBus = _system.EthernetController.EStatus();
+ break;
+
+ case ZIOXIn.ReadKIData:
+ _xBus = _system.ShugartController.ReadKIData();
+ break;
+
+ case ZIOXIn.ReadKStatus:
+ _xBus = _system.ShugartController.ReadKStatus();
+ break;
+
+ case ZIOXIn.KStrobe:
+ _system.ShugartController.KStrobe();
+ break;
+
+ case ZIOXIn.ReadMStatus:
+ _xBus = _system.MemoryController.MStatus;
+ break;
+
+ case ZIOXIn.ReadKTest:
+ _xBus = _system.ShugartController.ReadKTest();
+ break;
+
+ case ZIOXIn.EStrobe:
+ _system.EthernetController.EStrobe(_cycle);
+ break;
+
+ case ZIOXIn.ReadIOPIData:
+ _xBus = ReadIOPData();
+ if (Log.Enabled) Log.Write(LogComponent.CPControl, "<-IOPData {0:x2}", _xBus);
+ break;
+
+ case ZIOXIn.ReadIOPStatus:
+ _xBus = ReadIOPStatus();
+ if (Log.Enabled) Log.Write(LogComponent.CPControl, "<-IOPStatus {0} ({1:x2})", (IOPStatusFlags)_xBus, _xBus);
+ break;
+
+ case ZIOXIn.ReadErrnIBnStkp:
+ // uCode reference, p.33:
+ // "X[8-9] = EKerr, X[10-11] = ~ibPtr, X[12-15] = ~stackP
+ //
+ _xBus =
+ (ushort)((_eKErr << 6) |
+ ((~(int)_ibPtr & 0x3) << 4) |
+ (~_stackP & 0xf));
+ break;
+
+ case ZIOXIn.ReadRH:
+ _xBus = _rh[instruction.rB];
+ break;
+
+ case ZIOXIn.ReadibNA:
+ if (_ibPtr == IBState.Empty)
+ {
+ // IB is empty, trap.
+ SignalErrorTrap(ErrorTrap.IBEmpty);
+
+ // Cancel MDR<- in c2
+ _ibEmptyCancel = _cycle == 1;
+ }
+ else
+ {
+ // xBus <- ibFront, leave ibPtr alone.
+ _xBus = _ibFront;
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPIB, "<-ibNA 0x{0:x2} ibPtr={1}", _ibFront, _ibPtr);
+ }
+ break;
+
+ case ZIOXIn.Readib:
+ if (_ibPtr == IBState.Empty)
+ {
+ // IB is empty, trap.
+ SignalErrorTrap(ErrorTrap.IBEmpty);
+
+ // Cancel MDR<- in c2
+ _ibEmptyCancel = _cycle == 1;
+ }
+ else
+ {
+ // xBus <- ibFront, decrement ibPtr.
+ _xBus = _ibFront;
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPIB, "<-ib 0x{0:x2} ibPtr={1}", _ibFront, _ibPtr);
+
+ _ibFront = _ib[((int)_ibPtr) & 0x1];
+ DecrementIBPtr();
+
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPIB, "ibFront now 0x{0:x2} ibPtr={1}", _ibFront, _ibPtr);
+ }
+ break;
+
+ case ZIOXIn.ReadibLow:
+ if (_ibPtr == IBState.Empty)
+ {
+ // IB is empty, trap.
+ SignalErrorTrap(ErrorTrap.IBEmpty);
+
+ // Cancel MDR<- in c2
+ _ibEmptyCancel = _cycle == 1;
+ }
+ else
+ {
+ // low nibble of ibFront, leave ibPtr alone.
+ _xBus = (ushort)(_ibFront & 0xf);
+
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPIB, "<-ibLow 0x{0:x2} ibPtr={1}", _xBus, _ibPtr);
+ }
+ break;
+
+ case ZIOXIn.ReadibHigh:
+ if (_ibPtr == IBState.Empty)
+ {
+ // IB is empty, trap.
+ SignalErrorTrap(ErrorTrap.IBEmpty);
+
+ // Cancel MDR<- in c2
+ _ibEmptyCancel = _cycle == 1;
+ }
+ else
+ {
+ // high nibble of ibFront, leave ibPtr alone.
+ _xBus = (ushort)(_ibFront >> 4);
+
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPIB, "<-ibHigh 0x{0:x2} ibPtr={1}", _xBus, _ibPtr);
+ }
+ break;
+ }
+ break;
+ }
+
+ if (instruction.fX == XFunction.LoadCinFrompc16)
+ {
+ cIn = _pc16;
+ invertPc16 = true; // Invert pc16 at the end of the cycle.
+ }
+
+ if (instruction.SURead)
+ {
+ // SU read operations
+ switch ((int)instruction.fSfZ)
+ {
+ case 0:
+ case 1:
+ _xBus = _u[_stackP];
+ break;
+
+ case 2:
+ case 3:
+ if (altUAddr)
+ {
+ // U address is rA,,Y[12-15]
+ // (Y bus from *previous* instruction.)
+ _xBus = _u[(instruction.rA << 4) | (lastYBus & 0xf)];
+ }
+ else
+ {
+ // U address is rA,,fZ
+ _xBus = _u[instruction.UAddress];
+ }
+ break;
+ }
+ }
+
+ // Handle <-MD instructions which occur only in C3.
+ if (instruction.mem && _cycle == 3)
+ {
+ bool valid = false;
+ _xBus = _system.MemoryController.ReadMD(_currentTask, out valid);
+
+ if (!valid)
+ {
+ //
+ // Read from non-existent or uncorrectable memory. This causes a double-bit memory fault.
+ //
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPError, "Invalid memory access, address 0x{0:x5}", _system.MemoryController.MAR);
+ SignalErrorTrap(ErrorTrap.EmulatorMemoryError);
+ }
+ }
+
+ //
+ // Generate new Y bus value after feeding it through the ALU.
+ //
+ _yBus = _alu.Execute(instruction, _xBus, cIn, (instruction.mem && _cycle == 1));
+
+ //
+ // Handle MAR<-, Map<- and MDR<-, which take their input from the Y Bus (+ YH for MAR<-).
+ //
+ if (instruction.MarMapMDR)
+ {
+ switch (_cycle)
+ {
+ case 1:
+
+ if (instruction.LoadMap)
+ {
+ //
+ // Map<- : This is 0x10000 + YH[0-7],,Y[0-7], providing a 24-bit virtual address indexing
+ // into the virtual memory map (64k).
+ // Earlier CP boards only supported 22-bit VA's (using only YH[2-7], indexing into a 16k map.)
+ //
+#if TWENTYTWOBITVA
+ int mapAddr = 0x10000 + ((((_rh[instruction.rB] & 0x3f) << 16) | _yBus) >> 8);
+ _system.MemoryController.LoadMAR(mapAddr);
+
+ if ((_rh[instruction.rB] & 0xc0) != 0)
+ {
+ SignalErrorTrap(ErrorTrap.EmulatorMemoryError);
+ }
+#else
+ int mapAddr = 0x10000 + (((_rh[instruction.rB] << 16) | _yBus) >> 8);
+ _system.MemoryController.LoadMAR(mapAddr);
+#endif
+
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPMap, "Map<- 0x{0:x8} address loaded.", mapAddr);
+ }
+ else
+ {
+ //
+ // MAR<-: This is YH[4..7],,Y, providing a 20-bit physical address.
+ // Earlier CP boards only supported 18-bit physical addresses.
+ //
+#if EIGHTEENBITPA
+ _system.MemoryController.LoadMAR(((_rh[instruction.rB] & 0x3) << 16) | _yBus);
+#else
+ _system.MemoryController.LoadMAR(((_rh[instruction.rB] & 0xf) << 16) | _yBus);
+#endif
+ }
+
+ //
+ // Do MAR<- side-effects: pageCross branch
+ // See the HW ref, page 25.
+ // pageCross is the XOR of the carry out from the low byte of the ALU with af[2].
+ //
+ if (instruction.mem && (_alu.PgCarry ^ (((int)instruction.aF & 0x1) == 1)))
+ {
+ // MAR<- enables a pageCross branch in INIA[10].
+ _niaModifier |= 0x2;
+ _marPageCrossBr = true;
+ }
+ break;
+
+ case 2:
+ //
+ // Sanity check that Map<- is not occurring in c2:
+ //
+ if (instruction.LoadMap)
+ {
+ throw new InvalidOperationException("Map<- in c2");
+ }
+
+ // MDR<-
+ if (!pageCrossCancel && !ibEmptyCancel)
+ {
+ _system.MemoryController.LoadMDR(_yBus);
+ }
+ break;
+
+ case 3:
+ //
+ // Sanity check that Map<- is not occurring in c3:
+ //
+ if (instruction.LoadMap)
+ {
+ throw new InvalidOperationException("Map<- in c3");
+ }
+ break;
+ }
+ }
+
+ //
+ // Late LRotn functions.
+ // These take the ALU output on the Y Bus and apply the specified rotation,
+ // putting the result on the X Bus.
+ //
+ if (instruction.LateLRotN)
+ {
+ switch ((ZNormFunction)instruction.fZ)
+ {
+ case ZNormFunction.LRot0:
+ _xBus = _yBus;
+ break;
+
+ case ZNormFunction.LRot12:
+ _xBus = (ushort)((_yBus << 12) | (_yBus >> 4));
+ break;
+
+ case ZNormFunction.LRot8:
+ _xBus = (ushort)((_yBus << 8) | (_yBus >> 8));
+ break;
+
+ case ZNormFunction.LRot4:
+ _xBus = (ushort)((_yBus << 4) | (_yBus >> 12));
+ break;
+ }
+ }
+
+ //
+ // Load RH register from X Bus.
+ //
+ if (instruction.fX == XFunction.LoadRH)
+ {
+ _rh[instruction.rB] = (byte)_xBus;
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPExecution, "RH[0x{0:x2}] = 0x{1:x2}", instruction.rB, _xBus);
+ }
+
+ // Handle fY functions that aren't implicitly handled elsewhere (cycle, Byte, etc.)
+ switch (instruction.fSfY)
+ {
+ case FunctionSelectFY.fyNorm:
+ switch ((YNormFunction)instruction.fY)
+ {
+ case YNormFunction.ExitKern:
+ //
+ // Microcode ref, p 34 (section K.3):
+ // "When executed in c1, ExitKern will cause normal task scheduling to begin. Thus,
+ // which task runs in the click following ExitKern depends on where in the round structure
+ // the ExitKern occured. [sic]"
+ //
+ if (_cycle == 1)
+ {
+ _exitKernel = true;
+ }
+ break;
+
+ case YNormFunction.EnterKern:
+ throw new NotImplementedException("EnterKern not implemented.");
+
+ case YNormFunction.ClrIntErr:
+ //
+ // Clear pending interrupts and error state:
+ //
+ // HwRef sec 2.5.3:
+ // "MInt is ... cleared with fY = ClrIntErr. (ClrIntErr also resets
+ // the EKErr register.)"
+ //
+ // HwRef sec 2.5.5.2:
+ // "[EKErr is] Cleared by ClrIntErr, which, as a side-effect, also resets any pending interrupts."
+ //
+ _mInt = false;
+ _eKErr = 0;
+ break;
+
+ case YNormFunction.IBDisp:
+ //
+ // NB: AlwaysIBDisp is not a special function, it is an assembler macro for IBDisp, IBPtr<- 1.
+ // This is canceled if the last memory operation resulted in a page cross.
+ if (!pageCrossCancel)
+ {
+ if ((_ibPtr != IBState.Full || _mInt) && !instruction.AlwaysIBDisp)
+ {
+ //
+ // From hw ref (2.5.5.1)
+ // If an IBDisp is executed and ibPtr != full, the dispatch does not occur and instead a microcode trap is invoked.
+ // The jump to the trap location occurs at the end of the next cycle (unlike emulator error traps which happen
+ // in a future c1).
+ // - INIA[0-3] is replaced with 4 when ibPtr = empty or 5 when ibPtr != empty
+ // - If there is a pending Mesa interrupt request (_mInt = 1):
+ // - INIA[0-3] is replaced with 6 if ibPtr = empty or full, or 7 otherwise.
+ // Regardless, ibPtr does not change.
+ //
+ // A non-trapping IBDispatch is forced by fZ = IBPtr<-1 (i.e. AlwaysIBDisp).
+ //
+ if (_mInt)
+ {
+ _niaModifier |= (_ibPtr == IBState.Empty || _ibPtr == IBState.Full) ? 0x600 : 0x700;
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPIB, "Mint trap to 0x{0:x3}", _niaModifier);
+
+ }
+ else
+ {
+ _niaModifier |= (_ibPtr == IBState.Empty) ? 0x400 : 0x500;
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPIB, "IB refill trap to 0x{0:x3}", _niaModifier);
+ }
+
+ _niaModifierType = NiaModiferType.IBRefillTrap;
+ }
+ else
+ {
+ //
+ // Do the normal dispatch, and decrement ibPtr when done.
+ // Unlike other dispatches, ibFront replaces some bits (rather than just or'ing) of
+ // the next instruction's INIA. This needs to be specially handled.
+ // "The high 4 bits of ibFront replace INIA[4-7] while the low 4 bits of ibFront are OR'd
+ // with INIA[8-11] (thereby allowing simultaneous branch/dispatches). INIA[0-3] is unaffected.
+ //
+ _niaModifier |= _ibFront;
+ _niaModifierType = NiaModiferType.IBDispatch;
+
+ /*
+ MacroInstruction inst = MacroInstruction.GetInstruction(MacroType.Lisp, _ibFront);
+
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPInst,
+ "PC 0x{0:x5} - 0x{1:x2} ({2}) ibPtr ({3}) {4}",
+ ((((_rh[5] & 0xf) << 16) | _alu.R[5]) << 1) | (_pc16 ? 1 : 0),
+ _ibFront,
+ inst.Mnemonic,
+ inst.Operand,
+ _ibPtr);
+ */
+
+ // new ibFront is IB[ibPtr[1]]
+ _ibFront = _ib[((int)_ibPtr) & 0x1];
+
+ DecrementIBPtr();
+
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPIB, "<-ibFront 0x{0:x2} ibPtr={1}", _ibFront, _ibPtr);
+ }
+ }
+ break;
+
+ case YNormFunction.MesaIntRq:
+ _mInt = true;
+ break;
+
+ case YNormFunction.LoadIB:
+ if (instruction.LoadIBPtr1)
+ {
+ //
+ // If buffer is empty, the low byte goes to ibFront and the high
+ // byte is discarded, otherwise load ib[0] and ib[1] and leave
+ // ibFront alone. (hwref, p. 20)
+ //
+ if (_ibPtr != IBState.Empty)
+ {
+ _ib[0] = (byte)(_xBus >> 8);
+ _ib[1] = (byte)_xBus;
+
+ // new ibPtr: "if empty THEN byte ELSE full"
+ _ibPtr = IBState.Full;
+
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPIB, "ibPtr<-1 IB<-, notempty: ibPtr={0}, ib[0]=0x{1:x2} ib[1]=0x{2:x2}", _ibPtr, _ib[0], _ib[1]);
+ }
+ else
+ {
+ // new ibPtr: "if empty THEN byte ELSE full"
+ _ibPtr = IBState.Byte;
+
+ // new ibFront: "if ibPtr = empty THEN X[8-15] ELSE unchanged"
+ _ibFront = (byte)_xBus;
+
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPIB, "ibPtr<-1 IB<-, empty: ibPtr={0}, ibFront=0x{1:x2}", _ibPtr, _ibFront);
+ }
+ }
+ else
+ {
+ // low byte to ib[1]
+ _ib[1] = (byte)_xBus;
+
+ if (_ibPtr != IBState.Empty)
+ {
+ // high byte to ib[0]
+ _ib[0] = (byte)(_xBus >> 8);
+
+ // new ibPtr: "if empty THEN word ELSE full"
+ _ibPtr = IBState.Full;
+
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPIB, "IB<-, notempty: ibPtr={0}, ib[0]=0x{1:x2} ib[1]=0x{2:x2}", _ibPtr, _ib[0], _ib[1]);
+ }
+ else
+ {
+ // new ibFront: "if ibPtr = empty THEN X[0-7] ELSE unchanged"
+ _ibFront = (byte)(_xBus >> 8);
+
+ // new ibPtr: "if empty THEN word ELSE full"
+ _ibPtr = IBState.Word;
+
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPIB, "IB<-, empty: ibPtr={0}, ibFront=0x{1:x2}, ib[0]=0x{2:x2} ib[1]=0x{3:x2}", _ibPtr, _ibFront, _ib[0], _ib[1]);
+ }
+ }
+ break;
+
+ case YNormFunction.ClrDPRq:
+ _system.DisplayController.ClrDpRq();
+ break;
+
+ case YNormFunction.ClrIOPRq:
+ SleepTask(TaskType.IOP);
+ break;
+
+ case YNormFunction.ClrRefRq:
+ SleepTask(TaskType.Refresh);
+ break;
+
+ case YNormFunction.ClrKFlags:
+ _system.ShugartController.ClrKFlags();
+ break;
+ }
+ break;
+
+ case FunctionSelectFY.DispBr:
+ switch ((YDispBrFunction)instruction.fY)
+ {
+ case YDispBrFunction.NegBr:
+ if (_alu.Neg)
+ {
+ _niaModifier |= 1;
+ }
+ break;
+
+ case YDispBrFunction.ZeroBr:
+ if (_alu.Zero)
+ {
+ _niaModifier |= 1;
+ }
+ break;
+
+ case YDispBrFunction.NZeroBr:
+ if (!_alu.Zero)
+ {
+ _niaModifier |= 1;
+ }
+ break;
+
+ case YDispBrFunction.MesaIntBr:
+ if (_mInt)
+ {
+ _niaModifier |= 1;
+ }
+ break;
+
+ case YDispBrFunction.PgCarryBr:
+ if (_alu.PgCarry)
+ {
+ _niaModifier |= 1;
+ }
+ break;
+
+ case YDispBrFunction.CarryBr:
+ if (_alu.CarryOut)
+ {
+ _niaModifier |= 1;
+ }
+ break;
+
+ case YDispBrFunction.XRefBr:
+ //
+ // Dispatch on X[11] into INIA[11]
+ //
+ _niaModifier |= (_xBus & 0x10) >> 4;
+ break;
+
+ case YDispBrFunction.NibCarryBr:
+ if (_alu.NibCarry)
+ {
+ _niaModifier |= 1;
+ }
+ break;
+
+ case YDispBrFunction.XDisp:
+ _niaModifier |= (_xBus & 0xf);
+ break;
+
+ case YDispBrFunction.YDisp:
+ _niaModifier |= (_yBus & 0xf);
+ break;
+
+ case YDispBrFunction.XC2npcDisp:
+ //
+ // Dispatch on X[12-13],,cycle 2,,~pc16 into INIA[8-11]
+ //
+ _niaModifier |= (_xBus & 0xc) | (_cycle == 2 ? 0x2 : 0x0) | (_pc16 ? 0x0 : 0x1);
+ break;
+
+ case YDispBrFunction.YIODisp:
+ //
+ // Dispatch on Y[12-13],,bp[39],,bp[139]
+ // Also known as EtherDisp.
+ //
+ _niaModifier |= (_yBus & 0xc) | (_system.EthernetController.EtherDisp());
+ break;
+
+ case YDispBrFunction.XwdDisp:
+ //
+ // Dispatch on X.9,,X.10 into INIA 10,,11
+ //
+ _niaModifier |= (_xBus & 0x60) >> 5;
+ break;
+
+ case YDispBrFunction.XHDisp:
+ //
+ // Dispatch on X.4,,X.0
+ //
+ _niaModifier |= ((_xBus & 0x8000) >> 15) | ((_xBus & 0x0800) >> 10);
+ break;
+
+ case YDispBrFunction.XLDisp:
+ //
+ // Dispatch on X.8,,X.15
+ //
+ _niaModifier |= (_xBus & 0x1) | ((_xBus & 0x80) >> 6);
+ break;
+
+ case YDispBrFunction.PgCrOvDisp:
+ //
+ // Dispatch on _pageCross,,ALU overflow bit into INIA 10,,11.
+ //
+ // See the HW ref, page 25.
+ // pageCross is the XOR of the carry out from the low byte of the ALU with af[2].
+ //
+ _niaModifier |= (_alu.PgCarry ^ (((int)instruction.aF & 0x1) == 1) ? 0x2 : 0x0) | (_alu.Overflow ? 0x1 : 0x0);
+ break;
+ }
+ break;
+
+ case FunctionSelectFY.IOOut:
+ switch ((YIOOutFunction)instruction.fY)
+ {
+ case YIOOutFunction.IOPOData:
+ if (Log.Enabled) Log.Write(LogComponent.CPControl, "IOPOData<- {0:x2}", (byte)_xBus);
+ WriteIOPData((byte)_xBus);
+ break;
+
+ case YIOOutFunction.IOPCtl:
+ WriteIOPCtl((byte)_xBus);
+ break;
+
+ case YIOOutFunction.KOData:
+ _system.ShugartController.SetKOData(_xBus);
+ break;
+
+ case YIOOutFunction.KCtl:
+ _system.ShugartController.SetKCtl(_xBus);
+ break;
+
+ case YIOOutFunction.EOData:
+ _system.EthernetController.EOData(_xBus);
+ break;
+
+ case YIOOutFunction.EICtl:
+ _system.EthernetController.EICtl(_xBus);
+ break;
+
+ case YIOOutFunction.DCtlFifo:
+ _system.DisplayController.SetDCtlFifo(_yBus);
+ break;
+
+ case YIOOutFunction.DCtl:
+ _system.DisplayController.SetDCtl(_xBus);
+ break;
+
+ case YIOOutFunction.DBorder:
+ _system.DisplayController.SetDBorder(_yBus);
+ break;
+
+ case YIOOutFunction.PCtl:
+ // Assume this is for the LSEP controller; docs are thin.
+ if (Log.Enabled) Log.Write(LogType.Error, LogComponent.CPExecution, "PCtl<-0x{0}, unimplemented.", _xBus);
+
+ if ((_xBus & 0x1) != 0)
+ {
+ // Per MoonCycle.mc,
+ // This wakes the LSEP/Refresh task (task 3).
+ WakeTask(TaskType.Refresh);
+ }
+ else
+ {
+ SleepTask(TaskType.Refresh);
+ }
+ break;
+
+ case YIOOutFunction.MCtl:
+ _system.MemoryController.SetMCtl(_yBus);
+ break;
+
+ case YIOOutFunction.EOCtl:
+ _system.EthernetController.EOCtl(_xBus);
+ break;
+
+ case YIOOutFunction.KCmd:
+ _system.ShugartController.SetKCmd(_xBus);
+ break;
+
+ case YIOOutFunction.POData:
+ throw new NotImplementedException("POData not implemented.");
+ break;
+
+ case YIOOutFunction.Invalid0:
+ case YIOOutFunction.Invalid1:
+ // Just a no-op
+ break;
+ }
+ break;
+ }
+
+ // SU reg write
+ if (instruction.SUWrite)
+ {
+ switch ((int)instruction.fSfZ)
+ {
+ case 0:
+ case 1:
+ _u[_stackP] = _yBus;
+ break;
+
+ case 2:
+ case 3:
+ if (altUAddr)
+ {
+ // U address is rA,,Y[12-15]
+ // (Y bus from *previous* instruction.)
+ _u[(instruction.rA << 4) | (lastYBus & 0xf)] = _yBus;
+ }
+ else
+ {
+ // U address is rA,,fZ
+ _u[instruction.UAddress] = _yBus;
+ }
+ break;
+ }
+ }
+
+ //
+ // pc16 gets inverted at the end of the cycle if fX or fZ is Cin<-pc16.
+ // (HW ref, section 2.3.7)
+ //
+ if (invertPc16)
+ {
+ _pc16 = !_pc16;
+ }
+
+ //
+ // Stack modifications occur at the end of the microinstruction, handle them here.
+ //
+ if (instruction.LoadStackP)
+ {
+ _stackP = (_yBus & 0xf);
+ if (Log.Enabled) Log.Write(LogComponent.CPStack, "Stackp loaded, now 0x{0:x}", _stackP);
+ }
+
+ //
+ // Handle pushes, pops, and stack pointer tests performed by performing multiple
+ // pops/pushes at the same time.
+ //
+ if (instruction.StackOperation)
+ {
+ switch (instruction.StackTest)
+ {
+ case StackTestType.None:
+ // Normal stack behavior.
+ if (instruction.Push)
+ {
+ if (_stackP == 0xf)
+ {
+ // Overflow
+ if (Log.Enabled) Log.Write(LogComponent.CPStack, "Stack overflow, raising error trap.");
+ SignalErrorTrap(ErrorTrap.StackOverUnderflow);
+ }
+
+ _stackP = (_stackP + 1) & 0xf;
+ if (Log.Enabled) Log.Write(LogComponent.CPStack, "Push: Stack pointer is now 0x{0:x}", _stackP);
+ }
+ else if (instruction.DoublePop)
+ {
+ // Test for 2 word underflow.
+ if (_stackP < 2)
+ {
+ // Underflow
+ if (Log.Enabled) Log.Write(LogComponent.CPStack, "Stack underflow, raising error trap.");
+ SignalErrorTrap(ErrorTrap.StackOverUnderflow);
+ }
+
+ // Still only decrement stackP by 1.
+ _stackP = (_stackP - 1) & 0xf;
+ if (Log.Enabled) Log.Write(LogComponent.CPStack, "Double Pop: Stack pointer is now 0x{0:x}", _stackP);
+ }
+ else if (instruction.Pop)
+ {
+ if (_stackP == 0)
+ {
+ // Underflow
+ if (Log.Enabled) Log.Write(LogComponent.CPStack, "Stack underflow, raising error trap.");
+ SignalErrorTrap(ErrorTrap.StackOverUnderflow);
+ }
+
+ _stackP = (_stackP - 1) & 0xf;
+ if (Log.Enabled) Log.Write(LogComponent.CPStack, "Pop: Stack pointer is now 0x{0:x}", _stackP);
+ }
+ break;
+
+ case StackTestType.Underflow:
+ // Test if a pop would cause an underflow
+ if (_stackP == 0x0)
+ {
+ if (Log.Enabled) Log.Write(LogComponent.CPStack, "Stack underflow test passed, raising error trap.");
+ SignalErrorTrap(ErrorTrap.StackOverUnderflow);
+ }
+ break;
+
+ case StackTestType.Overflow:
+ // Test if a push would cause an overflow
+ if (_stackP == 0xf)
+ {
+ if (Log.Enabled) Log.Write(LogComponent.CPStack, "Stack overflow test passed, raising error trap.");
+ SignalErrorTrap(ErrorTrap.StackOverUnderflow);
+ }
+ break;
+
+ case StackTestType.Underflow2:
+ // Test if stackP is 0 or 1
+ if (_stackP < 2)
+ {
+ if (Log.Enabled) Log.Write(LogComponent.CPStack, "Stack underflow (2) test passed, raising error trap.");
+ SignalErrorTrap(ErrorTrap.StackOverUnderflow);
+ }
+ break;
+ }
+ }
+
+ //
+ // Calculate NIA based on this instruction's INIA field and condition/dispatch bits from the last
+ // instruction.
+ //
+ int nia = instruction.INIA;
+
+ //
+ // If an error trap is pending we cancel any pending IBRefill trap.
+ //
+ if (_eKErr > 0 && niaModifierType == NiaModiferType.IBRefillTrap)
+ {
+ niaModifierType = NiaModiferType.Normal;
+ niaModifier = 0;
+ if (Log.Enabled) Log.Write(LogComponent.CPError, "Error trap pending, IBRefill trap aborted.");
+ }
+
+ switch (niaModifierType)
+ {
+ case NiaModiferType.Normal:
+ // Normal dispatch, just OR the bits in
+ nia |= niaModifier;
+ break;
+
+ case NiaModiferType.IBDispatch:
+ // IBDisp dispatch: bits [4-7] are replaced, bits [8-11] are or'd.
+ nia = (nia & 0xf0f) | niaModifier;
+
+ //
+ // Set the IBDispatch breakpoint flag so that debuggers
+ // can be notified of a new Mesa instruction.
+ //
+ _ibDispatch = true;
+ break;
+
+ case NiaModiferType.IBRefillTrap:
+ // Refill Trap: bits [0-3] are replaced.
+ nia = (nia & 0x0ff) | niaModifier;
+ break;
+ }
+
+ //
+ // Dispatch to the calculated NIA.
+ //
+ _tpc[(int)_currentTask] = nia;
+
+ //
+ // OR link bits into the next instruction's NIA (or save them) as necessary.
+ //
+ if (instruction.LinkAddress != -1)
+ {
+ // Modify the link register on a write (indicated by NIA[7] == 0)
+ if ((nia & 0x10) == 0)
+ {
+ //
+ // Save the low nibble only.
+ //
+ _link[instruction.LinkAddress] = nia & 0xf;
+
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPExecution, "Link[{0}] = {1:x}", instruction.LinkAddress, _link[instruction.LinkAddress]);
+ }
+ // Modify the NIA based on the link register (NIA[7] == 1)
+ else
+ {
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPExecution, "nia modifier ({0:x3}), Link[{1}] = {2:x}", _niaModifier, instruction.LinkAddress, _link[instruction.LinkAddress]);
+ //
+ // Or the link register in.
+ //
+ _niaModifier |= _link[instruction.LinkAddress];
+ if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.CPExecution, "nia modifier now {0:x3}", nia);
+ }
+ }
+
+ _cycle++;
+
+ if (_cycle > 3)
+ {
+ _cycle = 1;
+ TaskSwitch();
+ }
+ }
+ }
+
+ public void WakeTask(TaskType task)
+ {
+ _wakeup[(int)task] = true;
+
+ if (Log.Enabled) Log.Write(LogComponent.CPTask, "Task {0} set to wake.", task);
+ }
+
+ ///
+ /// Yes I know that "sleep" is an intransitive verb.
+ ///
+ ///
+ public void SleepTask(TaskType task)
+ {
+ _wakeup[(int)task] = false;
+
+ if (Log.Enabled) Log.Write(LogComponent.CPTask, "Task {0} set to sleep.", task);
+ }
+
+ ///
+ /// Invoked at the end of a click. If a task switch is necessary the proper task is selected and switched to.
+ ///
+ private void TaskSwitch()
+ {
+ //
+ // Move to the next click. This happens even while executing the Kernel task, though it
+ // causes no task switching in that case.
+ //
+ _click = (ClickType)(((int)_click + 1) % 5);
+
+ // if (Log.Enabled) Log.Write(LogComponent.CPTask, "Switch to click {0}", _click);
+
+ //
+ // If we are executing in the Kernel task and we aren't being asked to leave via ExitKernel
+ // then no task switching takes place.
+ //
+ if (_exitKernel || _currentTask != TaskType.Kernel)
+ {
+ if (_exitKernel)
+ {
+ // Remove the Kernel task wakeup signal.
+ SleepTask(TaskType.Kernel);
+ _exitKernel = false;
+ }
+
+ switch (_click)
+ {
+ case ClickType.Ethernet0:
+ case ClickType.Ethernet1:
+ DoTaskSwitch(TaskType.Ethernet);
+ break;
+
+ case ClickType.Disk:
+ DoTaskSwitch(TaskType.Disk);
+ break;
+
+ case ClickType.IOP:
+ DoTaskSwitch(TaskType.IOP);
+ break;
+
+ case ClickType.Display:
+ if (_system.DisplayController.DisplayOn)
+ {
+ DoTaskSwitch(TaskType.Display);
+ }
+ else
+ {
+ DoTaskSwitch(TaskType.Refresh);
+ }
+ break;
+ }
+
+ _exitKernel = false;
+ }
+
+ //
+ // If an emulator error trap occurred during some prior click and we're in the emulator
+ // task now, trap to location 0 when the click count reaches zero.
+ //
+ if (_emulatorErrorTrap && _currentTask == TaskType.Emulator)
+ {
+ _emulatorErrorTrapClickCount--;
+
+ if (_emulatorErrorTrapClickCount == 0)
+ {
+ _emulatorErrorTrap = false;
+ _tpc[(int)_currentTask] = 0;
+ if (Log.Enabled) Log.Write(LogComponent.CPError, "Taking trap to 0 for eKerr {0}", _eKErr);
+ }
+ }
+ }
+
+ private void DoTaskSwitch(TaskType newTask)
+ {
+ TaskType nextTask;
+ //
+ // If the Kernel has been awoken we switch to the Kernel task regardless of anything else.
+ //
+ if (WakeStatus(TaskType.Kernel))
+ {
+ nextTask = TaskType.Kernel;
+ if (Log.Enabled) Log.Write(LogComponent.CPTask, "Waking Kernel task.", _click);
+ }
+ else
+ {
+ //
+ // If there is a wakeup for the requested task then we switch to that task,
+ // otherwise we default to the Emulator task.
+ //
+ nextTask = WakeStatus(newTask) ? newTask : TaskType.Emulator;
+ }
+
+ if (nextTask == _currentTask)
+ {
+ // Nothing changed, nothing to do, early return.
+ // if (Log.Enabled) Log.Write(LogComponent.CPTask, "No task switch this click.");
+ return;
+ }
+
+ //
+ // Save the current task's NIA condition bits to the TC array. Only the 4 low bits are saved.
+ //
+ _tc[(int)_currentTask] = _niaModifier & 0xf;
+
+ //
+ // Restore the new tasks's NIA condition bits
+ //
+ _niaModifier = _tc[(int)nextTask];
+
+ //
+ // Switch to the new task.
+ //
+ _currentTask = nextTask;
+
+ if (Log.Enabled) Log.Write(LogComponent.CPTask, "Task switch to {0}", _currentTask);
+ }
+
+ private bool WakeStatus(TaskType task)
+ {
+ return _wakeup[(int)task];
+ }
+
+ private void SignalErrorTrap(ErrorTrap err)
+ {
+ if (err == ErrorTrap.ControlStoreParity)
+ {
+ // Not implemented, probably will never be...
+ throw new NotImplementedException("CS Parity errors not implemented.");
+ }
+
+ // Set the emulator-kernel error register.
+ // TODO: Smaller values have priority over larger.
+ if ((int)err < _eKErr || (_eKErr == 0 && !_emulatorErrorTrap))
+ {
+ _eKErr = (int)err;
+ }
+
+ //
+ // An error trap transfers control of the Emulator task
+ // to location 0; this will occur in c1 one or two emulator clicks in the future (including
+ // the current click) depending on the trap and the cycle the trap occurred in.
+ // The hardware requires the execution of one additional Emulator click before the trap.
+ // (hwref, pg. 33).
+ //
+ if (!_emulatorErrorTrap)
+ {
+ _emulatorErrorTrap = true;
+ switch (err)
+ {
+ case ErrorTrap.ControlStoreParity:
+ //
+ // "If the instruction read from microstore in c1 has bad parity, then the Kernel
+ // runs at location 0 in the next c1. If the parity error occurs in c2 or c3, then there
+ // is a one click delay before the Kernel executes at location 0 in c1.
+ //
+ _emulatorErrorTrapClickCount = _cycle == 1 ? 1 : 2;
+ break;
+
+ case ErrorTrap.EmulatorMemoryError:
+ // "The hardware requires the execution of one additional Emulator click between the c3 which
+ // errored and the trap at location 0."
+ _emulatorErrorTrapClickCount = 2;
+ break;
+
+ case ErrorTrap.StackOverUnderflow:
+ // "The hardware requires the execution of on additional Emulator click before the trap at location 0."
+ _emulatorErrorTrapClickCount = 2;
+ break;
+
+ case ErrorTrap.IBEmpty:
+ // "If the IB-Empty error occurs in c1, then control transfers to location 0 in the next Emulator c1.
+ // However if the error occurs in c2 or c3, the hardware requires the execution of one additional
+ // Emulator click before the trap at location 0."
+ _emulatorErrorTrapClickCount = _cycle == 1 ? 1 : 2;
+ break;
+ }
+ if (Log.Enabled) Log.Write(LogComponent.CPError, "Error trap {0} at address {1:x3}. Jumping to CS address 0 for task {2} in future c1.", err, _tpc[(int)_currentTask], _currentTask);
+ }
+ }
+
+ ///
+ /// Does the unique "decrement" of ibPtr -- 2, 3, 1, 0 (full, word, byte, empty)
+ ///
+ private void DecrementIBPtr()
+ {
+ _ibPtr = _nextIBPtr[(int)_ibPtr];
+ }
+
+ private enum ErrorTrap
+ {
+ ControlStoreParity = 0,
+ EmulatorMemoryError = 1,
+ StackOverUnderflow = 2,
+ IBEmpty = 3,
+ }
+
+ private enum NiaModiferType
+ {
+ Normal,
+ IBDispatch,
+ IBRefillTrap,
+ }
+
+ // Task/Temporary Program Counters
+ private int[] _tpc = new int[8];
+
+ // Task/Temporary Condition bits (NIA modifiers). This is only 4 bits.
+ private int[] _tc = new int[8];
+
+ // Task wakeups
+ private bool[] _wakeup = new bool[8];
+
+ // Current task
+ private TaskType _currentTask;
+
+ // Microcode store
+ private ulong[] _microcode = new ulong[4096];
+
+ // Microcode decode cache
+ private Microinstruction[] _microcodeCache = new Microinstruction[4096];
+
+ // 2901 ALU
+ private AM2901 _alu = new AM2901();
+
+ // RH registers, 8 bit
+ private byte[] _rh = new byte[16];
+
+ // Link registers, 4 bit
+ // NOTE: Link register:
+ // See section 2.5.4 of the HW ref;
+ // Link is addressed by fX and is written with the low nibble of NIAX when
+ // fX is in 0..7 and NIA[7] = 0;
+ // A Link register is or'd into the low nibble of INIA when fX is in 0..7 and
+ // NIA[7] = 1. If the preceding uinstruction does not specify a branch/dispatch,
+ // the Link register is loaded with a constant.
+ // However if the prior instruction does specify branch/dispatch, the value loaded
+ // depends on the outcome of the branch or dispatch.
+ private int[] _link = new int[8];
+
+ // U registers
+ private ushort[] _u = new ushort[256];
+
+ // Instruction buffer (IB)
+ private byte _ibFront;
+ private byte[] _ib = new byte[2];
+ private IBState _ibPtr;
+ private bool _ibEmptyCancel;
+
+ // Table of values for next ipPtr value when decrementing ibPtr.
+ private readonly IBState[] _nextIBPtr = { IBState.Empty, IBState.Empty, IBState.Word, IBState.Byte };
+
+ // Stack pointer, 4 bits
+ private int _stackP;
+
+ // pc16 register, 1 bit
+ private bool _pc16;
+
+ // Bus data
+ private ushort _xBus;
+ private ushort _yBus;
+
+ // NIA modifier for branch/dispatch
+ private int _niaModifier;
+ private NiaModiferType _niaModifierType;
+
+ // AltUAddress flag
+ private bool _altUAddr;
+
+ //
+ // Interrupt flags
+ //
+ private bool _mInt;
+
+ //
+ // Error state
+ //
+
+ //
+ // HWRef, section 2.5.5.2:
+ // The EKErr register, read onto X[8-9] with <-ErrnIBnStkp, names the type of error:
+ // 0 - control store parity error
+ // 1 - Emulator memory error
+ // 2 - stackPointer overflow or underflow
+ // 3 - IB-Empty error
+ // If, coincidentally, two or more error occur at the same time, smaller values of EKErr
+ // are reported. The error types are also accumulated until EKErr is reset: the minimum
+ // value is reported when EKErr is read.
+ // Cleared by ClrIntErr, which, as a side-effect, also resets any pending interrupts.
+ private int _eKErr;
+ private bool _emulatorErrorTrap;
+ private int _emulatorErrorTrapClickCount;
+
+ ///
+ /// Whether a PageCross branch occurred during the last MAR<- operation.
+ /// Cleared at the beginning of the next instruction, and used to indicate whether
+ /// an MDR<-, IBDisp, or AlwaysIBDisp should be canceled.
+ ///
+ private bool _marPageCrossBr;
+
+ //
+ // Cycle / Click / Round data
+ //
+ private int _cycle; // c1 ... c3
+ private ClickType _click; // 0 ... 4
+
+ //
+ // Whether to exit the Kernel task at the end of this click
+ //
+ private bool _exitKernel;
+
+ //
+ // Debugging flag: Indicates that an IBDispatch has occurred,
+ // allows handling Mesa (or other bytecode) instruction breakpoints.
+ //
+ private bool _ibDispatch;
+
+ //
+ // The D System we belong to
+ //
+ private DSystem _system;
+ }
+}
diff --git a/D/CP/CentralProcessorIO.cs b/D/CP/CentralProcessorIO.cs
new file mode 100644
index 0000000..8e7aaa2
--- /dev/null
+++ b/D/CP/CentralProcessorIO.cs
@@ -0,0 +1,712 @@
+/*
+ BSD 2-Clause License
+
+ Copyright Vulcan Inc. 2017-2018 and Living Computer Museum + Labs 2018
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+using D.IOP;
+using D.Logging;
+using System;
+
+namespace D.CP
+{
+ //
+ // From SysDefs.asm:
+ // Bits 0:5 - (IOPWait', SwTAddr', IOPattn, CPDmaMode, CPDmaIn)
+ // (in the usual Xerox reverse order)
+ //
+ [Flags]
+ public enum CPControlFlags
+
+ {
+ IOPWait_ = 0x80,
+ SwTAddr_ = 0x40,
+ IOPattn = 0x20,
+ CPDmaMode = 0x10,
+ CPDmaIn = 0x08,
+ }
+
+ //
+ // From IOP schematics, p 15-17:
+ //
+ public enum CPStatusFlags
+ {
+ CPAttn = 0x80,
+ EmuWake = 0x40,
+ IOPAttn_ = 0x20,
+ CPDmaMode_ = 0x10,
+ CPDmaIn_ = 0x08,
+ CPInIntReq_ = 0x04,
+ CPOutIntReq_ = 0x2,
+ CPDmaComplete_ = 0x1,
+ }
+
+ [Flags]
+ public enum IOPCtlFlags
+ {
+ EmuWake = 0x8,
+ CPAttn = 0x4,
+ WakeMode0 = 0x2,
+ WakeMode1 = 0x1,
+ }
+
+ [Flags]
+ public enum IOPStatusFlags
+ {
+ IOPAttn = 0x20,
+ EmuWake_ = 0x10,
+ CPAttn_ = 0x8,
+ WakeMode0_ = 0x4,
+ WakeMode1_ = 0x2,
+ IOPReq = 0x1,
+ }
+
+ ///
+ /// The Dandelion Central Processor, I/O implmentation.
+ /// This partial class implements the CP<->IOP communication channel,
+ /// and IOP microcode loading logic.
+ ///
+ public partial class CentralProcessor : IIOPDevice, IDMAInterface
+ {
+ //
+ // IOP port info
+ //
+ public int[] ReadPorts
+ {
+ get { return _readPorts; }
+ }
+
+ public int[] WritePorts
+ {
+ get { return _writePorts; }
+ }
+
+ public void WritePort(int port, byte value)
+ {
+ switch ((PortWriteRegister)port)
+ {
+ case PortWriteRegister.CPDataOut:
+ WriteCPInBuffer(value);
+ break;
+
+ case PortWriteRegister.CPControl:
+ WriteCPCtl(value);
+ break;
+
+ case PortWriteRegister.CPClrDmaComplete:
+ _cpDmaComplete_ = false;
+ if (Log.Enabled) Log.Write(LogComponent.IOPDMA, "CP DMA complete flag cleared.");
+ break;
+
+ case PortWriteRegister.CPCSa:
+ case PortWriteRegister.CPCSb:
+ case PortWriteRegister.CPCSc:
+ case PortWriteRegister.CPCSd:
+ case PortWriteRegister.CPCSe:
+ case PortWriteRegister.CPCSf: // CS microcode word, MSB ($F8) to LSB ($FD)
+ WriteIOPMicrocodeWord(port - 0xf8, (byte)~value);
+
+ if (port == 0xfd)
+ {
+ if (Log.Enabled) Log.Write(LogComponent.CPMicrocodeLoad, "CS word {0:x3} completed: {1:x12} {2}", _tpc[6], _microcode[_tpc[6]], new Microinstruction(_microcode[_tpc[6]]).Disassemble(-1));
+ }
+ break;
+
+ case PortWriteRegister.TPCHigh: // TPC high : TPCAddr[0:2],,TPCData[0:4]'
+ _tpcAddr = value >> 5;
+ _tpcTemp = ((~value & 0x1f) << 7);
+ if (Log.Enabled) Log.Write(LogComponent.CPTPCLoad, "TPC high written: TPC[{0}] ({1}) is now {2:x3}", _tpcAddr, (TaskType)_tpcAddr, _tpcTemp);
+ break;
+
+ case PortWriteRegister.TPCLow: // TPC low : don't care,,TPCData[5:11]'
+ _tpc[_tpcAddr] = _tpcTemp | (~value & 0x7f);
+ if (Log.Enabled) Log.Write(LogComponent.CPTPCLoad, "TPC low written: TPC[{0}] ({1}) is now {2:x3}", _tpcAddr, (TaskType)_tpcAddr, _tpc[_tpcAddr]);
+ break;
+
+ default:
+ throw new InvalidOperationException(String.Format("Unexpected write to port {0:x2}", port));
+ }
+ }
+
+ public byte ReadPort(int port)
+ {
+ byte value = 0;
+ switch ((PortReadRegister)port)
+ {
+ case PortReadRegister.CPDataIn:
+ value = ReadCPOutBuffer();
+ break;
+
+ case PortReadRegister.CPStatus:
+ value = ReadCPStatus();
+ break;
+
+ case PortReadRegister.CPCS0:
+ case PortReadRegister.CPCS1:
+ case PortReadRegister.CPCS2:
+ case PortReadRegister.CPCS3:
+ case PortReadRegister.CPCS4:
+ case PortReadRegister.CPCS5: // CS microcode word, MSB ($F8) to LSB ($FD)
+ value = ReadIOPMicrocodeWord(port - 0xf8);
+ break;
+
+ case PortReadRegister.CPCS6: // TPC high : TC[0:3],,TPCData[0:3]'
+ value = (byte)~((~_tc[_tpcAddr] << 4) | ((_tpc[_tpcAddr] & 0xf00) >> 8));
+ break;
+
+ case PortReadRegister.CPCS7: // TPC low : TPCData[4:11]'
+ value = (byte)(~_tpc[_tpcAddr]);
+ break;
+
+ default:
+ throw new InvalidOperationException(String.Format("Unexpected read from port {0:x2}", port));
+ }
+
+ if (Log.Enabled) Log.Write(LogComponent.CPControl, "CP port {0:x2}({1}) read {2:x2}", port, (PortReadRegister)port, value);
+
+ return value;
+ }
+
+ //
+ // IDMAInterface implementation
+ //
+ ///
+ /// DMA Request: device request to obtain a DMA cycle from the DMA controller
+ ///
+ public bool DRQ
+ {
+ get
+ {
+ if (_cpDmaMode) // DMA is enabled
+ {
+ if (_cpDmaIn)
+ {
+ return _outLatched;
+ }
+ else
+ {
+ return !_inLatched;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Writes a single byte to the device from the DMA controller
+ ///
+ ///
+ public void DMAWrite(byte value)
+ {
+ WriteCPInBuffer(value);
+ }
+
+ ///
+ /// Reads a single byte from the device to the DMA controller
+ ///
+ ///
+ public byte DMARead()
+ {
+ return ReadCPOutBuffer();
+ }
+
+ public void DMAComplete()
+ {
+ _cpDmaComplete_ = true;
+ if (Log.Enabled) Log.Write(LogComponent.IOPDMA, "CP DMA complete, flag set.");
+ }
+
+ private byte ReadCPOutBuffer()
+ {
+ if (!_outLatched)
+ {
+ if (Log.Enabled) Log.Write(LogType.Warning, LogComponent.CPControl, "CP data out not latched on IOP read.");
+ }
+
+ //
+ // Clear the output data latched flag.
+ //
+ _outLatched = false;
+
+ //
+ // Clear the CP->IOP interrupt flag (active low): the IOP has read the available data.
+ //
+ _cpInIntReq_ = true;
+
+ UpdateIOPTaskWakeup();
+
+ //
+ // Return the buffer data
+ //
+ return _cpInData;
+ }
+
+ private void WriteCPInBuffer(byte value)
+ {
+ if (Log.Enabled) Log.Write(LogComponent.CPControl, "CP data out write ({0:x2})", value);
+
+ if (_inLatched)
+ {
+ if (Log.Enabled) Log.Write(LogType.Warning, LogComponent.CPControl, "CP data out already latched on IOP write", value);
+ }
+
+ //
+ // Clear the IOP->CP interrupt (active low): The CP has yet to read the data provided by the IOP.
+ //
+ _cpOutIntReq_ = true;
+ _cpOutData = value;
+
+ //
+ // Let the CP know there's data available.
+ //
+ _inLatched = true;
+
+ UpdateIOPTaskWakeup();
+ }
+
+ ///
+ /// Writes one byte of the microcode word currently pointed to by
+ /// TPC[6].
+ ///
+ ///
+ ///
+ private void WriteIOPMicrocodeWord(int b, byte value)
+ {
+ //
+ // In true Xerox fashion, the 48 bits of the microcode word provided by the IOP
+ // are not in order from MSB to LSB or anything simple like that. Though most of them are.
+ // From SysDefs.asm:
+ //
+ // "; Write (all CSi are complemented values):
+ // CSa equ CSBase + 0; CS Byte a: rA[0:3],,rB[0:3]
+ // CSb equ CSBase + 1; CS Byte b: aS[0:2],,aF[0:2],,aD[0:1]
+ // CSc equ CSBase + 2; CS Byte c: EP,,CIN,,EnSU,,mem,,fS[0:3]
+ // CSd equ CSBase + 3; CS Byte d: fY[0:3], INIA[0:3]
+ // CSe equ CSBase + 4; CS Byte e: fX[0:3], INIA[4:7]
+ // CSf equ CSBase + 5; CS Byte f: fZ[0:3], INIA[8:11]"
+ //
+ // "value" is expected to already be complemented on call to WriteIOPMicrocodeWord.
+ //
+
+
+ // TPC register 6 is always used for IOP microcode writes.
+ ulong word = _microcode[_tpc[6]];
+ switch (b)
+ {
+ case 0:
+ word = (word & 0x00ffffffffff) | ((ulong)value << 40);
+ break;
+
+ case 1:
+ word = (word & 0xff00ffffffff) | ((ulong)value << 32);
+ break;
+
+ case 2:
+ word = (word & 0xffff00ffffff) | ((ulong)value << 24);
+ break;
+
+ case 3:
+ {
+ // FY[0:3], INIA[0:3]
+ ulong fy = ((ulong)value & 0xf0) >> 4;
+ ulong inia = ((ulong)value & 0xf);
+ word = (word & 0xfffffff0f0ff) | (fy << 16) | (inia << 8);
+ }
+ break;
+
+ case 4:
+ {
+ // FX[0:3], INIA[4:7]
+ ulong fx = ((ulong)value & 0xf0) >> 4;
+ ulong inia = ((ulong)value & 0xf);
+ word = (word & 0xffffff0fff0f) | (fx << 20) | (inia << 4);
+ }
+ break;
+
+ case 5:
+ {
+ // FZ[0:3], INIA[8:11]
+ ulong fz = ((ulong)value & 0xf0) >> 4;
+ ulong inia = ((ulong)value & 0xf);
+ word = (word & 0xffffffff0ff0) | (fz << 12) | inia;
+ }
+ break;
+
+ default:
+ throw new InvalidOperationException("Invalid byte number for microcode word.");
+ }
+
+ _microcode[_tpc[6]] = word;
+ _microcodeCache[_tpc[6]] = new Microinstruction(word);
+ }
+
+ ///
+ /// Reads one byte of the microcode word currently pointed to by
+ /// TPC[6].
+ ///
+ ///
+ ///
+ private byte ReadIOPMicrocodeWord(int b)
+ {
+ byte value = 0;
+
+ // TPC register 6 is always used for IOP microcode reads.
+ ulong word = _microcode[_tpc[6]];
+ switch (b)
+ {
+ case 0:
+ value = (byte)(_microcode[_tpc[6]] >> 40);
+ break;
+
+ case 1:
+ value = (byte)(_microcode[_tpc[6]] >> 32);
+ break;
+
+ case 2:
+ value = (byte)(_microcode[_tpc[6]] >> 24);
+ break;
+
+ case 3:
+ {
+ // FY[0:3], INIA[0:3]
+ value = (byte)(((_microcode[_tpc[6]] >> 12) & 0xf0) | ((_microcode[_tpc[6]] >> 8) & 0xf));
+ }
+ break;
+
+ case 4:
+ {
+ // FX[0:3], INIA[4:7]
+ value = (byte)(((_microcode[_tpc[6]] >> 16) & 0xf0) | ((_microcode[_tpc[6]] >> 4) & 0xf));
+ }
+ break;
+
+ case 5:
+ {
+ // FZ[0:3], INIA[8:11]
+ value = (byte)(((_microcode[_tpc[6]] >> 8) & 0xf0) | (_microcode[_tpc[6]] & 0xf));
+ }
+ break;
+
+ default:
+ throw new InvalidOperationException("Invalid byte number for microcode word.");
+ }
+
+ return value;
+ }
+
+ private void WriteCPCtl(byte value)
+ {
+ if (Log.Enabled) Log.Write(LogComponent.CPControl, "CP control write {0} ({1:x2})", (CPControlFlags)value, value);
+
+ bool oldIopWait = _iopWait_;
+ _iopWait_ = (value & (int)CPControlFlags.IOPWait_) == 0; // inverted sense
+ _swTAddr = (value & (int)CPControlFlags.SwTAddr_) == 0; // ditto
+ _iopAttn = (value & (int)CPControlFlags.IOPattn) != 0;
+ _cpDmaMode = (value & (int)CPControlFlags.CPDmaMode) != 0;
+ _cpDmaIn = (value & (int)CPControlFlags.CPDmaIn) != 0;
+
+ if (oldIopWait != _iopWait_)
+ {
+ //
+ // Raising IOPWait causes a Kernel wakeup to be requested so that the Kernel task
+ // will run when the CP is allowed to run again.
+ //
+ for(int i=0;i<7;i++)
+ {
+ SleepTask((TaskType)i);
+ }
+
+ WakeTask(TaskType.Kernel);
+ _currentTask = TaskType.Kernel;
+
+ //
+ // Reset any error status
+ //
+ _emulatorErrorTrap = false;
+ _emulatorErrorTrapClickCount = 0;
+ }
+ }
+
+ private byte ReadCPStatus()
+ {
+ return (byte)
+ ((_cpDmaComplete_ ? CPStatusFlags.CPDmaComplete_ : 0) |
+ (!_cpOutIntReq_ ? CPStatusFlags.CPOutIntReq_ : 0) |
+ (!_cpInIntReq_ ? CPStatusFlags.CPInIntReq_ : 0) |
+ (!_cpDmaIn ? CPStatusFlags.CPDmaIn_ : 0) |
+ (!_cpDmaMode ? CPStatusFlags.CPDmaMode_ : 0) |
+ (_emuWake ? CPStatusFlags.EmuWake : 0) |
+ (!_cpAttn ? CPStatusFlags.CPAttn : 0));
+ }
+
+ private void WriteIOPCtl(byte value)
+ {
+ if (Log.Enabled) Log.Write(LogComponent.CPControl, "IOPCtl<- {0} ({1:x2})", (IOPCtlFlags)value, value);
+
+ _wakeMode1 = (value & (int)IOPCtlFlags.WakeMode1) != 0;
+ _wakeMode0 = (value & (int)IOPCtlFlags.WakeMode0) != 0;
+ _cpAttn = (value & (int)IOPCtlFlags.CPAttn) != 0;
+ _emuWake = (value & (int)IOPCtlFlags.EmuWake) != 0;
+
+ _wakeMode = (IOPTaskWakeMode)((_wakeMode0 ? 0x2 : 0x0) | (_wakeMode1 ? 0x1 : 0x0));
+ if (Log.Enabled) Log.Write(LogComponent.CPControl, "IOP Wake mode is {0}", _wakeMode);
+
+ // See if the wake status of the IOP task needs to change.
+ UpdateIOPTaskWakeup();
+ }
+
+ private byte ReadIOPStatus()
+ {
+ return (byte)
+ ((_iopReq ? IOPStatusFlags.IOPReq : 0) |
+ (!_wakeMode1 ? IOPStatusFlags.WakeMode1_ : 0) |
+ (!_wakeMode0 ? IOPStatusFlags.WakeMode0_ : 0) |
+ (!_cpAttn ? IOPStatusFlags.CPAttn_ : 0) |
+ (!_emuWake ? IOPStatusFlags.EmuWake_ : 0) |
+ (_iopAttn ? IOPStatusFlags.IOPAttn : 0));
+ }
+
+ private byte ReadIOPData()
+ {
+ if (!_inLatched)
+ {
+ if (Log.Enabled) Log.Write(LogType.Warning, LogComponent.CPControl, "CP data not latched on <-IOPData.");
+ }
+
+ //
+ // Clear the IOP request flag
+ //
+ _inLatched = false;
+
+ //
+ // Raise the IOP->CP flag (active low): the CP has read the available data.
+ //
+ _cpOutIntReq_ = false;
+
+ UpdateIOPTaskWakeup();
+
+ return _cpOutData;
+ }
+
+ private void WriteIOPData(byte value)
+ {
+ if (_outLatched)
+ {
+ if (Log.Enabled) Log.Write(LogType.Warning, LogComponent.CPControl, "CP data already latched on IOPOData<-");
+ }
+
+ //
+ // Latch the output data
+ //
+ _outLatched = true;
+
+ //
+ // Raise the CP->IOP interrupt flag (active low): there is data available for the IOP to read.
+ //
+ _cpInIntReq_ = false;
+
+ //
+ // Fill the CP->IOP buffer
+ //
+ _cpInData = value;
+
+ UpdateIOPTaskWakeup();
+ }
+
+ private void UpdateIOPTaskWakeup()
+ {
+ //
+ // Wake or sleep the IOP task as appropriate based on the current wake mode
+ // and the status of the I/O channel.
+ //
+ switch (_wakeMode)
+ {
+ case IOPTaskWakeMode.Always:
+ //
+ // Like the label says, we wake up the IOP task unconditionally.
+ //
+ _iopReq = true;
+ WakeTask(TaskType.IOP);
+ break;
+
+ case IOPTaskWakeMode.Input:
+ //
+ // If there's input waiting, wake the IOP task.
+ //
+ if (_inLatched)
+ {
+ _iopReq = true;
+ WakeTask(TaskType.IOP);
+ }
+ else
+ {
+ _iopReq = false;
+ SleepTask(TaskType.IOP);
+ }
+ break;
+
+ case IOPTaskWakeMode.Output:
+ //
+ // If the output buffer is currently empty, wake the IOP task.
+ //
+ if (!_outLatched)
+ {
+ _iopReq = true;
+ WakeTask(TaskType.IOP);
+ }
+ else
+ {
+ _iopReq = false;
+ SleepTask(TaskType.IOP);
+ }
+ break;
+
+ case IOPTaskWakeMode.Disabled:
+ _iopReq = false;
+ SleepTask(TaskType.IOP);
+ break;
+ }
+ }
+
+ private enum PortReadRegister
+ {
+ CPDataIn = 0xeb,
+ CPStatus = 0xec,
+ CPCS0 = 0xf8,
+ CPCS1 = 0xf9,
+ CPCS2 = 0xfa,
+ CPCS3 = 0xfb,
+ CPCS4 = 0xfc,
+ CPCS5 = 0xfd,
+ CPCS6 = 0xfe,
+ CPCS7 = 0xff,
+ }
+
+ private enum PortWriteRegister
+ {
+ CPDataOut = 0xeb,
+ CPControl = 0xec,
+ CPClrDmaComplete = 0xee,
+ CPCSa = 0xf8,
+ CPCSb = 0xf9,
+ CPCSc = 0xfa,
+ CPCSd = 0xfb,
+ CPCSe = 0xfc,
+ CPCSf = 0xfd,
+ TPCHigh = 0xfe,
+ TPCLow = 0xff,
+ }
+
+
+ // From the IOP schematic:
+ // - 00 = Disabled(no wakeups)
+ // - 01 = Input(wakeup when Input from IOP is available)
+ // - 10 = Output(wakeup when IOP is ready for data from CP)
+ // - 11 = Always wake up
+ private enum IOPTaskWakeMode
+ {
+ Disabled = 0,
+ Input,
+ Output,
+ Always,
+ }
+
+ //
+ // IOP port data
+ //
+ private readonly int[] _readPorts = new int[]
+ {
+ (int)PortReadRegister.CPDataIn, // CP data in
+ (int)PortReadRegister.CPStatus, // CP port status
+ (int)PortReadRegister.CPCS0, // control store word, MSB
+ (int)PortReadRegister.CPCS1,
+ (int)PortReadRegister.CPCS2,
+ (int)PortReadRegister.CPCS3,
+ (int)PortReadRegister.CPCS4,
+ (int)PortReadRegister.CPCS5, // control store word, LSB
+ (int)PortReadRegister.CPCS6, // TPC high
+ (int)PortReadRegister.CPCS7, // low
+ };
+
+ private readonly int[] _writePorts = new int[]
+ {
+ (int)PortWriteRegister.CPDataOut,
+ (int)PortWriteRegister.CPControl,
+ (int)PortWriteRegister.CPClrDmaComplete,
+ (int)PortWriteRegister.CPCSa, // control store word, MSB
+ (int)PortWriteRegister.CPCSb,
+ (int)PortWriteRegister.CPCSc,
+ (int)PortWriteRegister.CPCSd,
+ (int)PortWriteRegister.CPCSe,
+ (int)PortWriteRegister.CPCSf, // control store word, LSB
+ (int)PortWriteRegister.TPCHigh,
+ (int)PortWriteRegister.TPCLow,
+ };
+
+ //
+ // Control data, IOP
+ //
+ private bool _cpDmaComplete_;
+ private bool _iopWait_; // Waiting for IOP to wake us
+ private bool _swTAddr;
+ private bool _iopAttn;
+ private bool _cpDmaMode;
+ private bool _cpDmaIn;
+
+ //
+ // Control data, CP
+ //
+ private bool _wakeMode1;
+ private bool _wakeMode0;
+ private bool _cpAttn;
+ private bool _emuWake;
+ private IOPTaskWakeMode _wakeMode;
+
+ //
+ // Status data
+ //
+ private bool _cpOutIntReq_;
+ private bool _cpInIntReq_;
+ private bool _outLatched; // Data from CP->IOP latched
+ private bool _inLatched; // Data from IOP->CP latched
+ private bool _iopReq;
+
+ //
+ // CP<->IOP data buffers
+ //
+ private byte _cpOutData; // OUT from IOP (CP reads)
+ private byte _cpInData; // IN from CP (IOP reads)
+
+ // Used as TPC address when IOP is writing control store or modifying TPC values.
+ private int _tpcAddr;
+
+ // Temporary used when loading TPC values; stores high bits of new TPC address.
+ private int _tpcTemp;
+ }
+}
diff --git a/D/CP/MacroInstruction.cs b/D/CP/MacroInstruction.cs
new file mode 100644
index 0000000..1fce3d3
--- /dev/null
+++ b/D/CP/MacroInstruction.cs
@@ -0,0 +1,641 @@
+/*
+ BSD 2-Clause License
+
+ Copyright Vulcan Inc. 2017-2018 and Living Computer Museum + Labs 2018
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+namespace D.CP
+{
+ public enum MacroType
+ {
+ Mesa,
+ Lisp,
+ }
+
+ public enum MacroOperand
+ {
+ None,
+ Byte,
+ SignedByte,
+ Pair,
+ TwoByte,
+ Word,
+ ThreeByte,
+ }
+ ///
+ /// Provides facilities for interpreting Mesa bytecodes
+ ///
+ public struct MacroInstruction
+ {
+ private MacroInstruction(byte opcode, string mnemonic, MacroOperand operand)
+ {
+ _mnemonic = mnemonic;
+ _operand = operand;
+ }
+
+ public string Mnemonic
+ {
+ get { return _mnemonic; }
+ }
+
+ public MacroOperand Operand
+ {
+ get { return _operand; }
+ }
+
+ public static MacroInstruction GetInstruction(MacroType type, byte opcode)
+ {
+ MacroInstruction inst = Invalid;
+ switch(type)
+ {
+ case MacroType.Mesa:
+ inst = _mesaInstructionTable[opcode];
+ break;
+
+ case MacroType.Lisp:
+ inst = _lispInstructionTable[opcode];
+ break;
+ }
+
+ return inst;
+ }
+
+ private string _mnemonic;
+ private MacroOperand _operand;
+
+ private static MacroInstruction[] _mesaInstructionTable =
+ {
+ Invalid,
+ new MacroInstruction(0x01, "LL0", MacroOperand.None),
+ new MacroInstruction(0x02, "LL1", MacroOperand.None),
+ new MacroInstruction(0x03, "LL2", MacroOperand.None),
+ new MacroInstruction(0x04, "LL3", MacroOperand.None),
+ new MacroInstruction(0x05, "LL4", MacroOperand.None),
+ new MacroInstruction(0x06, "LL5", MacroOperand.None),
+ new MacroInstruction(0x07, "LL6", MacroOperand.None),
+ new MacroInstruction(0x08, "LL7", MacroOperand.None),
+ new MacroInstruction(0x09, "LL8", MacroOperand.None),
+ new MacroInstruction(0x0a, "LL9", MacroOperand.None),
+ new MacroInstruction(0x0b, "LL10", MacroOperand.None),
+ new MacroInstruction(0x0c, "LL11", MacroOperand.None),
+ new MacroInstruction(0x0d, "LLB", MacroOperand.Byte),
+ new MacroInstruction(0x0e, "LLD0", MacroOperand.None),
+ new MacroInstruction(0x0f, "LLD1", MacroOperand.None),
+
+ new MacroInstruction(0x10, "LLD2", MacroOperand.None),
+ new MacroInstruction(0x11, "LLD3", MacroOperand.None),
+ new MacroInstruction(0x12, "LLD4", MacroOperand.None),
+ new MacroInstruction(0x13, "LLD5", MacroOperand.None),
+ new MacroInstruction(0x14, "LLD6", MacroOperand.None),
+ new MacroInstruction(0x15, "LLD7", MacroOperand.None),
+ new MacroInstruction(0x16, "LLD8", MacroOperand.None),
+ new MacroInstruction(0x17, "LLD10", MacroOperand.None),
+ new MacroInstruction(0x18, "LLDB", MacroOperand.Byte),
+ new MacroInstruction(0x19, "SL0", MacroOperand.None),
+ new MacroInstruction(0x1a, "SL1", MacroOperand.None),
+ new MacroInstruction(0x1b, "SL2", MacroOperand.None),
+ new MacroInstruction(0x1c, "SL3", MacroOperand.None),
+ new MacroInstruction(0x1d, "SL4", MacroOperand.None),
+ new MacroInstruction(0x1e, "SL5", MacroOperand.None),
+ new MacroInstruction(0x1f, "SL6", MacroOperand.None),
+
+ new MacroInstruction(0x20, "SL7", MacroOperand.None),
+ new MacroInstruction(0x21, "SL8", MacroOperand.None),
+ new MacroInstruction(0x22, "SL9", MacroOperand.None),
+ new MacroInstruction(0x23, "SL10", MacroOperand.None),
+ new MacroInstruction(0x24, "SLB", MacroOperand.Byte),
+ new MacroInstruction(0x25, "SLD0", MacroOperand.None),
+ new MacroInstruction(0x26, "SLD1", MacroOperand.None),
+ new MacroInstruction(0x27, "SLD2", MacroOperand.None),
+ new MacroInstruction(0x28, "SLD3", MacroOperand.None),
+ new MacroInstruction(0x29, "SLD4", MacroOperand.None),
+ new MacroInstruction(0x2a, "SLD5", MacroOperand.None),
+ new MacroInstruction(0x2b, "SLD6", MacroOperand.None),
+ new MacroInstruction(0x2c, "SLD8", MacroOperand.None),
+ new MacroInstruction(0x2d, "PL0", MacroOperand.None),
+ new MacroInstruction(0x2e, "PL1", MacroOperand.None),
+ new MacroInstruction(0x2f, "PL2", MacroOperand.None),
+
+ new MacroInstruction(0x30, "PL3", MacroOperand.None),
+ new MacroInstruction(0x31, "PLB", MacroOperand.Byte),
+ new MacroInstruction(0x32, "PLD0", MacroOperand.None),
+ new MacroInstruction(0x33, "PLDB", MacroOperand.Byte),
+ new MacroInstruction(0x34, "LG0", MacroOperand.None),
+ new MacroInstruction(0x35, "LG1", MacroOperand.None),
+ new MacroInstruction(0x36, "LG2", MacroOperand.None),
+ new MacroInstruction(0x37, "LGB", MacroOperand.Byte),
+ new MacroInstruction(0x38, "LGD0", MacroOperand.None),
+ new MacroInstruction(0x39, "LGD2", MacroOperand.None),
+ new MacroInstruction(0x3a, "LGDB", MacroOperand.Byte),
+ new MacroInstruction(0x3b, "SGB", MacroOperand.Byte),
+ new MacroInstruction(0x3c, "BNDCK", MacroOperand.None),
+ new MacroInstruction(0x3d, "BRK", MacroOperand.None),
+ Invalid,
+ new MacroInstruction(0x3f, "STC", MacroOperand.None),
+
+ new MacroInstruction(0x40, "R0", MacroOperand.None),
+ new MacroInstruction(0x41, "R1", MacroOperand.None),
+ new MacroInstruction(0x42, "RB", MacroOperand.Byte),
+ new MacroInstruction(0x43, "RL0", MacroOperand.None),
+ new MacroInstruction(0x44, "RLB", MacroOperand.Byte),
+ new MacroInstruction(0x45, "RD0", MacroOperand.None),
+ new MacroInstruction(0x46, "RDB", MacroOperand.None),
+ new MacroInstruction(0x47, "RDL0", MacroOperand.None),
+ new MacroInstruction(0x48, "RDLB", MacroOperand.Byte),
+ new MacroInstruction(0x49, "W0", MacroOperand.None),
+ new MacroInstruction(0x4a, "WB", MacroOperand.Byte),
+ new MacroInstruction(0x4b, "PSB", MacroOperand.Byte),
+ new MacroInstruction(0x4c, "WLB", MacroOperand.Byte),
+ new MacroInstruction(0x4d, "PSLB", MacroOperand.Byte),
+ new MacroInstruction(0x4e, "WDB", MacroOperand.Byte),
+ new MacroInstruction(0x4f, "PSD0", MacroOperand.None),
+
+ new MacroInstruction(0x50, "PSDB", MacroOperand.Byte),
+ new MacroInstruction(0x51, "WDLB", MacroOperand.Byte),
+ new MacroInstruction(0x52, "PSDLB", MacroOperand.Byte),
+ new MacroInstruction(0x53, "RLI00", MacroOperand.None),
+ new MacroInstruction(0x54, "RLI01", MacroOperand.None),
+ new MacroInstruction(0x55, "RLI02", MacroOperand.None),
+ new MacroInstruction(0x56, "RLI03", MacroOperand.None),
+ new MacroInstruction(0x57, "RLIP", MacroOperand.Pair),
+ new MacroInstruction(0x58, "RLILP", MacroOperand.Pair),
+ new MacroInstruction(0x59, "RLDI00", MacroOperand.None),
+ new MacroInstruction(0x5a, "RLDIP", MacroOperand.Pair),
+ new MacroInstruction(0x5b, "RLDILP", MacroOperand.Pair),
+ new MacroInstruction(0x5c, "RGIP", MacroOperand.Pair),
+ new MacroInstruction(0x5d, "RGILP", MacroOperand.Pair),
+ new MacroInstruction(0x5e, "WLIP", MacroOperand.Pair),
+ new MacroInstruction(0x5f, "WLILP", MacroOperand.Pair),
+
+ new MacroInstruction(0x60, "WLDILP", MacroOperand.Pair),
+ new MacroInstruction(0x61, "RS", MacroOperand.None),
+ new MacroInstruction(0x62, "RLS", MacroOperand.None),
+ new MacroInstruction(0x63, "WS", MacroOperand.None),
+ new MacroInstruction(0x64, "WLS", MacroOperand.None),
+ new MacroInstruction(0x65, "R0F", MacroOperand.Byte),
+ new MacroInstruction(0x66, "RF", MacroOperand.TwoByte),
+ new MacroInstruction(0x67, "RL0F", MacroOperand.Byte),
+ new MacroInstruction(0x68, "RLF", MacroOperand.TwoByte),
+ new MacroInstruction(0x69, "RLFS", MacroOperand.None),
+ new MacroInstruction(0x6a, "RLIPF", MacroOperand.Word),
+ new MacroInstruction(0x6b, "RLILPF", MacroOperand.Word),
+ new MacroInstruction(0x6c, "WOF", MacroOperand.None),
+ new MacroInstruction(0x6d, "WF", MacroOperand.TwoByte),
+ new MacroInstruction(0x6e, "PSF", MacroOperand.TwoByte),
+ new MacroInstruction(0x6f, "PS0F", MacroOperand.None),
+
+ new MacroInstruction(0x70, "WS0F", MacroOperand.Byte),
+ new MacroInstruction(0x71, "WL0F", MacroOperand.Byte),
+ new MacroInstruction(0x72, "WLF", MacroOperand.TwoByte),
+ new MacroInstruction(0x73, "PSLF", MacroOperand.TwoByte),
+ new MacroInstruction(0x74, "WLFS", MacroOperand.Byte),
+ new MacroInstruction(0x75, "SLDB", MacroOperand.Byte),
+ new MacroInstruction(0x76, "SGDB", MacroOperand.Byte),
+ new MacroInstruction(0x77, "LLKB", MacroOperand.Byte),
+ new MacroInstruction(0x78, "RKIB", MacroOperand.Byte),
+ new MacroInstruction(0x79, "RKDIB", MacroOperand.Byte),
+ new MacroInstruction(0x7a, "LKB", MacroOperand.Byte),
+ new MacroInstruction(0x7b, "SHIFT", MacroOperand.None),
+ new MacroInstruction(0x7c, "SHIFTSB", MacroOperand.SignedByte),
+ new MacroInstruction(0x7d, "MBP", MacroOperand.Pair),
+ new MacroInstruction(0x7e, "RBP", MacroOperand.Pair),
+ new MacroInstruction(0x7f, "WBP", MacroOperand.Pair),
+
+ new MacroInstruction(0x80, "CATCH", MacroOperand.Byte),
+ new MacroInstruction(0x81, "J2", MacroOperand.None),
+ new MacroInstruction(0x82, "J3", MacroOperand.None),
+ new MacroInstruction(0x83, "J4", MacroOperand.None),
+ new MacroInstruction(0x84, "J5", MacroOperand.None),
+ new MacroInstruction(0x85, "J6", MacroOperand.None),
+ new MacroInstruction(0x86, "J7", MacroOperand.None),
+ new MacroInstruction(0x87, "J8", MacroOperand.None),
+ new MacroInstruction(0x88, "JB", MacroOperand.Byte),
+ new MacroInstruction(0x89, "JW", MacroOperand.Word),
+ new MacroInstruction(0x8a, "JEP", MacroOperand.Pair),
+ new MacroInstruction(0x8b, "JEB", MacroOperand.Byte),
+ new MacroInstruction(0x8c, "JEBB", MacroOperand.TwoByte),
+ new MacroInstruction(0x8d, "JNEP", MacroOperand.Pair),
+ new MacroInstruction(0x8e, "JNEB", MacroOperand.Byte),
+ new MacroInstruction(0x8f, "JNEBB", MacroOperand.TwoByte),
+
+ new MacroInstruction(0x90, "JLB", MacroOperand.Byte),
+ new MacroInstruction(0x91, "JGB", MacroOperand.Byte),
+ new MacroInstruction(0x92, "JGEB", MacroOperand.Byte),
+ new MacroInstruction(0x93, "JLEB", MacroOperand.Byte),
+ new MacroInstruction(0x94, "JULB", MacroOperand.Byte),
+ new MacroInstruction(0x95, "JUGB", MacroOperand.Byte),
+ new MacroInstruction(0x96, "JUGEB", MacroOperand.Byte),
+ new MacroInstruction(0x97, "JULEB", MacroOperand.Byte),
+ new MacroInstruction(0x98, "JZ3", MacroOperand.None),
+ new MacroInstruction(0x99, "JZ4", MacroOperand.None),
+ new MacroInstruction(0x9a, "JZB", MacroOperand.Byte),
+ new MacroInstruction(0x9b, "JNZ3", MacroOperand.None),
+ new MacroInstruction(0x9c, "JNZ4", MacroOperand.None),
+ new MacroInstruction(0x9d, "JNZB", MacroOperand.Byte),
+ new MacroInstruction(0x9e, "JDEB", MacroOperand.Byte),
+ new MacroInstruction(0x9f, "JDNEB", MacroOperand.Byte),
+
+ new MacroInstruction(0xa0, "JIB", MacroOperand.Byte),
+ new MacroInstruction(0xa1, "JIW", MacroOperand.Word),
+ new MacroInstruction(0xa2, "REC", MacroOperand.None),
+ new MacroInstruction(0xa3, "REC2", MacroOperand.None),
+ new MacroInstruction(0xa4, "DIS", MacroOperand.None),
+ new MacroInstruction(0xa5, "DIS2", MacroOperand.None),
+ new MacroInstruction(0xa6, "EXCH", MacroOperand.None),
+ new MacroInstruction(0xa7, "DEXCH", MacroOperand.None),
+ new MacroInstruction(0xa8, "DUP", MacroOperand.None),
+ new MacroInstruction(0xa9, "DDUP", MacroOperand.None),
+ new MacroInstruction(0xaa, "EXDIS", MacroOperand.None),
+ new MacroInstruction(0xab, "NEG", MacroOperand.None),
+ new MacroInstruction(0xac, "INC", MacroOperand.None),
+ new MacroInstruction(0xad, "DEC", MacroOperand.None),
+ new MacroInstruction(0xae, "DINC", MacroOperand.None),
+ new MacroInstruction(0xaf, "DBL", MacroOperand.None),
+
+ new MacroInstruction(0xb0, "DDBL", MacroOperand.None),
+ new MacroInstruction(0xb1, "TRPL", MacroOperand.None),
+ new MacroInstruction(0xb2, "AND", MacroOperand.None),
+ new MacroInstruction(0xb3, "IOR", MacroOperand.None),
+ new MacroInstruction(0xb4, "ADDSB", MacroOperand.SignedByte),
+ new MacroInstruction(0xb5, "ADD", MacroOperand.None),
+ new MacroInstruction(0xb6, "SUB", MacroOperand.None),
+ new MacroInstruction(0xb7, "DADD", MacroOperand.None),
+ new MacroInstruction(0xb8, "DSUB", MacroOperand.None),
+ new MacroInstruction(0xb9, "ADC", MacroOperand.None),
+ new MacroInstruction(0xba, "ACD", MacroOperand.None),
+ new MacroInstruction(0xbb, "AL0IB", MacroOperand.Byte),
+ new MacroInstruction(0xbc, "MUL", MacroOperand.None),
+ new MacroInstruction(0xbd, "DCMP", MacroOperand.None),
+ new MacroInstruction(0xbe, "UDCMP", MacroOperand.None),
+ Invalid,
+
+ new MacroInstruction(0xc0, "LI0", MacroOperand.None),
+ new MacroInstruction(0xc1, "LI1", MacroOperand.None),
+ new MacroInstruction(0xc2, "LI2", MacroOperand.None),
+ new MacroInstruction(0xc3, "LI3", MacroOperand.None),
+ new MacroInstruction(0xc4, "LI4", MacroOperand.None),
+ new MacroInstruction(0xc5, "LI5", MacroOperand.None),
+ new MacroInstruction(0xc6, "LI6", MacroOperand.None),
+ new MacroInstruction(0xc7, "LI7", MacroOperand.None),
+ new MacroInstruction(0xc8, "LI8", MacroOperand.None),
+ new MacroInstruction(0xc9, "LI9", MacroOperand.None),
+ new MacroInstruction(0xca, "LI10", MacroOperand.None),
+ new MacroInstruction(0xcb, "LIN1", MacroOperand.None),
+ new MacroInstruction(0xcc, "LINI", MacroOperand.None),
+ new MacroInstruction(0xcd, "LIB", MacroOperand.Byte),
+ new MacroInstruction(0xce, "LIW", MacroOperand.Word),
+ new MacroInstruction(0xcf, "LINB", MacroOperand.Byte),
+
+ new MacroInstruction(0xd0, "LIHB", MacroOperand.Byte),
+ new MacroInstruction(0xd1, "LID0", MacroOperand.None),
+ new MacroInstruction(0xd2, "LA0", MacroOperand.None),
+ new MacroInstruction(0xd3, "LA1", MacroOperand.None),
+ new MacroInstruction(0xd4, "LA2", MacroOperand.None),
+ new MacroInstruction(0xd5, "LA3", MacroOperand.None),
+ new MacroInstruction(0xd6, "LA6", MacroOperand.None),
+ new MacroInstruction(0xd7, "LA8", MacroOperand.None),
+ new MacroInstruction(0xd8, "LAB", MacroOperand.Byte),
+ new MacroInstruction(0xd9, "LAW", MacroOperand.Word),
+ new MacroInstruction(0xda, "GA0", MacroOperand.None),
+ new MacroInstruction(0xdb, "GA1", MacroOperand.None),
+ new MacroInstruction(0xdc, "GAB", MacroOperand.Byte),
+ new MacroInstruction(0xdd, "GAW", MacroOperand.Word),
+ Invalid,
+ new MacroInstruction(0xdf, "EFC0", MacroOperand.None),
+
+ new MacroInstruction(0xe0, "EFC1", MacroOperand.None),
+ new MacroInstruction(0xe1, "EFC2", MacroOperand.None),
+ new MacroInstruction(0xe2, "EFC3", MacroOperand.None),
+ new MacroInstruction(0xe3, "EFC4", MacroOperand.None),
+ new MacroInstruction(0xe4, "EFC5", MacroOperand.None),
+ new MacroInstruction(0xe5, "EFC6", MacroOperand.None),
+ new MacroInstruction(0xe6, "EFC7", MacroOperand.None),
+ new MacroInstruction(0xe7, "EFC8", MacroOperand.None),
+ new MacroInstruction(0xe8, "EFC9", MacroOperand.None),
+ new MacroInstruction(0xe9, "EFC10", MacroOperand.None),
+ new MacroInstruction(0xea, "EFC11", MacroOperand.None),
+ new MacroInstruction(0xeb, "EFC12", MacroOperand.None),
+ new MacroInstruction(0xec, "EFCB", MacroOperand.Byte),
+ new MacroInstruction(0xed, "LFC", MacroOperand.Word),
+ new MacroInstruction(0xee, "SFC", MacroOperand.None),
+ new MacroInstruction(0xef, "RET", MacroOperand.None),
+
+ new MacroInstruction(0xf0, "KFCB", MacroOperand.Byte),
+ new MacroInstruction(0xf1, "ME", MacroOperand.None),
+ new MacroInstruction(0xf2, "MX", MacroOperand.None),
+ new MacroInstruction(0xf3, "BLT", MacroOperand.None),
+ new MacroInstruction(0xf4, "BLTL", MacroOperand.None),
+ new MacroInstruction(0xf5, "BLTC", MacroOperand.None),
+ new MacroInstruction(0xf6, "BLTCL", MacroOperand.None),
+ new MacroInstruction(0xf7, "LP", MacroOperand.None),
+ new MacroInstruction(0xf8, "ESC", MacroOperand.Byte),
+ new MacroInstruction(0xf9, "ESCL", MacroOperand.Word),
+ new MacroInstruction(0xfa, "LGA0", MacroOperand.None),
+ new MacroInstruction(0xfb, "LGAB", MacroOperand.Byte),
+ new MacroInstruction(0xfc, "LGAW", MacroOperand.Word),
+ new MacroInstruction(0xfd, "DESC", MacroOperand.None),
+ Invalid,
+ Invalid,
+ };
+
+ private static MacroInstruction[] _lispInstructionTable =
+ {
+ Invalid,
+ new MacroInstruction(0x01, "CAR", MacroOperand.None),
+ new MacroInstruction(0x02, "CDR", MacroOperand.None),
+ new MacroInstruction(0x03, "LISTP", MacroOperand.None),
+ new MacroInstruction(0x04, "NTYPX", MacroOperand.None),
+ new MacroInstruction(0x05, "TYPEP", MacroOperand.Byte),
+ new MacroInstruction(0x06, "DTEST", MacroOperand.TwoByte),
+ new MacroInstruction(0x07, "UNWIND", MacroOperand.TwoByte),
+ new MacroInstruction(0x08, "FN0", MacroOperand.TwoByte),
+ new MacroInstruction(0x09, "FN1", MacroOperand.TwoByte),
+ new MacroInstruction(0x0a, "FN2", MacroOperand.TwoByte),
+ new MacroInstruction(0x0b, "FN3", MacroOperand.TwoByte),
+ new MacroInstruction(0x0c, "FN4", MacroOperand.TwoByte),
+ new MacroInstruction(0x0d, "FNX", MacroOperand.ThreeByte),
+ new MacroInstruction(0x0e, "APPLYFN", MacroOperand.None),
+ new MacroInstruction(0x0f, "CHECKAPPLY", MacroOperand.None),
+
+ new MacroInstruction(0x10, "RETURN", MacroOperand.None),
+ new MacroInstruction(0x11, "BIND", MacroOperand.TwoByte),
+ new MacroInstruction(0x12, "UNBIND", MacroOperand.None),
+ new MacroInstruction(0x13, "DUNBIND", MacroOperand.None),
+ new MacroInstruction(0x14, "RPLPTR.N", MacroOperand.Byte),
+ new MacroInstruction(0x15, "GCREF", MacroOperand.Byte),
+ new MacroInstruction(0x16, "ASSOC", MacroOperand.None),
+ new MacroInstruction(0x17, "GVAR<-", MacroOperand.TwoByte),
+ new MacroInstruction(0x18, "RPLACA", MacroOperand.None),
+ new MacroInstruction(0x19, "RPLACD", MacroOperand.None),
+ new MacroInstruction(0x1a, "CONS", MacroOperand.None),
+ new MacroInstruction(0x1b, "CMLASSOC", MacroOperand.None),
+ new MacroInstruction(0x1c, "FMEMB", MacroOperand.None),
+ new MacroInstruction(0x1d, "CMLMEMBER", MacroOperand.None),
+ new MacroInstruction(0x1e, "FINDKEY", MacroOperand.Byte),
+ new MacroInstruction(0x1f, "CREATECELL", MacroOperand.None),
+
+ new MacroInstruction(0x20, "BIN", MacroOperand.None),
+ new MacroInstruction(0x21, "BOUT", MacroOperand.None),
+ new MacroInstruction(0x22, "PROLOGOPDISP", MacroOperand.None),
+ new MacroInstruction(0x23, "RESTLIST", MacroOperand.Byte),
+ new MacroInstruction(0x24, "MISCN", MacroOperand.TwoByte),
+ new MacroInstruction(0x25, "ENDCOLLECT", MacroOperand.None),
+ new MacroInstruction(0x26, "RPLCONS", MacroOperand.None),
+ Invalid,
+ new MacroInstruction(0x28, "ELT", MacroOperand.None),
+ new MacroInstruction(0x29, "NTHCHC", MacroOperand.None),
+ new MacroInstruction(0x2a, "SETA", MacroOperand.None),
+ new MacroInstruction(0x2b, "RPLCHARCODE", MacroOperand.None),
+ new MacroInstruction(0x2c, "EVAL", MacroOperand.None),
+ new MacroInstruction(0x2d, "EVALV", MacroOperand.None),
+ new MacroInstruction(0x2e, "TYPECHECK.N", MacroOperand.Byte),
+ new MacroInstruction(0x2f, "STKSCAN", MacroOperand.None),
+
+ new MacroInstruction(0x30, "BUSBLT", MacroOperand.Byte),
+ new MacroInstruction(0x31, "MISC8", MacroOperand.Byte),
+ new MacroInstruction(0x32, "UBFLOAT3", MacroOperand.Byte),
+ new MacroInstruction(0x33, "TYPEMASK.N", MacroOperand.Byte),
+ new MacroInstruction(0x34, "PROLOGREADPTR", MacroOperand.None),
+ new MacroInstruction(0x35, "PROLOGREADTAG", MacroOperand.None),
+ new MacroInstruction(0x36, "PROLOGWRITETAGPTR", MacroOperand.None),
+ new MacroInstruction(0x37, "PROLOGWRITE0PTR", MacroOperand.None),
+ new MacroInstruction(0x38, "PSEUDOCOLOR", MacroOperand.None),
+ Invalid,
+ new MacroInstruction(0x3a, "EQL", MacroOperand.None),
+ new MacroInstruction(0x3b, "DRAWLINE", MacroOperand.None),
+ new MacroInstruction(0x3c, "STORE.N", MacroOperand.Byte),
+ new MacroInstruction(0x3d, "COPY.N", MacroOperand.Byte),
+ new MacroInstruction(0x3e, "RAID", MacroOperand.None),
+ new MacroInstruction(0x3f, "\\RETURN", MacroOperand.None),
+
+ new MacroInstruction(0x40, "IVAR0", MacroOperand.None),
+ new MacroInstruction(0x41, "IVAR1", MacroOperand.None),
+ new MacroInstruction(0x42, "IVAR2", MacroOperand.None),
+ new MacroInstruction(0x43, "IVAR3", MacroOperand.None),
+ new MacroInstruction(0x44, "IVAR4", MacroOperand.None),
+ new MacroInstruction(0x45, "IVAR5", MacroOperand.None),
+ new MacroInstruction(0x46, "IVAR6", MacroOperand.None),
+ new MacroInstruction(0x47, "IVARX", MacroOperand.Byte),
+ new MacroInstruction(0x48, "PVAR0", MacroOperand.None),
+ new MacroInstruction(0x49, "PVAR1", MacroOperand.None),
+ new MacroInstruction(0x4a, "PVAR2", MacroOperand.None),
+ new MacroInstruction(0x4b, "PVAR3", MacroOperand.None),
+ new MacroInstruction(0x4c, "PVAR4", MacroOperand.None),
+ new MacroInstruction(0x4d, "PVAR5", MacroOperand.None),
+ new MacroInstruction(0x4e, "PVAR6", MacroOperand.None),
+ new MacroInstruction(0x4f, "PVARX", MacroOperand.Byte),
+
+ new MacroInstruction(0x50, "FVAR0", MacroOperand.None),
+ new MacroInstruction(0x51, "FVAR1", MacroOperand.None),
+ new MacroInstruction(0x52, "FVAR2", MacroOperand.None),
+ new MacroInstruction(0x53, "FVAR3", MacroOperand.None),
+ new MacroInstruction(0x54, "FVAR4", MacroOperand.None),
+ new MacroInstruction(0x55, "FVAR5", MacroOperand.None),
+ new MacroInstruction(0x56, "FVAR6", MacroOperand.None),
+ new MacroInstruction(0x57, "FVARX", MacroOperand.Byte),
+ new MacroInstruction(0x58, "PVAR0<-", MacroOperand.None),
+ new MacroInstruction(0x59, "PVAR1<-", MacroOperand.None),
+ new MacroInstruction(0x5a, "PVAR2<-", MacroOperand.None),
+ new MacroInstruction(0x5b, "PVAR3<-", MacroOperand.None),
+ new MacroInstruction(0x5c, "PVAR4<-", MacroOperand.None),
+ new MacroInstruction(0x5d, "PVAR5<-", MacroOperand.None),
+ new MacroInstruction(0x5e, "PVAR6<-", MacroOperand.None),
+ new MacroInstruction(0x5f, "PVARX<-", MacroOperand.Byte),
+
+ new MacroInstruction(0x60, "GVAR", MacroOperand.TwoByte),
+ new MacroInstruction(0x61, "ARG0", MacroOperand.None),
+ new MacroInstruction(0x62, "IVARX<-", MacroOperand.Byte),
+ new MacroInstruction(0x63, "FVARX<-", MacroOperand.Byte),
+ new MacroInstruction(0x64, "COPY", MacroOperand.None),
+ new MacroInstruction(0x65, "MYARGCOUNT", MacroOperand.None),
+ new MacroInstruction(0x66, "MYALINK", MacroOperand.None),
+ new MacroInstruction(0x67, "ACONST", MacroOperand.TwoByte),
+ new MacroInstruction(0x68, "'NIL", MacroOperand.None),
+ new MacroInstruction(0x69, "'T", MacroOperand.None),
+ new MacroInstruction(0x6a, "'0", MacroOperand.None),
+ new MacroInstruction(0x6b, "'1", MacroOperand.None),
+ new MacroInstruction(0x6c, "SIC", MacroOperand.Byte),
+ new MacroInstruction(0x6d, "SNIC", MacroOperand.Byte),
+ new MacroInstruction(0x6e, "SICX", MacroOperand.TwoByte),
+ new MacroInstruction(0x6f, "GCONST", MacroOperand.ThreeByte),
+
+ new MacroInstruction(0x70, "ATOMNUMBER", MacroOperand.TwoByte),
+ new MacroInstruction(0x71, "READFLAGS", MacroOperand.None),
+ new MacroInstruction(0x72, "READRP", MacroOperand.None),
+ new MacroInstruction(0x73, "WRITEMAP", MacroOperand.None),
+ new MacroInstruction(0x74, "READPRINTERPORT", MacroOperand.None),
+ new MacroInstruction(0x75, "WRITEPRINTERPORT", MacroOperand.None),
+ new MacroInstruction(0x76, "PILOTBITBLT", MacroOperand.None),
+ new MacroInstruction(0x77, "RCLK", MacroOperand.None),
+ new MacroInstruction(0x78, "MISC1", MacroOperand.Byte),
+ new MacroInstruction(0x79, "MISC2", MacroOperand.Byte),
+ new MacroInstruction(0x7a, "RECLAIMCELL", MacroOperand.None),
+ new MacroInstruction(0x7b, "GCSCAN1", MacroOperand.None),
+ new MacroInstruction(0x7c, "GCSCAN2", MacroOperand.None),
+ new MacroInstruction(0x7d, "SUBRCALL", MacroOperand.TwoByte),
+ new MacroInstruction(0x7e, "CONTEXT", MacroOperand.None),
+ Invalid,
+
+ new MacroInstruction(0x80, "JUMP0", MacroOperand.None),
+ new MacroInstruction(0x81, "JUMP1", MacroOperand.None),
+ new MacroInstruction(0x82, "JUMP2", MacroOperand.None),
+ new MacroInstruction(0x83, "JUMP3", MacroOperand.None),
+ new MacroInstruction(0x84, "JUMP4", MacroOperand.None),
+ new MacroInstruction(0x85, "JUMP5", MacroOperand.None),
+ new MacroInstruction(0x86, "JUMP6", MacroOperand.None),
+ new MacroInstruction(0x87, "JUMP7", MacroOperand.None),
+ new MacroInstruction(0x88, "JUMP8", MacroOperand.None),
+ new MacroInstruction(0x89, "JUMP9", MacroOperand.None),
+ new MacroInstruction(0x8a, "JUMP10", MacroOperand.None),
+ new MacroInstruction(0x8b, "JUMP11", MacroOperand.None),
+ new MacroInstruction(0x8c, "JUMP12", MacroOperand.None),
+ new MacroInstruction(0x8d, "JUMP13", MacroOperand.None),
+ new MacroInstruction(0x8e, "JUMP14", MacroOperand.None),
+ new MacroInstruction(0x8f, "JUMP15", MacroOperand.None),
+
+ new MacroInstruction(0x90, "FJUMP0", MacroOperand.None),
+ new MacroInstruction(0x91, "FJUMP1", MacroOperand.None),
+ new MacroInstruction(0x92, "FJUMP2", MacroOperand.None),
+ new MacroInstruction(0x93, "FJUMP3", MacroOperand.None),
+ new MacroInstruction(0x94, "FJUMP4", MacroOperand.None),
+ new MacroInstruction(0x95, "FJUMP5", MacroOperand.None),
+ new MacroInstruction(0x96, "FJUMP6", MacroOperand.None),
+ new MacroInstruction(0x97, "FJUMP7", MacroOperand.None),
+ new MacroInstruction(0x98, "FJUMP8", MacroOperand.None),
+ new MacroInstruction(0x99, "FJUMP9", MacroOperand.None),
+ new MacroInstruction(0x9a, "FJUMP10", MacroOperand.None),
+ new MacroInstruction(0x9b, "FJUMP11", MacroOperand.None),
+ new MacroInstruction(0x9c, "FJUMP12", MacroOperand.None),
+ new MacroInstruction(0x9d, "FJUMP13", MacroOperand.None),
+ new MacroInstruction(0x9e, "FJUMP14", MacroOperand.None),
+ new MacroInstruction(0x9f, "FJUMP15", MacroOperand.None),
+
+ new MacroInstruction(0xa0, "TJUMP2", MacroOperand.None),
+ new MacroInstruction(0xa1, "TJUMP3", MacroOperand.None),
+ new MacroInstruction(0xa2, "TJUMP4", MacroOperand.None),
+ new MacroInstruction(0xa3, "TJUMP5", MacroOperand.None),
+ new MacroInstruction(0xa4, "TJUMP6", MacroOperand.None),
+ new MacroInstruction(0xa5, "TJUMP7", MacroOperand.None),
+ new MacroInstruction(0xa6, "TJUMP8", MacroOperand.None),
+ new MacroInstruction(0xa7, "TJUMP9", MacroOperand.None),
+ new MacroInstruction(0xa8, "TJUMPa", MacroOperand.None),
+ new MacroInstruction(0xa9, "TJUMPb", MacroOperand.None),
+ new MacroInstruction(0xaa, "TJUMPc", MacroOperand.None),
+ new MacroInstruction(0xab, "TJUMPe", MacroOperand.None),
+ new MacroInstruction(0xac, "TJUMPf", MacroOperand.None),
+ new MacroInstruction(0xad, "TJUMP10", MacroOperand.None),
+ new MacroInstruction(0xae, "TJUMP11", MacroOperand.None),
+ new MacroInstruction(0xaf, "TJUMP12", MacroOperand.None),
+
+ new MacroInstruction(0xb0, "JUMPX", MacroOperand.Byte),
+ new MacroInstruction(0xb1, "JUMPXX", MacroOperand.TwoByte),
+ new MacroInstruction(0xb2, "FJUMPX", MacroOperand.Byte),
+ new MacroInstruction(0xb3, "TJUMPX", MacroOperand.Byte),
+ new MacroInstruction(0xb4, "NFJUMPX", MacroOperand.Byte),
+ new MacroInstruction(0xb5, "NTJUMPX", MacroOperand.Byte),
+ new MacroInstruction(0xb6, "AREF1", MacroOperand.None),
+ new MacroInstruction(0xb7, "ASET1", MacroOperand.None),
+ new MacroInstruction(0xb8, "PVAR0<-^", MacroOperand.None),
+ new MacroInstruction(0xb9, "PVAR1<-^", MacroOperand.None),
+ new MacroInstruction(0xba, "PVAR2<-^", MacroOperand.None),
+ new MacroInstruction(0xbb, "PVAR3<-^", MacroOperand.None),
+ new MacroInstruction(0xbc, "PVAR4<-^", MacroOperand.None),
+ new MacroInstruction(0xbd, "PVAR5<-^", MacroOperand.None),
+ new MacroInstruction(0xbe, "PVAR6<-^", MacroOperand.None),
+ new MacroInstruction(0xbf, "POP", MacroOperand.None),
+
+ new MacroInstruction(0xc0, "POP.N", MacroOperand.Byte),
+ new MacroInstruction(0xc1, "ATOMCELL.N", MacroOperand.Byte),
+ new MacroInstruction(0xc2, "GETBASEBYTE", MacroOperand.None),
+ new MacroInstruction(0xc3, "INSTANCEP", MacroOperand.TwoByte),
+ new MacroInstruction(0xc4, "BLT", MacroOperand.None),
+ new MacroInstruction(0xc5, "MISC10", MacroOperand.TwoByte),
+ Invalid,
+ new MacroInstruction(0xc7, "PUTBASEBYTE", MacroOperand.None),
+ new MacroInstruction(0xc8, "GETBASE.N", MacroOperand.Byte),
+ new MacroInstruction(0xc9, "GETBASEPTR.N", MacroOperand.Byte),
+ new MacroInstruction(0xca, "GETBITS.N.FD", MacroOperand.TwoByte),
+ Invalid,
+ new MacroInstruction(0xcc, "CMLEQUAL", MacroOperand.None),
+ new MacroInstruction(0xcd, "PUTBASE.N", MacroOperand.Byte),
+ new MacroInstruction(0xce, "PUTBASEPTR.N", MacroOperand.Byte),
+ new MacroInstruction(0xcf, "PUTBITS.N.FD", MacroOperand.TwoByte),
+
+ new MacroInstruction(0xd0, "ADDBASE", MacroOperand.None),
+ new MacroInstruction(0xd1, "VAG2", MacroOperand.None),
+ new MacroInstruction(0xd2, "HILOC", MacroOperand.None),
+ new MacroInstruction(0xd3, "LOLOC", MacroOperand.None),
+ new MacroInstruction(0xd4, "PLUS2", MacroOperand.None),
+ new MacroInstruction(0xd5, "DIFFERENCE", MacroOperand.None),
+ new MacroInstruction(0xd6, "TIMES2", MacroOperand.None),
+ new MacroInstruction(0xd7, "QUOTIENT", MacroOperand.None),
+ new MacroInstruction(0xd8, "IPLUS2", MacroOperand.None),
+ new MacroInstruction(0xd9, "IDIFFERENCE", MacroOperand.None),
+ new MacroInstruction(0xda, "ITIMES2", MacroOperand.None),
+ new MacroInstruction(0xdb, "IQUOTIENT", MacroOperand.None),
+ new MacroInstruction(0xdc, "IREMAINDER", MacroOperand.None),
+ new MacroInstruction(0xdd, "IPLUS.N", MacroOperand.Byte),
+ new MacroInstruction(0xde, "IDIFFERENCE.N", MacroOperand.Byte),
+ Invalid,
+
+ new MacroInstruction(0xe0, "LLSH1", MacroOperand.None),
+ new MacroInstruction(0xe1, "LLSH8", MacroOperand.None),
+ new MacroInstruction(0xe2, "LRSH1", MacroOperand.None),
+ new MacroInstruction(0xe3, "LRSH8", MacroOperand.None),
+ new MacroInstruction(0xe4, "LOGOR2", MacroOperand.None),
+ new MacroInstruction(0xe5, "LOGAND2", MacroOperand.None),
+ new MacroInstruction(0xe6, "LOGXOR2", MacroOperand.None),
+ new MacroInstruction(0xe7, "LSH", MacroOperand.None),
+ new MacroInstruction(0xe8, "FPLUS2", MacroOperand.None),
+ new MacroInstruction(0xe9, "FDIFFERENCE", MacroOperand.None),
+ new MacroInstruction(0xea, "FTIMES2", MacroOperand.None),
+ new MacroInstruction(0xeb, "FQUOTIENT", MacroOperand.None),
+ new MacroInstruction(0xec, "UBFLOAT2", MacroOperand.Byte),
+ new MacroInstruction(0xed, "UBFLOAT1", MacroOperand.Byte),
+ new MacroInstruction(0xee, "AREF2", MacroOperand.None),
+ new MacroInstruction(0xef, "ASET2", MacroOperand.None),
+
+ new MacroInstruction(0xe0, "EQ", MacroOperand.None),
+ new MacroInstruction(0xe1, "IGREATERP", MacroOperand.None),
+ new MacroInstruction(0xe2, "FGREATERP", MacroOperand.None),
+ new MacroInstruction(0xe3, "GREATERP", MacroOperand.None),
+ new MacroInstruction(0xe4, "EQUAL", MacroOperand.None),
+ new MacroInstruction(0xe5, "MAKENUMBER", MacroOperand.None),
+ new MacroInstruction(0xe6, "BOXIPLUS", MacroOperand.None),
+ new MacroInstruction(0xe7, "BOXIDIFFERENCE", MacroOperand.None),
+ new MacroInstruction(0xe8, "FLOATBLT", MacroOperand.None),
+ new MacroInstruction(0xe9, "FFTSTEP", MacroOperand.None),
+ new MacroInstruction(0xea, "MISC3", MacroOperand.ThreeByte),
+ new MacroInstruction(0xeb, "MISC4", MacroOperand.ThreeByte),
+ Invalid,
+ new MacroInstruction(0xed, "SWAP", MacroOperand.None),
+ new MacroInstruction(0xee, "NOP", MacroOperand.None),
+ Invalid,
+ };
+
+ private static MacroInstruction Invalid = new MacroInstruction(0x00, "INVALID", MacroOperand.None);
+ }
+}
diff --git a/D/CP/Microinstruction.cs b/D/CP/Microinstruction.cs
new file mode 100644
index 0000000..111637f
--- /dev/null
+++ b/D/CP/Microinstruction.cs
@@ -0,0 +1,1267 @@
+/*
+ BSD 2-Clause License
+
+ Copyright Vulcan Inc. 2017-2018 and Living Computer Museum + Labs 2018
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+using System;
+
+namespace D.CP
+{
+ public enum AluSourcePair
+ {
+ AQ = 0,
+ AB = 1,
+ ZQ = 2,
+ ZB = 3,
+ ZA = 4,
+ DA = 5,
+ DQ = 6,
+ D0 = 7,
+ }
+
+ public enum AluFunction
+ {
+ RplusS = 0,
+ SminusR = 1,
+ RminusS = 2,
+ RorS = 3,
+ RandS = 4,
+ notRandS = 5,
+ RxorS = 6,
+ notRxorS = 7,
+ }
+
+ public enum FunctionSelectFY
+ {
+ DispBr = 0,
+ fyNorm = 1,
+ IOOut = 2,
+ Byte = 3,
+ }
+
+ public enum FunctionSelectFZ
+ {
+ fzNorm = 0,
+ Nibble = 1,
+ Uaddr = 2,
+ IOXIn = 3,
+ }
+
+ public enum XFunction
+ {
+ pCallRet0 = 0x0,
+ pCallRet1 = 0x1,
+ pCallRet2 = 0x2,
+ pCallRet3 = 0x3,
+ pCallRet4 = 0x4,
+ pCallRet5 = 0x5,
+ pCallRet6 = 0x6,
+ pCallRet7 = 0x7,
+ Noop = 0x8,
+ LoadRH = 0x9,
+ shift = 0xa,
+ cycle = 0xb,
+ LoadCinFrompc16 = 0xc,
+ LoadMap = 0xd,
+ pop = 0xe,
+ push = 0xf,
+ }
+
+ public enum YNormFunction
+ {
+ ExitKern = 0x0,
+ EnterKern = 0x1,
+ ClrIntErr = 0x2,
+ IBDisp = 0x3,
+ MesaIntRq = 0x4,
+ LoadstackP = 0x5,
+ LoadIB = 0x6,
+ cycle = 0x7,
+ Noop = 0x8,
+ LoadMap = 0x9,
+ Refresh = 0xa,
+ push = 0xb,
+ ClrDPRq = 0xc,
+ ClrIOPRq = 0xd,
+ ClrRefRq = 0xe,
+ ClrKFlags = 0xf,
+ }
+
+ public enum YDispBrFunction
+ {
+ NegBr = 0x0,
+ ZeroBr = 0x1,
+ NZeroBr = 0x2,
+ MesaIntBr = 0x3,
+ PgCarryBr = 0x4,
+ CarryBr = 0x5,
+ XRefBr = 0x6,
+ NibCarryBr = 0x7,
+ XDisp = 0x8,
+ YDisp = 0x9,
+ XC2npcDisp = 0xa,
+ YIODisp = 0xb,
+ XwdDisp = 0xc,
+ XHDisp = 0xd,
+ XLDisp = 0xe, // AKA XDirtyDisp
+ PgCrOvDisp = 0xf,
+ }
+
+ public enum YIOOutFunction
+ {
+ IOPOData = 0x0,
+ IOPCtl = 0x1,
+ KOData = 0x2,
+ KCtl = 0x3,
+ EOData = 0x4,
+ EICtl = 0x5,
+ DCtlFifo = 0x6,
+ DCtl = 0x7,
+ DBorder = 0x8,
+ PCtl = 0x9,
+ MCtl = 0xa,
+ Invalid0 = 0xb,
+ EOCtl = 0xc,
+ KCmd = 0xd,
+ Invalid1 = 0xe,
+ POData = 0xf,
+ }
+
+ public enum ZNormFunction
+ {
+ Refresh = 0x0,
+ LoadIBPtr1 = 0x1,
+ LoadIBPtr0 = 0x2,
+ LoadCinFrompc16 = 0x3,
+ LoadBank = 0x4,
+ pop = 0x5,
+ push = 0x6,
+ AltUaddr = 0x7,
+ Noop0 = 0x8,
+ Noop1 = 0x9,
+ Noop2 = 0xa,
+ Noop3 = 0xb,
+ LRot0 = 0xc,
+ LRot12 = 0xd,
+ LRot8 = 0xe,
+ LRot4 = 0xf
+ }
+
+ // For Zap Rowsdower
+ public enum ZIOXIn
+ {
+ ReadEIdata = 0x0,
+ ReadEStatus = 0x1,
+ ReadKIData = 0x2,
+ ReadKStatus = 0x3,
+ KStrobe = 0x4,
+ ReadMStatus = 0x5,
+ ReadKTest = 0x6,
+ EStrobe = 0x7,
+ ReadIOPIData = 0x8,
+ ReadIOPStatus = 0x9,
+ ReadErrnIBnStkp = 0xa,
+ ReadRH = 0xb,
+ ReadibNA = 0xc,
+ Readib = 0xd,
+ ReadibLow = 0xe,
+ ReadibHigh = 0xf,
+ }
+
+ public enum StackTestType
+ {
+ None,
+ Underflow,
+ Overflow,
+ Underflow2,
+ }
+
+ ///
+ /// Decodes a single microcode word.
+ ///
+ public class Microinstruction
+ {
+ public Microinstruction(ulong word)
+ {
+ rA = (int)((word & 0xf00000000000) >> 44);
+ rB = (int)((word & 0x0f0000000000) >> 40);
+ aS = (AluSourcePair)((word & 0x00e000000000) >> 37);
+ aF = (AluFunction)((word & 0x001c00000000) >> 34);
+ aD = (int)((word & 0x000300000000) >> 32);
+ ep = (word & 0x000080000000) != 0;
+ Cin = (word & 0x000040000000) != 0;
+ enSU = (word & 0x000020000000) != 0;
+ mem = (word & 0x000010000000) != 0;
+ fSfY = (FunctionSelectFY)((word & 0x00000c000000) >> 26);
+ fSfZ = (FunctionSelectFZ)((word & 0x000003000000) >> 24);
+ fX = (XFunction)((word & 0x000000f00000) >> 20);
+ fY = (int)((word & 0x0000000f0000) >> 16);
+ fZ = (int)((word & 0x00000000f000) >> 12);
+ INIA = (int)((word & 0x000000000fff));
+
+
+ //
+ // Instruction metadata that can be precomputed and cached
+ //
+ Cycle = (fX == XFunction.cycle) ||
+ (fSfY == FunctionSelectFY.fyNorm && ((YNormFunction)fY) == YNormFunction.cycle);
+ Shift =
+ ((fX == XFunction.shift) ||
+ Cycle);
+
+ AluNeedsXBus = (aS == AluSourcePair.D0 || aS == AluSourcePair.DA || aS == AluSourcePair.DQ);
+
+ AluDestination = aD | (Shift ? 0x4 : 0x0);
+
+ SURead = enSU && !Cin;
+
+ SUWrite = enSU && Cin;
+
+ LoadMap = fX == XFunction.LoadMap ||
+ (fSfY == FunctionSelectFY.fyNorm &&
+ (YNormFunction)fY == YNormFunction.LoadMap);
+
+ ABypass = AluDestination == 0x2;
+
+ LoadStackP = (fSfY == FunctionSelectFY.fyNorm &&
+ (YNormFunction)fY == YNormFunction.LoadstackP);
+
+ LoadIBPtr1 = (fSfZ == FunctionSelectFZ.fzNorm && ((ZNormFunction)fZ) == ZNormFunction.LoadIBPtr1);
+
+ AlwaysIBDisp = (fSfY == FunctionSelectFY.fyNorm &&
+ (YNormFunction)fY == YNormFunction.IBDisp) &&
+ LoadIBPtr1;
+
+ LoadIB = fSfY == FunctionSelectFY.fyNorm &&
+ (YNormFunction)fY == YNormFunction.LoadIB;
+
+ UAddress = (rA << 4) | fZ;
+
+ switch (fX)
+ {
+ case XFunction.pCallRet0:
+ case XFunction.pCallRet1:
+ case XFunction.pCallRet2:
+ case XFunction.pCallRet3:
+ case XFunction.pCallRet4:
+ case XFunction.pCallRet5:
+ case XFunction.pCallRet6:
+ case XFunction.pCallRet7:
+ LinkAddress = (int)fX;
+ break;
+
+ default:
+ LinkAddress = -1;
+ break;
+ }
+
+ MarMapMDR = mem || LoadMap;
+
+ LateLRotN = !ABypass && fSfZ == FunctionSelectFZ.fzNorm;
+
+ if (fSfY == FunctionSelectFY.Byte)
+ {
+ // Byte constant
+ Byte = (byte)((fY << 4) | fZ);
+ }
+ else if (fSfZ == FunctionSelectFZ.Nibble)
+ {
+ // Nibble constant
+ Byte = (byte)fZ;
+ }
+ else
+ {
+ // No constant value.
+ Byte = 0;
+ }
+
+ bool fxPop = (fX == XFunction.pop);
+ bool fzPop = (fSfZ == FunctionSelectFZ.fzNorm && ((ZNormFunction)fZ) == ZNormFunction.pop);
+
+ Pop = fxPop || fzPop;
+
+ //
+ // There is a special case if both fxPop and fzPop are specified: stackP is still decremented by 1,
+ // but a trap is invoked if stackP is 1 or 0 (rather than just 0).
+ //
+ DoublePop = fxPop && fzPop;
+
+ Push = (fX == XFunction.push) ||
+ (fSfY == FunctionSelectFY.fyNorm && ((YNormFunction)fY) == YNormFunction.push) ||
+ (fSfZ == FunctionSelectFZ.fzNorm && ((ZNormFunction)fZ) == ZNormFunction.push);
+
+ StackOperation = Pop || Push;
+
+ //
+ // From the HWref (p. 33):
+ // "Multiple pop's and push's can be specified per microinstruction in order to ameliorate the detection
+ // of Stack overflow or underflow. For instance, fXpop (i.e. the pop in the fX field), fZpop, and
+ // push executed together leave the stackPointer unmodified, yet simulate two pop's with respect to
+ // stack underflow detection..."
+ // The actual overflow detection logic is controlled by a PROM, there's nothing too weird going on
+ // here (other than overloading to provide only semi-related semantics, which is annoying.) At
+ // any rate, we precompute the check that's being requested (if any) so we don't have to do it
+ // at execution time.
+ // TODO: might make sense to dump the PROM and use that.
+ //
+ if (fxPop && fzPop && Push)
+ {
+ StackTest = StackTestType.Underflow2;
+ }
+ else if (Push && fzPop)
+ {
+ StackTest = StackTestType.Overflow;
+ }
+ else if (fxPop && Push)
+ {
+ StackTest = StackTestType.Underflow;
+ }
+ else
+ {
+ // No non-modify test, just normal stack behavior.
+ StackTest = StackTestType.None;
+ }
+
+ }
+
+ ///
+ /// 2901 A reg addr, U addr [0-3]
+ ///
+ public readonly int rA;
+
+ ///
+ /// 2901 B reg addr, RH addr
+ ///
+ public readonly int rB;
+
+ ///
+ /// 2901 alu Source operand pair
+ ///
+ public readonly AluSourcePair aS;
+
+ ///
+ /// 2901 alu Function
+ ///
+ public readonly AluFunction aF;
+
+ ///
+ /// 2901 alu Destination/shift control
+ ///
+ public readonly int aD;
+
+ ///
+ /// Even Parity
+ ///
+ public readonly bool ep;
+
+ ///
+ /// 2901 Carry In, Shift Ends, writeSU (if enSU = 1)
+ ///
+ public readonly bool Cin;
+
+ ///
+ /// enable SU reg file
+ ///
+ public readonly bool enSU;
+
+ ///
+ /// MAR<- (if c1), MDR<- (if c2), <-MD (if c3)
+ ///
+ public readonly bool mem;
+
+ ///
+ /// Function field selector for Y
+ ///
+ public readonly FunctionSelectFY fSfY;
+
+ ///
+ /// Function field selector for Z
+ ///
+ public readonly FunctionSelectFZ fSfZ;
+
+ ///
+ /// X Function
+ ///
+ public readonly XFunction fX;
+
+ ///
+ /// Y Function
+ ///
+ public readonly int fY;
+
+ ///
+ /// Z Function
+ ///
+ public readonly int fZ;
+
+ ///
+ /// Next Instruction Address
+ ///
+ public readonly int INIA;
+
+ //
+ // The following are metadata for this instruction, used to speed execution.
+ //
+
+ ///
+ /// Instruction specifies a Cycle of ALU output when writing back to R/Q
+ ///
+ public readonly bool Cycle;
+
+ ///
+ /// Instruction specifies a Shift of ALU as above.
+ ///
+ public readonly bool Shift;
+
+ ///
+ /// Instruction requires XBus input to ALU.
+ ///
+ public readonly bool AluNeedsXBus;
+
+ ///
+ /// Destination control for the ALU
+ ///
+ public readonly int AluDestination;
+
+ ///
+ /// Instruction specifies an SU register read
+ ///
+ public readonly bool SURead;
+
+ ///
+ /// Instruction specifies an SU register write
+ ///
+ public readonly bool SUWrite;
+
+ ///
+ /// Instruction specifies a Map<- operation.
+ ///
+ public readonly bool LoadMap;
+
+ ///
+ /// Instruction uses the A-bypass mode for the ALU.
+ ///
+ public readonly bool ABypass;
+
+ ///
+ /// Instruction specifies a stackP<- operation.
+ ///
+ public readonly bool LoadStackP;
+
+ ///
+ /// Instruction specifies a push operation
+ ///
+ public readonly bool Push;
+
+ ///
+ /// Instruction specifies a pop operation
+ ///
+ public readonly bool Pop;
+
+ ///
+ /// Instruction specifies a double-pop operation.
+ ///
+ public readonly bool DoublePop;
+
+ ///
+ /// Whether any stack operations (pushes or pops) occur in this instruction.
+ ///
+ public readonly bool StackOperation;
+
+ ///
+ /// Specifies the kind of test specified by the various
+ /// push/pop instruction fields.
+ ///
+ public readonly StackTestType StackTest;
+
+ ///
+ /// Causes an IBDisp branch even if IB is not full;
+ /// specified by IBDisp + IBPtr<-1
+ ///
+ public readonly bool AlwaysIBDisp;
+
+ ///
+ /// Whether an IB<- is specified this instruction.
+ ///
+ public readonly bool LoadIB;
+
+ ///
+ /// Whether the instruction specifies an ibPtr<-1 operation,
+ /// which can be used to modify other operations.
+ ///
+ public readonly bool LoadIBPtr1;
+
+ ///
+ /// Constant address used to address U register when loading/storing
+ ///
+ public readonly int UAddress;
+
+ ///
+ /// Constant byte value
+ ///
+ ///
+ public readonly byte Byte;
+
+ ///
+ /// Link address specified by instruction (or -1 if not specified)
+ ///
+ public readonly int LinkAddress;
+
+ ///
+ /// Whether the instruction specifies an MAR<-, Map<-, or MDR<- operation.
+ ///
+ public readonly bool MarMapMDR;
+
+ ///
+ /// Whether to do an LrotN operation after the ALU runs.
+ ///
+ public readonly bool LateLRotN;
+
+ public override string ToString()
+ {
+ return String.Format("rA={0:x} rB={1:x} aS={2} aF={3} aD={4} ep={5} Cin={6} enSU={7} mem={8} fSY={9} fSZ={10} fX={11} fY={12:x} fZ={13:x} INIA={14:x3}",
+ rA, rB, aS, aF, aD, ep, Cin, enSU, mem, fSfY, fSfZ, fX, fY, fZ, INIA);
+ }
+
+ public string Disassemble(int cycle)
+ {
+ //
+ // Build ALU op, start with the sources:
+ //
+
+ string aluR;
+ string aluS;
+ bool Rzero = false;
+ bool Szero = false;
+
+ string xBusValue = DisassembleXBusSource(cycle);
+
+ switch (aS)
+ {
+ case AluSourcePair.AB:
+ aluR = String.Format("R{0:x}", rA);
+ aluS = String.Format("R{0:x}", rB);
+ break;
+
+ case AluSourcePair.AQ:
+ aluR = String.Format("R{0:x}", rA);
+ aluS = "Q";
+ break;
+
+ case AluSourcePair.ZA:
+ aluR = "0";
+ Rzero = true;
+ aluS = String.Format("R{0:x}", rA);
+ break;
+
+ case AluSourcePair.ZB:
+ aluR = "0";
+ Rzero = true;
+ aluS = String.Format("R{0:x}", rB);
+ break;
+
+ case AluSourcePair.ZQ:
+ aluR = "0";
+ Rzero = true;
+ aluS = "Q";
+ break;
+
+ case AluSourcePair.D0:
+ aluR = xBusValue;
+ aluS = "0";
+ Szero = true;
+ break;
+
+ case AluSourcePair.DA:
+ aluR = xBusValue;
+ aluS = String.Format("R{0:x}", rA);
+ break;
+
+ case AluSourcePair.DQ:
+ aluR = xBusValue;
+ aluS = "Q";
+ break;
+
+ default:
+ throw new InvalidOperationException("Unexpected ALU source pair.");
+ }
+
+ //
+ // Select operation
+ //
+ string aluOp;
+ switch (aF)
+ {
+ case AluFunction.RplusS:
+ if (Rzero)
+ {
+ aluOp = aluS;
+ }
+ else if (Szero)
+ {
+ aluOp = aluR;
+ }
+ else
+ {
+ aluOp = String.Format("{0}+{1}", aluR, aluS);
+ }
+ break;
+
+ case AluFunction.SminusR:
+ if (Rzero)
+ {
+ aluOp = aluS;
+ }
+ else if (Szero)
+ {
+ aluOp = "-" + aluR;
+ }
+ else
+ {
+ aluOp = String.Format("{0}-{1}", aluS, aluR);
+ }
+ break;
+
+ case AluFunction.RminusS:
+ if (Rzero)
+ {
+ aluOp = "-" + aluS;
+ }
+ else if (Szero)
+ {
+ aluOp = aluR;
+ }
+ else
+ {
+ aluOp = String.Format("{0}-{1}", aluR, aluS);
+ }
+ break;
+
+ case AluFunction.RorS:
+ if (Rzero)
+ {
+ aluOp = aluS;
+ }
+ else if (Szero)
+ {
+ aluOp = aluR;
+ }
+ else
+ {
+ aluOp = String.Format("{0} or {1}", aluR, aluS);
+ }
+ break;
+
+ case AluFunction.RandS:
+ if (Rzero)
+ {
+ aluOp = "0";
+ }
+ else if (Szero)
+ {
+ aluOp = "0";
+ }
+ else
+ {
+ aluOp = String.Format("{0} and {1}", aluR, aluS);
+ }
+ break;
+
+ case AluFunction.notRandS:
+ if (Rzero)
+ {
+ aluOp = aluS;
+ }
+ else if (Szero)
+ {
+ aluOp = "0";
+ }
+ else
+ {
+ aluOp = String.Format("~{0} and {1}", aluR, aluS);
+ }
+ break;
+
+ case AluFunction.RxorS:
+ if (Rzero)
+ {
+ aluOp = aluS;
+ }
+ else if (Szero)
+ {
+ aluOp = aluR;
+ }
+ else
+ {
+ aluOp = String.Format("{0} xor {1}", aluR, aluS);
+ }
+ break;
+
+ case AluFunction.notRxorS:
+ if (Szero)
+ {
+ aluOp = "~" + aluR;
+ }
+ else
+ {
+ aluOp = String.Format("~{0} xor {1}", aluR, aluS);
+ }
+ break;
+
+ default:
+ throw new InvalidOperationException("Unexpected ALU operation");
+ }
+
+ //
+ // Select register writeback (to rB)
+ // Q writeback, and Y source (F, or A bypass)
+ //
+ int writeFn = aD | (Shift ? 0x4 : 0x0);
+ string regAssignment;
+ bool aBypass = false;
+ bool yBusIsSourceForDestination = false;
+ bool aluNoWriteBack = false;
+ switch(writeFn)
+ {
+ case 0:
+ // no write, Q<-F
+ regAssignment = String.Format("Q<- {0}{1}", aluOp, GetCarryMod());
+ yBusIsSourceForDestination = true;
+ break;
+
+ case 1:
+ // no write.
+ regAssignment = String.Format("{0}{1}", aluOp, GetCarryMod());
+ yBusIsSourceForDestination = false;
+ aluNoWriteBack = true;
+ break;
+
+ case 2:
+ // R[rB] <- F, no write to Q, A Bypass for YBus<-
+ regAssignment = String.Format("R{0:x}<- {1}{2}", rB, aluOp, GetCarryMod());
+ aBypass = true;
+ yBusIsSourceForDestination = true;
+ break;
+
+ case 3:
+ // R[rB] <- F, no write to Q
+ regAssignment = String.Format("R{0:x}<- {1}{2}", rB, aluOp, GetCarryMod());
+ yBusIsSourceForDestination = true;
+ break;
+
+ case 4:
+ if (Cycle)
+ {
+ // double-word right shift
+ regAssignment = String.Format("R{0:x}<- DRShift1 {1}{2}{3}", rB, aluOp, GetCarryMod(), Cin ? " SE<-1" : String.Empty);
+ }
+ else
+ {
+ // double-word arithmetic right shift.
+ regAssignment = String.Format("R{0:x}<- DARShift1 {1}{2}{3}", rB, aluOp, GetCarryMod(), Cin ? " SE<-1" : String.Empty);
+ }
+ yBusIsSourceForDestination = true;
+ break;
+
+ case 5:
+ if (Cycle)
+ {
+ // F: single-word right rotate:
+ regAssignment = String.Format("R{0:x}<- RRot1 {1}{2}", rB, aluOp, GetCarryMod());
+ }
+ else
+ {
+ // F: single-word right shift w/carryIn to MSB:
+ regAssignment = String.Format("R{0:x}<- RShift1 {1}{2}{3}", rB, aluOp, GetCarryMod(), Cin ? " SE<-1" : String.Empty);
+ }
+ yBusIsSourceForDestination = true;
+ break;
+
+ case 6:
+ if (Cycle)
+ {
+ // double-word left shift
+ regAssignment = String.Format("R{0:x}<- DLShift1 {1}{2}{3}", rB, aluOp, GetCarryMod(), Cin ? " SE<-1" : String.Empty);
+ }
+ else
+ {
+ // double-word arithmetic left shift
+ regAssignment = String.Format("R{0:x}<- DALShift1 {1}{2}{3}", rB, aluOp, GetCarryMod(), Cin ? " SE<-1" : String.Empty);
+ }
+ yBusIsSourceForDestination = true;
+ break;
+
+ case 7:
+ if (Cycle)
+ {
+ // single-word left rotate:
+ regAssignment = String.Format("R{0:x}<- LRot1 {1}{2}", rB, aluOp, GetCarryMod());
+ }
+ else
+ {
+ // single-word left shift w/carryIn to MSB:
+ regAssignment = String.Format("R{0:x}<- LShift1 {1}{2}{3}", rB, aluOp, GetCarryMod(), Cin ? " SE<-1" : String.Empty);
+ }
+ yBusIsSourceForDestination = true;
+ break;
+
+ default:
+ throw new InvalidOperationException("Unexpected sh,,aD value.");
+ }
+
+ string yBusValue = aBypass ? String.Format("R{0:x}, {1}", rA, regAssignment) : String.Format("{0}", regAssignment);
+
+ string fxFunc = String.Empty;
+ bool xBusIsSourceForDestination = false;
+
+ bool yBusBranch = false;
+ bool xBusBranch = false;
+
+ // Handle fX functions that aren't implicitly handled elsewhere (shift, cycle)
+ switch (fX)
+ {
+ case XFunction.pCallRet0:
+ case XFunction.pCallRet1:
+ case XFunction.pCallRet2:
+ case XFunction.pCallRet3:
+ case XFunction.pCallRet4:
+ case XFunction.pCallRet5:
+ case XFunction.pCallRet6:
+ case XFunction.pCallRet7:
+ fxFunc = String.Format("pCall/Ret{0} ", (int)fX);
+ break;
+
+ case XFunction.LoadRH:
+ fxFunc = String.Format("RH{0:x}<-", rB);
+ xBusIsSourceForDestination = true;
+ break;
+
+ case XFunction.LoadCinFrompc16:
+ fxFunc = "SE<-pc16 ";
+ break;
+
+ case XFunction.LoadMap:
+ fxFunc = String.Format("Map<- RH{0:x},,", rB);
+ yBusIsSourceForDestination = true;
+ break;
+
+ case XFunction.pop:
+ fxFunc = "pop ";
+ break;
+
+ case XFunction.push:
+ fxFunc = "push ";
+ break;
+ }
+
+ string fyFunc = String.Empty;
+
+ // Handle fY functions that aren't implicitly handled elsewhere (cycle, Byte, etc.)
+ switch (fSfY)
+ {
+ case FunctionSelectFY.fyNorm:
+ switch ((YNormFunction)fY)
+ {
+ case YNormFunction.ExitKern:
+ fyFunc = "ExitKern ";
+ break;
+
+ case YNormFunction.EnterKern:
+ fyFunc = "EnterKern ";
+ break;
+
+ case YNormFunction.ClrIntErr:
+ fyFunc = "ClrIntErr ";
+ break;
+
+ case YNormFunction.IBDisp:
+ fyFunc = "IBDisp ";
+ break;
+
+ case YNormFunction.MesaIntRq:
+ fyFunc = "MesaIntRq ";
+ break;
+
+ case YNormFunction.LoadstackP:
+ fyFunc = "stackP<-";
+ yBusIsSourceForDestination = true;
+ break;
+
+ case YNormFunction.LoadIB:
+ fyFunc = "IB<-";
+ xBusIsSourceForDestination = true;
+ break;
+
+ case YNormFunction.LoadMap:
+ fyFunc = String.Format("Map<- RH{0:x},,", rB);
+ break;
+
+ case YNormFunction.Refresh:
+ fyFunc = "Refresh ";
+ break;
+
+ case YNormFunction.push:
+ fyFunc = "push ";
+ break;
+
+ case YNormFunction.ClrDPRq:
+ fyFunc = "ClrDPRq ";
+ break;
+
+ case YNormFunction.ClrIOPRq:
+ fyFunc = "ClrIOPRq ";
+ break;
+
+ case YNormFunction.ClrRefRq:
+ fyFunc = "ClrRefRq ";
+ break;
+
+ case YNormFunction.ClrKFlags:
+ fyFunc = "ClrKFlags ";
+ break;
+ }
+ break;
+
+ case FunctionSelectFY.DispBr:
+ fyFunc = ((YDispBrFunction)fY).ToString() + " ";
+
+ switch ((YDispBrFunction)fY)
+ {
+ case YDispBrFunction.NegBr:
+ case YDispBrFunction.ZeroBr:
+ case YDispBrFunction.NibCarryBr:
+ case YDispBrFunction.PgCarryBr:
+ case YDispBrFunction.CarryBr:
+ case YDispBrFunction.PgCrOvDisp:
+ case YDispBrFunction.YDisp:
+ case YDispBrFunction.YIODisp:
+ yBusBranch = true;
+ break;
+
+ case YDispBrFunction.XRefBr:
+ case YDispBrFunction.XwdDisp:
+ case YDispBrFunction.XHDisp:
+ case YDispBrFunction.XLDisp:
+ case YDispBrFunction.XDisp:
+ case YDispBrFunction.XC2npcDisp:
+ xBusBranch = true;
+ break;
+ }
+
+ break;
+
+ case FunctionSelectFY.IOOut:
+ if (fY != 0xb && fY != 0xe)
+ {
+ YIOOutFunction yIOOut = ((YIOOutFunction)fY);
+ fyFunc = yIOOut.ToString() + "<-";
+
+ // IOOut functions are roughly split between taking data from the XBus or the YBus.
+ xBusIsSourceForDestination =
+ (yIOOut == YIOOutFunction.IOPOData ||
+ yIOOut == YIOOutFunction.IOPCtl ||
+ yIOOut == YIOOutFunction.KOData ||
+ yIOOut == YIOOutFunction.KCtl ||
+ yIOOut == YIOOutFunction.EOData ||
+ yIOOut == YIOOutFunction.EICtl ||
+ yIOOut == YIOOutFunction.DCtl ||
+ yIOOut == YIOOutFunction.PCtl ||
+ yIOOut == YIOOutFunction.EOCtl ||
+ yIOOut == YIOOutFunction.KCmd ||
+ yIOOut == YIOOutFunction.POData
+ );
+
+ yBusIsSourceForDestination = (!xBusIsSourceForDestination && (fY != 0xb && fY != 0xe));
+
+ }
+ break;
+ }
+
+ string fzFunc = String.Empty;
+
+ // Handle fZ functions that aren't implicitly handled elsewhere (IOXIn)
+ switch (fSfZ)
+ {
+ case FunctionSelectFZ.fzNorm:
+ switch((ZNormFunction)fZ)
+ {
+ case ZNormFunction.Refresh:
+ fzFunc = "Refresh ";
+ break;
+
+ case ZNormFunction.LoadIBPtr1:
+ fzFunc = "IBPtr<-1 ";
+ break;
+
+ case ZNormFunction.LoadIBPtr0:
+ fzFunc = "IBPtr<-0 ";
+ break;
+
+ case ZNormFunction.LoadCinFrompc16:
+ fzFunc = "SE<-pc16 ";
+ break;
+
+ case ZNormFunction.pop:
+ fzFunc = "pop ";
+ break;
+
+ case ZNormFunction.push:
+ fzFunc = "push ";
+ break;
+
+ case ZNormFunction.AltUaddr:
+ fzFunc = "AltUaddr ";
+ break;
+
+ case ZNormFunction.LRot0:
+ fzFunc = "LRot0 ";
+ break;
+
+ case ZNormFunction.LRot12:
+ fzFunc = "LRot12 ";
+ break;
+
+ case ZNormFunction.LRot8:
+ fzFunc = "LRot8 ";
+ break;
+
+ case ZNormFunction.LRot4:
+ fzFunc = "LRot4 ";
+ break;
+ }
+ break;
+ }
+
+ // SU reg write
+ string suWriteStr = String.Empty;
+ bool suWrite = enSU && Cin;
+ bool suRead = enSU && !Cin;
+ if (suWrite)
+ {
+ switch((int)fSfZ)
+ {
+ case 0:
+ case 1:
+ suWriteStr = "STK<-";
+ break;
+
+ case 2:
+ case 3:
+ suWriteStr = String.Format("U{0:x2}<-", (rA << 4) | fZ);
+ break;
+ }
+
+ yBusIsSourceForDestination = true;
+ }
+
+ if(!yBusIsSourceForDestination && !xBusIsSourceForDestination)
+ {
+ suWriteStr = "Xbus<- ";
+
+ // Y bus is implicitly used to provide an X bus value if nothing else is selected.
+ yBusIsSourceForDestination = string.IsNullOrEmpty(xBusValue);
+ }
+
+ // MAR or MDR writes:
+ string memWrite = String.Empty;
+
+ if (mem)
+ {
+ if (cycle == 1)
+ {
+ memWrite = "MAR<- ";
+ }
+ else if (cycle == 2)
+ {
+ memWrite = "MDR<- ";
+ }
+ else if (cycle == -1)
+ {
+ memWrite = "{MAR/MDR/MD} ";
+ }
+ }
+
+ //
+ // The below is kind of messy because of conflation of the ALU with the Y-Bus way up above, etc.
+ // Bear with me.
+ //
+
+ //
+ // The Y Bus value is important and needs to be included in the disassembly if one or more of the
+ // below are true:
+ // - A register assignment is taking place
+ // - The Y Bus is being used as a data source
+ // - A dispatch or branch involving the Y Bus or ALU is being invoked during this instruction.
+ //
+ bool showyBusValue = (yBusBranch || yBusIsSourceForDestination || !aluNoWriteBack);
+
+ //
+ // The X Bus value is important and needs to be included in the disassembly if one or more of the
+ // below are true:
+ // - The ALU isn't already using the X Bus as an input
+ // - The X Bus is being used as a data source
+ // - A dispatch or branch involving the X Bus is being invoked during this instruction.
+ //
+ bool showxBusValue = (xBusBranch || !AluNeedsXBus || xBusIsSourceForDestination);
+
+ string disassembly = String.Format("{0}{1}{2}{3}{4}{5}{6} [{7:x3}]",
+ fxFunc,
+ fyFunc,
+ fzFunc,
+ memWrite,
+ suWriteStr,
+ showxBusValue ? xBusValue : String.Empty,
+ showyBusValue ? yBusValue : String.Empty,
+ INIA);
+
+
+ return disassembly;
+ }
+
+ private string GetCarryMod()
+ {
+ string mod = String.Empty;
+ bool add = (aF == AluFunction.RplusS);
+ bool sub = (aF == AluFunction.RminusS || aF == AluFunction.SminusR);
+
+ if (Cin & add)
+ {
+ mod = "+1";
+ }
+ else if (!Cin & sub)
+ {
+ mod = "-1";
+ }
+
+ return mod;
+ }
+
+ private string DisassembleXBusSource(int cycle)
+ {
+ string xBus = String.Empty;
+
+ // Byte and/or Nibble. In theory these are mutually exclusive,
+ // but there's nothing that prevents them both from being coded at the same time.
+ // If this happens, Byte takes precedence.
+ if (fSfY == FunctionSelectFY.Byte)
+ {
+ xBus = String.Format("byte({0:x2})", ((fY << 4) | fZ));
+ }
+
+ if(fSfZ == FunctionSelectFZ.Nibble && fSfY != FunctionSelectFY.Byte)
+ {
+ xBus = String.Format("nibble({0:x1})", fZ);
+ }
+ else if (fSfZ == FunctionSelectFZ.IOXIn)
+ {
+ // IOXIn sources
+ switch((ZIOXIn)fZ)
+ {
+ case ZIOXIn.ReadEIdata:
+ xBus += "EIData";
+ break;
+
+ case ZIOXIn.ReadEStatus:
+ xBus += "EStatus";
+ break;
+
+ case ZIOXIn.ReadKIData:
+ xBus += "KIData";
+ break;
+
+ case ZIOXIn.ReadKStatus:
+ xBus += "KStatus";
+ break;
+
+ case ZIOXIn.ReadMStatus:
+ xBus += "MStatus";
+ break;
+
+ case ZIOXIn.ReadKTest:
+ xBus += "KTest";
+ break;
+
+ case ZIOXIn.ReadIOPIData:
+ xBus += "IOPIData";
+ break;
+
+ case ZIOXIn.ReadIOPStatus:
+ xBus += "IOPStatus";
+ break;
+
+ case ZIOXIn.ReadErrnIBnStkp:
+ xBus += "ErrnIBnStkP";
+ break;
+
+ case ZIOXIn.ReadRH:
+ xBus += String.Format("RH{0:x}", rB);
+ break;
+
+ case ZIOXIn.ReadibNA:
+ xBus += "ibNA";
+ break;
+
+ case ZIOXIn.ReadibLow:
+ xBus += "ibLow";
+ break;
+
+ case ZIOXIn.ReadibHigh:
+ xBus += "ibHigh";
+ break;
+
+ default:
+ xBus += ((ZIOXIn)fZ).ToString();
+ break;
+ }
+ }
+
+ if (enSU && !Cin) // Cin is 0 for reads
+ {
+ // SU read operations
+ switch((int)fSfZ)
+ {
+ case 0:
+ case 1:
+ xBus += "STK";
+ break;
+
+ case 2:
+ case 3:
+ xBus += String.Format("U{0:x2}", (rA << 4) | fZ);
+ break;
+ }
+ }
+
+ if (mem && cycle == 3)
+ {
+ xBus += "<-MD";
+ }
+
+ return xBus;
+ }
+ }
+}
diff --git a/D/CP/Source/BootKernel_map.txt b/D/CP/Source/BootKernel_map.txt
new file mode 100644
index 0000000..aca29a4
--- /dev/null
+++ b/D/CP/Source/BootKernel_map.txt
@@ -0,0 +1,43 @@
+#
+ # This file maps assembly source symbols to PROM/microcode addresses and source lines, forming a crude
+ # symbol table.
+ #
+ # Each source file is given a header a la:
+ # [FooSource.asm]
+ # (with brackets)
+
+ # Each line's syntax is:
+ # , .. , : ,
+ # where '*none*' is a special symbol name meaning no symbol mapping is present.
+[BootKernel.mc,v]
+*none*: 0x0fdf,50
+KGo: 0x0fde,49
+*none*: 0x0fdd,51
+*none*: 0x0fdc,52
+*none*: 0x0fdb,53
+*none*: 0x0fda,54
+*none*: 0x0fd9,55
+*none*: 0x0fd8,56
+KEntry: 0x0fe0,66
+*none*: 0x0fe2,67
+*none*: 0x0fe6,68
+*none*: 0x0fe8,69
+KRefresh: 0x0fe5,71
+*none*: 0x0fe9,72
+*none*: 0x0fea,73
+KLoop: 0x0fe4,75
+*none*: 0x0feb,76
+*none*: 0x0ff0,77
+KTable: 0x0ffc,88
+*none*: 0x0fee,89
+*none*: 0x0fef,90
+*none*: 0x0fe7,81
+*none*: 0x0fe1,80
+*none*: 0x0ff1,82
+*none*: 0x0fec,85
+*none*: 0x0fed,86
+KDisp: 0x0fe3,84
+KRefCmd: 0x0ffd,92
+KCmd2: 0x0ffe,93
+KCmd3: 0x0fff,94
+
diff --git a/D/CP/Source/CPMemTest_map.txt b/D/CP/Source/CPMemTest_map.txt
new file mode 100644
index 0000000..1399d21
--- /dev/null
+++ b/D/CP/Source/CPMemTest_map.txt
@@ -0,0 +1,256 @@
+#
+ # This file maps assembly source symbols to PROM/microcode addresses and source lines, forming a crude
+ # symbol table.
+ #
+ # Each source file is given a header a la:
+ # [FooSource.asm]
+ # (with brackets)
+
+ # Each line's syntax is:
+ # , .. , : ,
+ # where '*none*' is a special symbol name meaning no symbol mapping is present.
+[MoonCPMemTest.mc,v]
+*none*: 0x00ff,72
+Start: 0x0182,71
+*none*: 0x0183,73
+*none*: 0x0184,75
+*none*: 0x0185,76
+*none*: 0x0186,77
+*none*: 0x0187,79
+*none*: 0x0188,80
+*none*: 0x0189,81
+*none*: 0x018a,83
+*none*: 0x018b,84
+*none*: 0x018c,85
+walk: 0x018d,90
+ChkBound: 0x018e,91
+*none*: 0x018f,92
+*none*: 0x0190,94
+*none*: 0x0096,95
+ChkYTop: 0x0191,97
+YBotOK: 0x0097,96
+*none*: 0x0192,99
+YTopOK: 0x0068,101
+ChkDone: 0x0193,102
+StartM: 0x0194,105
+*none*: 0x0195,106
+*none*: 0x0196,107
+*none*: 0x0197,109
+*none*: 0x0198,110
+*none*: 0x0199,111
+*none*: 0x019a,113
+*none*: 0x019b,114
+*none*: 0x019c,115
+*none*: 0x019d,117
+RUNLIST: 0x0098,120
+RUNLISTX: 0x0060,121
+SETUP: 0x01ea,293
+*none*: 0x01eb,294
+*none*: 0x01ec,295
+*none*: 0x01ed,297
+*none*: 0x01ee,298
+*none*: 0x01ef,299
+*none*: 0x01f0,301
+*none*: 0x01f1,302
+*none*: 0x01f2,303
+*none*: 0x01f3,305
+*none*: 0x01f4,306
+*none*: 0x01f5,307
+*none*: 0x01f6,308
+*none*: 0x01f7,311
+*none*: 0x01f8,312
+*none*: 0x01f9,313
+*none*: 0x01fa,314
+*none*: 0x01fb,315
+*none*: 0x01fc,318
+*none*: 0x01fd,319
+*none*: 0x01fe,321
+*none*: 0x01ff,322
+*none*: 0x0200,323
+*none*: 0x0201,325
+RUNLISTRET: 0x01cf,241
+*none*: 0x01d0,242
+*none*: 0x0038,243
+*none*: 0x00e0,123
+RUNL: 0x019e,124
+*none*: 0x019f,125
+RunTest: 0x0050,127
+*none*: 0x0051,128
+*none*: 0x0052,129
+*none*: 0x0053,130
+RUNLIST1: 0x01a0,133
+*none*: 0x0061,134
+*none*: 0x00e1,136
+*none*: 0x01a1,137
+*none*: 0x0022,138
+SSTORE: 0x0202,345
+*none*: 0x0025,346
+AdjustQ: 0x0227,480
+*none*: 0x0228,481
+*none*: 0x001c,483
+*none*: 0x001d,484
+*none*: 0x001e,485
+*none*: 0x001f,486
+*none*: 0x0105,347
+*none*: 0x0203,349
+*none*: 0x0046,350
+*none*: 0x0106,351
+*none*: 0x0204,353
+*none*: 0x0205,354
+STYPE: 0x0058,356
+*none*: 0x0059,357
+*none*: 0x005a,358
+*none*: 0x005b,359
+*none*: 0x005c,360
+SSTORE3: 0x020e,384
+*none*: 0x020f,385
+*none*: 0x0210,386
+*none*: 0x0211,387
+SDOAGAIN: 0x0084,388
+SLMATCH: 0x0085,391
+*none*: 0x0212,389
+SSTORE1: 0x0206,364
+*none*: 0x0207,365
+STYPE1: 0x0078,367
+*none*: 0x0079,368
+*none*: 0x007a,369
+*none*: 0x007b,370
+*none*: 0x007c,371
+*none*: 0x0027,392
+*none*: 0x0107,393
+*none*: 0x0213,394
+*none*: 0x0214,395
+*none*: 0x0215,397
+*none*: 0x0008,398
+*none*: 0x00d4,401
+SUMATCH: 0x00d5,403
+*none*: 0x0108,402
+*none*: 0x00e2,140
+*none*: 0x01a2,141
+Delay1: 0x01a3,143
+*none*: 0x01a4,144
+Delay2: 0x006b,146
+*none*: 0x006a,145
+*none*: 0x01a5,147
+*none*: 0x01a6,148
+*none*: 0x009c,149
+RUNL1: 0x009d,151
+*none*: 0x01a7,152
+RunTest1: 0x0070,154
+*none*: 0x0071,155
+*none*: 0x0072,156
+*none*: 0x0073,157
+RUNLIST2: 0x01a8,160
+*none*: 0x0023,161
+*none*: 0x00e3,164
+*none*: 0x01a9,165
+*none*: 0x0024,166
+CHECK: 0x0216,421
+*none*: 0x0081,422
+*none*: 0x0101,423
+*none*: 0x0217,425
+*none*: 0x0218,426
+*none*: 0x0028,428
+*none*: 0x0029,429
+*none*: 0x002a,430
+*none*: 0x002b,431
+*none*: 0x002c,432
+CHECK2: 0x021e,446
+*none*: 0x021f,447
+*none*: 0x0220,448
+CHECKENTRY: 0x0221,450
+*none*: 0x0222,451
+*none*: 0x0086,452
+DATAERR: 0x0087,471
+*none*: 0x0223,454
+CDOAGAIN: 0x00d6,455
+CLMATCH: 0x00d7,458
+*none*: 0x0224,456
+CHECK1: 0x0219,434
+*none*: 0x021a,435
+CTYPE1: 0x00d8,437
+*none*: 0x00d9,438
+*none*: 0x00da,439
+*none*: 0x00db,440
+*none*: 0x00dc,441
+*none*: 0x0225,459
+*none*: 0x0226,462
+*none*: 0x0042,463
+CDOAGAIN1: 0x0088,466
+CUMATCH: 0x0089,469
+*none*: 0x0102,467
+*none*: 0x00e4,168
+*none*: 0x01aa,169
+*none*: 0x01ab,170
+RUNLIST4X: 0x00e6,184
+*none*: 0x01b2,185
+*none*: 0x01b3,186
+*none*: 0x01b4,188
+TYPE0: 0x006c,190
+TYPE1: 0x006d,191
+TYPE3: 0x01b5,193
+DATAINC: 0x01b6,197
+*none*: 0x01b7,198
+*none*: 0x01b8,199
+*none*: 0x01b9,201
+*none*: 0x01ba,202
+*none*: 0x01bb,203
+*none*: 0x01bc,205
+*none*: 0x01bd,206
+*none*: 0x01be,207
+*none*: 0x01bf,208
+*none*: 0x01c0,209
+CHECKPASS: 0x01c1,212
+*none*: 0x01c2,213
+PASSDONE1: 0x0099,216
+*none*: 0x00e7,172
+*none*: 0x01ac,173
+*none*: 0x01ad,174
+*none*: 0x01ae,177
+*none*: 0x01af,178
+*none*: 0x0026,179
+MAP: 0x0229,498
+*none*: 0x022a,499
+*none*: 0x022b,500
+MAPOFF: 0x00f0,502
+MAPON: 0x00f1,505
+MDOAGAIN: 0x00f2,517
+*none*: 0x0233,518
+*none*: 0x0234,520
+*none*: 0x0235,521
+*none*: 0x0236,522
+*none*: 0x0237,524
+*none*: 0x0238,525
+*none*: 0x0239,526
+MAP2: 0x022d,508
+*none*: 0x022e,509
+*none*: 0x022f,510
+MAPENTRY: 0x0230,512
+*none*: 0x0231,513
+*none*: 0x008a,514
+MDATAERR: 0x008b,543
+*none*: 0x0232,516
+MLMATCH: 0x00f3,529
+*none*: 0x023a,530
+*none*: 0x023b,532
+*none*: 0x023c,533
+MDOAGAIN1: 0x008c,536
+MUMATCH: 0x008d,540
+*none*: 0x023d,537
+*none*: 0x021b,442
+*none*: 0x021c,443
+*none*: 0x021d,444
+TERROR1: 0x00df,63
+*none*: 0x0208,372
+*none*: 0x0209,373
+*none*: 0x020a,374
+SSTORE2: 0x020b,380
+*none*: 0x020c,381
+*none*: 0x020d,382
+
+[MoonCPMemDisplay.mc,v]
+DisplayStart: 0x0030,81
+
+[MoonCPMemKernel.mc,v]
+KernelStart: 0x003c,40
+
diff --git a/D/CP/Source/FloppyInitial_map.txt b/D/CP/Source/FloppyInitial_map.txt
new file mode 100644
index 0000000..9fcca64
--- /dev/null
+++ b/D/CP/Source/FloppyInitial_map.txt
@@ -0,0 +1,263 @@
+#
+ # This file maps assembly source symbols to PROM/microcode addresses and source lines, forming a crude
+ # symbol table.
+ #
+ # Each source file is given a header a la:
+ # [FooSource.asm]
+ # (with brackets)
+
+ # Each line's syntax is:
+ # , .. , : ,
+ # where '*none*' is a special symbol name meaning no symbol mapping is present.
+[CoreInitial.mc,v]
+*none*: 0x01f2,179
+*none*: 0x01f1,178
+*none*: 0x01f0,177
+*none*: 0x01ef,176
+*none*: 0x01f3,180
+*none*: 0x01f4,181
+largeVMOK: 0x01f5,187
+*none*: 0x01f6,188
+*none*: 0x01f7,189
+*none*: 0x01f8,191
+*none*: 0x010a,192
+*none*: 0x01f9,193
+*none*: 0x01ee,171
+*none*: 0x01ec,169
+*none*: 0x01ed,170
+*none*: 0x01eb,166
+*none*: 0x01ea,165
+*none*: 0x01e9,164
+mapBuild: 0x01e8,163
+go: 0x01b1,51
+*none*: 0x012f,52
+*none*: 0x01b2,55
+*none*: 0x01b3,66
+*none*: 0x01b4,67
+*none*: 0x01b5,68
+*none*: 0x01b6,69
+*none*: 0x01b7,70
+*none*: 0x01b8,71
+*none*: 0x01d8,140
+mapInit: 0x01d7,139
+*none*: 0x01d9,141
+*none*: 0x01da,142
+*none*: 0x01db,143
+*none*: 0x01dc,144
+*none*: 0x01dd,145
+*none*: 0x01de,146
+mark1: 0x01e0,151
+*none*: 0x01e1,152
+*none*: 0x011c,153
+*none*: 0x01e2,154
+*none*: 0x0108,155
+*none*: 0x01e3,156
+*none*: 0x01e4,157
+*none*: 0x01e5,158
+*none*: 0x01e6,159
+*none*: 0x01e7,160
+markPages: 0x0109,149
+*none*: 0x01df,150
+BLT: 0x0231,324
+*none*: 0x0232,325
+*none*: 0x0233,326
+*none*: 0x0228,299
+*none*: 0x0229,300
+*none*: 0x0124,298
+*none*: 0x0125,302
+*none*: 0x022a,303
+*none*: 0x022b,304
+clearLoop: 0x0134,290
+*none*: 0x0135,306
+*none*: 0x01b9,77
+*none*: 0x01ba,78
+*none*: 0x01bb,79
+*none*: 0x01bc,80
+*none*: 0x01bd,81
+clear: 0x0114,83
+*none*: 0x01be,84
+*none*: 0x01bf,85
+*none*: 0x0115,87
+*none*: 0x01c0,88
+*none*: 0x01c1,89
+*none*: 0x01c2,94
+*none*: 0x01c3,95
+*none*: 0x01c4,98
+*none*: 0x01c5,99
+*none*: 0x01c6,100
+*none*: 0x01c7,101
+*none*: 0x01c8,103
+*none*: 0x01c9,104
+*none*: 0x01ca,105
+SetVMMSize: 0x01cb,107
+*none*: 0x01cc,108
+*none*: 0x01cd,109
+*none*: 0x01ce,111
+*none*: 0x01cf,112
+enableIOP: 0x01d0,113
+*none*: 0x01d1,115
+*none*: 0x01d2,116
+*none*: 0x01d3,117
+*none*: 0x01d4,120
+*none*: 0x01d5,121
+*none*: 0x01d6,122
+
+[InitDLion.mc,v]
+OnceOnlyINit: 0x0101,66
+*none*: 0x010b,67
+*none*: 0x010e,78
+*none*: 0x011a,79
+*none*: 0x010f,89
+*none*: 0x011e,90
+*none*: 0x0128,92
+*none*: 0x0129,93
+*none*: 0x012b,94
+*none*: 0x012c,96
+*none*: 0x012d,97
+*none*: 0x012e,98
+*none*: 0x013a,100
+*none*: 0x013b,101
+*none*: 0x013c,102
+*none*: 0x013d,104
+*none*: 0x013e,105
+*none*: 0x013f,106
+*none*: 0x0140,108
+*none*: 0x0141,109
+*none*: 0x0142,110
+*none*: 0x0143,112
+*none*: 0x0144,113
+*none*: 0x0145,114
+*none*: 0x0146,116
+*none*: 0x0147,117
+*none*: 0x0148,118
+*none*: 0x0149,120
+*none*: 0x014a,121
+*none*: 0x014b,122
+IOPageLoop: 0x0111,126
+*none*: 0x014c,127
+*none*: 0x014d,128
+EtherInit: 0x0113,131
+*none*: 0x014e,132
+*none*: 0x014f,133
+*none*: 0x0150,135
+*none*: 0x0151,136
+*none*: 0x0152,137
+*none*: 0x0153,139
+*none*: 0x0154,140
+*none*: 0x0155,141
+MagTapeInit: 0x0156,144
+*none*: 0x0157,145
+*none*: 0x0158,146
+DiskInit: 0x0159,149
+*none*: 0x015a,150
+SAx000: 0x0117,153
+*none*: 0x015b,156
+*none*: 0x015c,157
+*none*: 0x015d,158
+*none*: 0x015e,161
+*none*: 0x015f,162
+*none*: 0x0160,163
+*none*: 0x0161,165
+SetSA1Const: 0x0102,177
+*none*: 0x0165,178
+*none*: 0x0166,181
+*none*: 0x0167,182
+SetURegs: 0x0168,183
+*none*: 0x0169,186
+*none*: 0x016a,187
+*none*: 0x016b,188
+DisplayInit: 0x018d,273
+*none*: 0x018e,274
+*none*: 0x018f,275
+*none*: 0x0190,277
+*none*: 0x0191,278
+*none*: 0x0192,279
+*none*: 0x0193,281
+*none*: 0x0194,282
+*none*: 0x0195,283
+*none*: 0x0196,285
+*none*: 0x0197,286
+*none*: 0x0198,287
+*none*: 0x0199,289
+*none*: 0x019a,290
+*none*: 0x019b,291
+*none*: 0x019c,293
+*none*: 0x019d,294
+*none*: 0x019e,295
+*none*: 0x019f,297
+*none*: 0x01a0,298
+*none*: 0x01a1,299
+*none*: 0x01a2,301
+*none*: 0x01a3,302
+*none*: 0x01a4,303
+*none*: 0x01a5,305
+*none*: 0x01a6,306
+*none*: 0x01a7,307
+*none*: 0x01a8,309
+*none*: 0x01a9,310
+LSepInit: 0x01aa,311
+*none*: 0x01ab,313
+*none*: 0x01ac,314
+*none*: 0x01ad,315
+*none*: 0x01ae,317
+*none*: 0x01af,318
+*none*: 0x01b0,319
+
+[FloppyInitial.mc,v]
+DoneOnceOnlyInit: 0x0244,50
+*none*: 0x0245,51
+*none*: 0x0246,52
+clearBank0: 0x0126,54
+*none*: 0x0247,55
+*none*: 0x0248,56
+GFT: 0x0127,60
+*none*: 0x0249,61
+*none*: 0x024a,62
+*none*: 0x024b,64
+*none*: 0x024c,65
+*none*: 0x0112,66
+*none*: 0x024d,68
+*none*: 0x024e,69
+*none*: 0x024f,70
+Remap: 0x0138,73
+*none*: 0x0250,74
+*none*: 0x0116,75
+DoneRemap: 0x0139,80
+*none*: 0x0251,81
+*none*: 0x0252,82
+
+[IOP.mc,v]
+IOPIdle: 0x0027,86
+*none*: 0x005f,87
+*none*: 0x002c,88
+CReadMem: 0x0021,158
+IOPSubc2: 0x0069,323
+*none*: 0x006a,324
+*none*: 0x006b,327
+*none*: 0x006c,328
+*none*: 0x006d,329
+*none*: 0x006e,332
+*none*: 0x006f,333
+*none*: 0x0070,334
+IOPSub2: 0x0022,339
+*none*: 0x0071,340
+*none*: 0x0072,341
+*none*: 0x0073,344
+*none*: 0x0013,345
+*none*: 0x0011,160
+RFirst: 0x0046,165
+*none*: 0x0047,166
+*none*: 0x0031,167
+RLoByte: 0x0048,172
+IOPSubc1: 0x0020,322
+*none*: 0x0010,102
+*none*: 0x002d,106
+*none*: 0x002e,107
+WLo3: 0x0019,119
+WHiByte: 0x002f,112
+*none*: 0x0030,113
+*none*: 0x003c,114
+WLo3Last: 0x003d,123
+WLo: 0x0032,117
+*none*: 0x0034,118
+
diff --git a/D/CP/Source/Main_map.txt b/D/CP/Source/Main_map.txt
new file mode 100644
index 0000000..e34ecd0
--- /dev/null
+++ b/D/CP/Source/Main_map.txt
@@ -0,0 +1,572 @@
+#
+ # This file maps assembly source symbols to PROM/microcode addresses and source lines, forming a crude
+ # symbol table.
+ #
+ # Each source file is given a header a la:
+ # [FooSource.asm]
+ # (with brackets)
+
+ # Each line's syntax is:
+ # , .. , : ,
+ # where '*none*' is a special symbol name meaning no symbol mapping is present.
+[IOPMain.mc,v]
+IOPIdle: 0x0ecc,57
+*none*: 0x014f,58
+IOPNoop: 0x061c,289
+*none*: 0x0c7f,61
+*none*: 0x0404,62
+*none*: 0x0c74,65
+*none*: 0x0ecd,66
+*none*: 0x0ece,67
+*none*: 0x04a5,71
+rTmpLRot8: 0x0226,287
+*none*: 0x0c75,75
+*none*: 0x0c76,79
+*none*: 0x0ecf,80
+CalculateLast: 0x0ed3,117
+*none*: 0x0ed4,118
+TestCarry: 0x0ed5,120
+MapLast: 0x092e,134
+*none*: 0x0ed7,135
+*none*: 0x0ed8,136
+*none*: 0x0ed9,141
+*none*: 0x0eda,142
+*none*: 0x0edb,143
+*none*: 0x0edc,145
+*none*: 0x0edd,146
+*none*: 0x0ede,147
+*none*: 0x0c70,178
+MapVirt3: 0x0890,180
+*none*: 0x0ee5,183
+*none*: 0x0ee6,184
+*none*: 0x0ee7,185
+*none*: 0x0ee8,190
+*none*: 0x0ee9,191
+*none*: 0x061a,192
+WriteBlock: 0x07ca,201
+*none*: 0x0eea,202
+*none*: 0x0942,203
+WriteBlockLoop: 0x0eeb,206
+*none*: 0x0eec,207
+*none*: 0x0699,208
+WritePageCross: 0x069a,232
+
+[MultiBankStartMesa.mc,v]
+*none*: 0x07fc,83
+*none*: 0x07fd,84
+SetMDS: 0x0aff,89
+*none*: 0x0dea,90
+*none*: 0x0deb,92
+*none*: 0x0dec,98
+*none*: 0x0ded,99
+*none*: 0x0dee,101
+*none*: 0x0def,102
+*none*: 0x0df0,103
+*none*: 0x0df1,118
+*none*: 0x0df2,119
+*none*: 0x0df3,120
+*none*: 0x0df4,122
+*none*: 0x0df5,123
+*none*: 0x0df6,124
+*none*: 0x0df7,127
+*none*: 0x0df8,128
+*none*: 0x0df9,129
+*none*: 0x0dfa,131
+*none*: 0x0904,132
+*none*: 0x0dfb,133
+KeyDone: 0x0905,149
+*none*: 0x0dfc,150
+*none*: 0x0dfd,154
+*none*: 0x0dfe,155
+*none*: 0x0dff,156
+LastChance: 0x0e00,159
+*none*: 0x0e01,160
+*none*: 0x0e02,161
+
+[Xfer.mc,v]
+XFER: 0x0b22,484
+XferIndirect: 0x042e,517
+*none*: 0x0d8d,518
+*none*: 0x018c,520
+*none*: 0x0701,521
+XReadx: 0x07e1,969
+XReady: 0x09f1,971
+XReadz: 0x0903,972
+*none*: 0x04da,973
+*none*: 0x038c,523
+*none*: 0x0d8e,524
+*none*: 0x0d8f,525
+*none*: 0x0d90,527
+*none*: 0x042c,488
+*none*: 0x0d85,489
+*none*: 0x08e6,491
+ControlTrap: 0x08e7,743
+*none*: 0x02d7,744
+TH1: 0x0dc4,745
+TH: 0x0dc9,756
+*none*: 0x0dca,757
+Tha: 0x0920,758
+*none*: 0x0dcb,760
+THb: 0x0788,761
+THc: 0x0dcc,765
+*none*: 0x0dcd,767
+*none*: 0x0dce,768
+*none*: 0x0dcf,769
+THx: 0x0619,775
+*none*: 0x0dd2,776
+*none*: 0x0dd3,777
+THd: 0x0330,779
+*none*: 0x08a1,780
+TrapGo: 0x007a,782
+*none*: 0x07fa,784
+*none*: 0x0dd4,785
+*none*: 0x0dd5,786
+*none*: 0x0dd6,788
+KFCBa: 0x0d5e,276
+*none*: 0x0d5f,277
+*none*: 0x0d60,279
+*none*: 0x0402,280
+GLe: 0x0ddc,894
+*none*: 0x04fc,896
+*none*: 0x020c,897
+*none*: 0x020d,898
+*none*: 0x0ddd,899
+*none*: 0x0dde,901
+GLc: 0x0443,902
+*none*: 0x04d2,903
+XFMUD: 0x0765,493
+StashPC0: 0x0940,842
+*none*: 0x07c1,847
+*none*: 0x0349,848
+*none*: 0x0334,850
+*none*: 0x0635,852
+StShift: 0x0dd8,855
+*none*: 0x0dd9,856
+StashPCb: 0x04d0,859
+*none*: 0x027a,860
+*none*: 0x0767,495
+*none*: 0x0d86,496
+*none*: 0x020a,498
+*none*: 0x0d87,499
+*none*: 0x0d88,500
+LGC: 0x0dae,656
+LGCx: 0x0daf,657
+*none*: 0x022a,658
+SameG: 0x04fb,701
+*none*: 0x033d,702
+sgOdd: 0x048e,703
+sgEven: 0x048f,704
+sg: 0x0dbe,706
+*none*: 0x0dbf,707
+*none*: 0x07f8,709
+sgY: 0x07f9,708
+UnboundTrap: 0x09fd,748
+*none*: 0x062b,749
+*none*: 0x0dc5,750
+*none*: 0x0dc6,752
+*none*: 0x0dc7,753
+*none*: 0x0dc8,754
+XferProc3: 0x042f,545
+*none*: 0x018d,547
+XNPa: 0x07f0,549
+*none*: 0x04fa,660
+LGCb: 0x07f5,663
+*none*: 0x0db0,664
+*none*: 0x0db1,666
+*none*: 0x04a6,667
+*none*: 0x0db2,668
+XCa: 0x08ec,671
+*none*: 0x0db3,672
+*none*: 0x0adf,674
+xcOdd: 0x0ade,673
+XMapG: 0x0db4,676
+*none*: 0x0db5,677
+*none*: 0x0db6,678
+*none*: 0x0db7,680
+LGCd: 0x07f7,682
+*none*: 0x0db8,683
+*none*: 0x0db9,685
+*none*: 0x0dba,686
+*none*: 0x0dbb,687
+*none*: 0x026e,689
+*none*: 0x0dbc,690
+*none*: 0x0dbd,691
+*none*: 0x09fe,693
+XCe: 0x08ef,694
+XCd: 0x08ee,698
+*none*: 0x01bb,696
+*none*: 0x01ba,695
+XAlloc: 0x02ad,552
+AllocSub: 0x0483,925
+*none*: 0x0347,926
+Alloc1: 0x0217,928
+AllocMUD1: 0x07a5,952
+*none*: 0x07a7,929
+*none*: 0x0de1,930
+*none*: 0x0de2,932
+AV0: 0x04cc,933
+*none*: 0x0368,934
+*none*: 0x0218,936
+*none*: 0x0655,953
+*none*: 0x0657,937
+*none*: 0x0de3,938
+*none*: 0x0de4,940
+*none*: 0x04d8,941
+*none*: 0x003d,554
+*none*: 0x0d92,556
+*none*: 0x0d93,557
+*none*: 0x0d94,558
+*none*: 0x0d95,560
+XPCalI: 0x032e,564
+XPSD: 0x0d9a,579
+*none*: 0x0d9b,581
+*none*: 0x04b6,582
+XferDone: 0x044e,617
+XTail: 0x0da3,619
+*none*: 0x0616,620
+
+[CommonSubs.mc,v]
+WMapFix: 0x07df,83
+*none*: 0x0160,84
+WMaps: 0x0354,86
+WMapb: 0x02d4,91
+*none*: 0x0acd,247
+*none*: 0x0710,246
+*none*: 0x0ace,248
+*none*: 0x000a,249
+
+[Write.mc,v]
+W: 0x0211,83
+*none*: 0x0463,84
+WMUD: 0x0461,86
+
+[LoadStore.mc,v]
+SLa: 0x0669,296
+*none*: 0x0504,185
+LLn: 0x00c6,195
+LLa: 0x00e1,196
+LLb: 0x00e2,197
+@@PLDB: 0x0533,270
+*none*: 0x0240,271
+PLDBa: 0x0359,272
+PLDB2: 0x0b14,275
+PLBx: 0x0125,254
+PLa: 0x04e9,255
+
+[Refill.mc,v]
+OpTable: 0x0500,126
+*none*: 0x0c78,127
+NoRCross: 0x0248,130
+RefillE: 0x0400,119
+*none*: 0x0228,120
+*none*: 0x016f,281
+*none*: 0x0740,282
+StackErr: 0x0492,299
+DISPNIonly: 0x0c85,261
+UpdatePC: 0x012f,156
+*none*: 0x0c79,157
+*none*: 0x0149,158
+RReMap: 0x0c7a,160
+*none*: 0x0471,161
+JRedo: 0x09ff,189
+*none*: 0x0889,190
+*none*: 0x0476,191
+ECross: 0x03c0,166
+JCross: 0x03cf,187
+
+[Misc.mc,v]
+@@ESC: 0x05f8,70
+*none*: 0x0b37,71
+*none*: 0x08b7,79
+@@WRMP: 0x0a67,349
+*none*: 0x0b5d,350
+*none*: 0x0b68,351
+*none*: 0x0b6a,353
+*none*: 0x0b6b,354
+@@WRWDC: 0x0a63,333
+WRx: 0x0b53,311
+*none*: 0x08b1,73
+*none*: 0x08b0,72
+@@GMF: 0x08f9,261
+*none*: 0x0161,262
+SMFa: 0x02c0,229
+*none*: 0x0b46,231
+*none*: 0x0b47,232
+*none*: 0x0b48,233
+*none*: 0x0b49,235
+*none*: 0x0b4a,236
+*none*: 0x0b4b,237
+*none*: 0x0b4c,238
+*none*: 0x06c4,240
+*none*: 0x0433,246
+*none*: 0x0b4d,248
+*none*: 0x0b4e,249
+*none*: 0x0b4f,250
+*none*: 0x0392,252
+GMFa: 0x0719,264
+SMFd: 0x0718,253
+*none*: 0x0b50,254
+SMd: 0x0b44,211
+*none*: 0x03ae,218
+ESC0n: 0x08f0,93
+@@SM: 0x08f7,199
+*none*: 0x0b3a,200
+*none*: 0x0b3b,201
+*none*: 0x0b3c,203
+*none*: 0x0b3d,204
+*none*: 0x0b3e,205
+*none*: 0x0b41,207
+*none*: 0x0b42,208
+*none*: 0x0b43,209
+SMc: 0x03a8,212
+@@SMF: 0x08f8,227
+*none*: 0x0b45,228
+*none*: 0x08b8,80
+@@INPUT: 0x0910,271
+*none*: 0x0b51,272
+*none*: 0x0a83,276
+
+[Stack.mc,v]
+@@DSHIFT: 0x0857,401
+*none*: 0x0cc1,402
+DSa: 0x079c,415
+*none*: 0x02a2,417
+*none*: 0x0cc3,418
+DSc: 0x08a6,407
+*none*: 0x047a,409
+*none*: 0x049a,412
+@@UDCMP: 0x05be,576
+*none*: 0x0ce2,577
+comp: 0x0ce3,578
+*none*: 0x0ce4,580
+CHighNE: 0x08ae,582
+CompG: 0x07b9,585
+
+[Jump.mc,v]
+@@JGEB: 0x0591,292
+*none*: 0x0adc,293
+*none*: 0x0ae4,303
+jNoOv: 0x03d6,305
+jOv: 0x03d7,306
+jc22: 0x000c,201
+jT: 0x0716,422
+jF: 0x0717,423
+NoJUmp: 0x0033,474
+jPop2Incr2: 0x089d,479
+@@JB: 0x0588,137
+*none*: 0x0180,138
+JPosOdd: 0x0609,428
+JPos: 0x0af6,434
+jnPNoCross: 0x0119,439
+JPtr1Pop0: 0x0872,459
+Jgo: 0x0af9,469
+*none*: 0x06ab,430
+@@JIW: 0x05a1,361
+*none*: 0x00a4,362
+jiCom: 0x0aee,365
+*none*: 0x0aef,367
+*none*: 0x0714,368
+*none*: 0x004d,369
+*none*: 0x01e0,371
+*none*: 0x0af0,372
+*none*: 0x0af1,373
+*none*: 0x0af2,376
+*none*: 0x0af3,377
+*none*: 0x0af4,378
+jiRedo: 0x04fd,380
+*none*: 0x0805,381
+*none*: 0x0350,382
+jibL: 0x0332,384
+ji: 0x012e,388
+jwPos: 0x04c9,148
+*none*: 0x0ad3,151
+jwOdd: 0x03d3,154
+jwCross: 0x0ad4,157
+JPtr0Pop2: 0x087f,467
+jiwL: 0x0336,386
+
+[DiskDlionA.mc,v]
+GetCSB: 0x0ef8,84
+*none*: 0x070f,85
+*none*: 0x0ef9,86
+*none*: 0x0efa,89
+*none*: 0x0efb,91
+*none*: 0x00ba,93
+NewIOCB: 0x0efc,97
+*none*: 0x0efd,98
+GoodIOCB: 0x0946,100
+*none*: 0x0947,101
+StartIOCB: 0x0efe,105
+*none*: 0x0eff,106
+*none*: 0x0f00,108
+GetCmd: 0x08d0,111
+GetCmdC2: 0x0f01,112
+GetCmdC3: 0x0346,113
+FetArg: 0x074f,118
+SameC2s: 0x0158,123
+SendCtlWd: 0x0159,153
+*none*: 0x0386,156
+SameC3s: 0x0366,124
+Inr: 0x0768,133
+*none*: 0x0f02,135
+*none*: 0x0f03,136
+*none*: 0x0f04,139
+*none*: 0x0f05,140
+IncBr: 0x0f06,141
+DoInc: 0x08d1,145
+FinLdReg: 0x0f1d,247
+LoadPr: 0x076d,162
+LoadRCLpC2: 0x0f08,170
+LoadRCLpC3: 0x06c2,172
+LoadRCLp: 0x0f07,168
+StartRALp: 0x06c3,176
+LoadRALp: 0x0f09,179
+LoadRALpC2: 0x0f0a,182
+LoadRALpC3: 0x06ba,184
+FinLd: 0x06bb,186
+*none*: 0x0f0b,188
+*none*: 0x0f0c,189
+*none*: 0x0f0d,196
+*none*: 0x0f0e,198
+*none*: 0x0f0f,199
+SaveHeadSect: 0x0948,206
+IsHeaderRead: 0x0949,202
+*none*: 0x0f10,210
+*none*: 0x0f11,213
+LdHeadSectC3: 0x03a6,214
+SetUHeadSect: 0x0f12,217
+FixupDone: 0x0f13,220
+*none*: 0x0f14,221
+*none*: 0x0f15,223
+SavePgNum: 0x08d2,228
+IsLabelRead: 0x08d3,225
+FormHdNotOkMsk: 0x0f1b,243
+*none*: 0x0f1c,244
+*none*: 0x015a,255
+*none*: 0x03c6,256
+NewSector: 0x094a,258
+*none*: 0x0f1e,259
+*none*: 0x0f1f,260
+*none*: 0x0f20,262
+*none*: 0x0f21,263
+*none*: 0x0f22,264
+NewHeader: 0x08d4,267
+*none*: 0x0f23,269
+*none*: 0x0a40,270
+HeaderRet: 0x0050,273
+*none*: 0x0f24,275
+*none*: 0x0f25,276
+HeaderWrong: 0x094c,278
+DoLabel: 0x094d,295
+*none*: 0x0f2a,296
+*none*: 0x0f2b,297
+*none*: 0x0f2c,299
+*none*: 0x0f2d,300
+*none*: 0x0861,301
+LabelRet: 0x0051,304
+*none*: 0x0f2e,305
+*none*: 0x0f2f,306
+DoData: 0x094f,318
+LabelQuit: 0x094e,315
+*none*: 0x0f30,320
+NoIncrDatPtr: 0x06f2,322
+IncrDatPtr: 0x06f3,323
+MapDataAddr: 0x0f31,326
+*none*: 0x0f32,329
+GetPhysDatAddr: 0x0406,331
+*none*: 0x0f33,335
+*none*: 0x0f34,336
+*none*: 0x0602,337
+*none*: 0x0f26,280
+*none*: 0x0f27,281
+TstSeenAll: 0x08d7,287
+HeaderQuit: 0x08d6,284
+*none*: 0x0f28,288
+*none*: 0x0f29,289
+NotFound: 0x08d5,292
+
+[DiskDlionB.mc,v]
+InitRegs: 0x076f,321
+*none*: 0x0f7b,322
+*none*: 0x0f7c,323
+*none*: 0x0f7d,325
+FinishIOCB: 0x076e,233
+*none*: 0x0f61,235
+*none*: 0x01fa,237
+*none*: 0x0f62,240
+*none*: 0x0f63,241
+*none*: 0x021a,242
+*none*: 0x0f64,245
+*none*: 0x0f65,246
+*none*: 0x0f66,247
+*none*: 0x0f67,250
+*none*: 0x0f68,251
+*none*: 0x0f69,252
+ComposeStat: 0x096b,263
+*none*: 0x0f6c,264
+*none*: 0x0f6d,268
+*none*: 0x0f6e,271
+*none*: 0x0f70,272
+*none*: 0x0f71,273
+*none*: 0x0f72,276
+*none*: 0x0f73,277
+MemError: 0x07ef,279
+LastIOCB: 0x0973,286
+ResetFirmwareBusy: 0x096d,291
+GetIntrMask: 0x0f74,300
+*none*: 0x0f75,303
+*none*: 0x0f76,304
+*none*: 0x0f78,305
+*none*: 0x0f79,309
+*none*: 0x0f7a,310
+QuitNow: 0x0cde,313
+TransferField: 0x0f48,87
+*none*: 0x0f49,88
+*none*: 0x0f4a,89
+*none*: 0x0f4b,91
+*none*: 0x0f4c,92
+SetupWrt: 0x0c9f,162
+*none*: 0x0f55,164
+SyncLp2: 0x0f56,169
+*none*: 0x0f57,170
+*none*: 0x0936,168
+FinSync: 0x0937,173
+*none*: 0x0f58,175
+*none*: 0x0f59,177
+SetupHd: 0x0968,181
+MakeSyncAdrMk: 0x0f5a,185
+*none*: 0x0f5b,186
+*none*: 0x0f5c,190
+*none*: 0x0f5d,191
+InitWrtC3: 0x046e,192
+WrtVerLp: 0x0970,197
+WrtVerLpC2: 0x0f5e,198
+WrtVerLpC3: 0x01f2,199
+FinWrtVer: 0x0971,202
+*none*: 0x0f5f,203
+FinWrite: 0x0cbf,207
+FinVerify: 0x0cbe,205
+*none*: 0x06e2,210
+SndWaitC2: 0x0f60,216
+SndWaitC3: 0x02d2,218
+SndWait: 0x07cf,215
+SndFreeze: 0x02d3,222
+SetupRdVer: 0x0c9e,101
+*none*: 0x0f4d,105
+*none*: 0x0f4e,106
+*none*: 0x0f4f,107
+*none*: 0x0f50,113
+*none*: 0x0f51,118
+StartVer: 0x07af,121
+StartRd: 0x07ad,126
+StartRdC1: 0x08c1,130
+ReadLpC2: 0x08dc,137
+ReadLpC3: 0x046a,138
+ReadLp: 0x0f52,136
+FinRead: 0x08dd,147
+FinReadC3: 0x011a,149
+FinReadLp: 0x0f53,152
+RdLastWd: 0x0966,153
+*none*: 0x0f54,154
+FreezeRead: 0x0967,157
+
diff --git a/D/CP/Source/MoonCycle_map.txt b/D/CP/Source/MoonCycle_map.txt
new file mode 100644
index 0000000..a9ae4a9
--- /dev/null
+++ b/D/CP/Source/MoonCycle_map.txt
@@ -0,0 +1,89 @@
+#
+ # This file maps assembly source symbols to PROM/microcode addresses and source lines, forming a crude
+ # symbol table.
+ #
+ # Each source file is given a header a la:
+ # [FooSource.asm]
+ # (with brackets)
+
+ # Each line's syntax is:
+ # , .. , : ,
+ # where '*none*' is a special symbol name meaning no symbol mapping is present.
+[MoonCycle.mc,v]
+START: 0x0090,155
+*none*: 0x011f,156
+*none*: 0x0091,157
+*none*: 0x0092,159
+*none*: 0x0093,160
+*none*: 0x0094,161
+*none*: 0x0095,163
+*none*: 0x0096,164
+*none*: 0x0097,165
+*none*: 0x0098,167
+*none*: 0x0099,168
+*none*: 0x009a,169
+*none*: 0x009b,171
+*none*: 0x009c,172
+START1: 0x0036,173
+START2: 0x0037,174
+START3: 0x009d,178
+*none*: 0x009e,179
+*none*: 0x0020,180
+Delay: 0x0052,304
+*none*: 0x00c9,305
+*none*: 0x00ca,306
+DelENRET: 0x0053,308
+*none*: 0x00cb,309
+*none*: 0x0017,310
+Task1: 0x0055,40
+Task2: 0x0067,62
+Task3: 0x0071,84
+Task4: 0x007b,106
+Task5: 0x0086,128
+*none*: 0x0010,182
+*none*: 0x00a0,183
+*none*: 0x0040,184
+CkRZero: 0x00c7,291
+*none*: 0x00c8,292
+ErrorTask1: 0x002d,298
+*none*: 0x002c,293
+ErrorTask2: 0x003b,299
+*none*: 0x003a,294
+ErrorTask3: 0x002f,300
+*none*: 0x002e,295
+ErrorTask4: 0x0051,301
+*none*: 0x0050,296
+ErrorTask5: 0x0043,302
+CkENRET: 0x0042,312
+*none*: 0x00cc,313
+*none*: 0x001e,314
+*none*: 0x0060,187
+*none*: 0x00a1,188
+*none*: 0x0001,189
+*none*: 0x005f,41
+*none*: 0x0056,42
+Task1A: 0x0018,44
+Task1B: 0x0019,48
+*none*: 0x0059,49
+*none*: 0x005a,50
+Task1C: 0x0008,52
+*none*: 0x005b,53
+*none*: 0x005c,54
+Task1D: 0x0009,56
+*none*: 0x005d,57
+*none*: 0x005e,58
+*none*: 0x0057,45
+*none*: 0x0058,46
+*none*: 0x0011,191
+*none*: 0x00a2,192
+*none*: 0x0021,193
+*none*: 0x0061,196
+*none*: 0x00a3,197
+*none*: 0x0002,198
+*none*: 0x0012,200
+*none*: 0x00a4,201
+*none*: 0x0022,202
+*none*: 0x0062,205
+*none*: 0x00a5,206
+*none*: 0x0003,207
+
diff --git a/D/CP/Source/MoonEthBTest_map.txt b/D/CP/Source/MoonEthBTest_map.txt
new file mode 100644
index 0000000..360169f
--- /dev/null
+++ b/D/CP/Source/MoonEthBTest_map.txt
@@ -0,0 +1,267 @@
+#
+ # This file maps assembly source symbols to PROM/microcode addresses and source lines, forming a crude
+ # symbol table.
+ #
+ # Each source file is given a header a la:
+ # [FooSource.asm]
+ # (with brackets)
+
+ # Each line's syntax is:
+ # , .. , : ,
+ # where '*none*' is a special symbol name meaning no symbol mapping is present.
+[MoonEthBTest.mc,v]
+CkTest: 0x0074,699
+*none*: 0x00bf,700
+*none*: 0x0196,701
+Go: 0x00a9,123
+*none*: 0x009f,124
+*none*: 0x00aa,125
+*none*: 0x00ab,127
+*none*: 0x00ac,128
+*none*: 0x00ad,129
+Go1: 0x0008,131
+Go2: 0x0009,134
+RunGood: 0x0fff,484
+*none*: 0x00ae,135
+*none*: 0x00af,136
+*none*: 0x00b3,138
+*none*: 0x00b4,139
+*none*: 0x00b5,140
+*none*: 0x00b6,144
+*none*: 0x00b7,145
+*none*: 0x00b8,146
+*none*: 0x00b9,150
+*none*: 0x00ba,151
+*none*: 0x00bb,152
+*none*: 0x00bc,154
+*none*: 0x00bd,155
+*none*: 0x00be,156
+Pause: 0x00c8,159
+*none*: 0x00c9,160
+*none*: 0x00ca,161
+Btest0: 0x00cb,164
+*none*: 0x00cc,165
+*none*: 0x00cd,166
+*none*: 0x00ce,168
+*none*: 0x00cf,169
+*none*: 0x00d3,170
+*none*: 0x00d4,172
+*none*: 0x00d5,173
+Badt0: 0x0014,640
+t0Stop: 0x00e0,641
+Btest1: 0x0015,176
+*none*: 0x00d6,178
+*none*: 0x00d7,179
+*none*: 0x00d8,180
+*none*: 0x00d9,182
+*none*: 0x00da,183
+*none*: 0x00db,184
+Btest2: 0x000d,188
+Badt1: 0x000c,643
+t1Stop: 0x00e1,644
+*none*: 0x00dc,189
+*none*: 0x00dd,190
+*none*: 0x00de,192
+*none*: 0x00e3,193
+*none*: 0x00e4,194
+*none*: 0x00e5,196
+*none*: 0x00e6,197
+*none*: 0x00e7,198
+*none*: 0x00e8,200
+*none*: 0x00e9,201
+*none*: 0x0019,202
+Badt2: 0x0018,646
+t2Stop: 0x00e2,647
+*none*: 0x00ea,204
+*none*: 0x00eb,205
+*none*: 0x0020,206
+FifoCk: 0x00ef,225
+*none*: 0x00f3,226
+*none*: 0x00f4,227
+FifoCk1: 0x0025,229
+*none*: 0x00f5,230
+*none*: 0x00f7,231
+*none*: 0x00f8,233
+*none*: 0x00f9,234
+*none*: 0x00fa,235
+FifoRead: 0x0024,238
+FifoRead1: 0x001a,240
+*none*: 0x00fb,241
+FifoErr: 0x0026,246
+*none*: 0x0027,242
+FifoDone: 0x001b,250
+*none*: 0x003c,251
+*none*: 0x0010,208
+*none*: 0x00ec,209
+*none*: 0x0001,210
+*none*: 0x0011,212
+*none*: 0x0012,216
+*none*: 0x0033,247
+*none*: 0x001e,248
+FifoErr0: 0x0100,649
+*none*: 0x0101,650
+*none*: 0x00ed,213
+*none*: 0x0002,214
+*none*: 0x00ee,218
+*none*: 0x0003,219
+Btest4: 0x0013,258
+*none*: 0x00fc,259
+*none*: 0x00fd,260
+*none*: 0x00a0,263
+*none*: 0x00fe,264
+*none*: 0x0104,265
+*none*: 0x0105,268
+*none*: 0x0106,269
+*none*: 0x0107,270
+*none*: 0x0108,272
+*none*: 0x0109,273
+*none*: 0x0040,274
+MemStore: 0x0173,574
+*none*: 0x0174,575
+*none*: 0x0175,576
+*none*: 0x0176,578
+*none*: 0x0177,579
+Pattern: 0x0070,581
+*none*: 0x0071,582
+Sun1: 0x017b,591
+*none*: 0x017c,592
+*none*: 0x017d,593
+Block: 0x017e,595
+*none*: 0x0072,583
+*none*: 0x0073,584
+ADD1: 0x0178,587
+*none*: 0x017f,596
+*none*: 0x0064,597
+MemDone: 0x0065,600
+*none*: 0x0183,601
+*none*: 0x0184,602
+*none*: 0x009b,603
+*none*: 0x00c0,276
+EndWB3: 0x010a,278
+*none*: 0x010b,281
+*none*: 0x010c,283
+*none*: 0x010d,284
+*none*: 0x0021,285
+*none*: 0x00c1,287
+*none*: 0x010e,288
+*none*: 0x0022,289
+*none*: 0x00c2,293
+ClrFin: 0x00c3,302
+*none*: 0x010f,294
+*none*: 0x0110,295
+ClrBuf: 0x0111,297
+*none*: 0x0112,298
+*none*: 0x0023,299
+*none*: 0x0113,303
+*none*: 0x0114,304
+*none*: 0x0115,306
+*none*: 0x0116,309
+*none*: 0x0117,310
+*none*: 0x0118,311
+*none*: 0x0119,316
+*none*: 0x0060,317
+Delay: 0x0044,488
+*none*: 0x015e,490
+*none*: 0x003a,491
+LLDone: 0x003b,495
+TimeOut: 0x0045,525
+*none*: 0x0075,703
+*none*: 0x0197,704
+DoTst: 0x001c,706
+LoopBkS: 0x0198,713
+*none*: 0x0199,714
+*none*: 0x019a,715
+*none*: 0x019b,718
+*none*: 0x019c,719
+*none*: 0x019d,720
+*none*: 0x019e,722
+*none*: 0x019f,723
+*none*: 0x01a0,724
+*none*: 0x01a1,726
+*none*: 0x01a2,727
+*none*: 0x01a3,728
+*none*: 0x01a4,730
+*none*: 0x01a5,731
+*none*: 0x01a6,732
+*none*: 0x01a7,734
+*none*: 0x01a8,737
+LData: 0x000e,738
+LbpLoop: 0x0068,736
+*none*: 0x0069,740
+*none*: 0x01a9,741
+*none*: 0x01aa,742
+*none*: 0x01ab,744
+*none*: 0x01ac,745
+*none*: 0x01ad,746
+Wait: 0x0078,761
+*none*: 0x01b3,762
+*none*: 0x006a,763
+AttenUp: 0x006b,766
+*none*: 0x007a,768
+*none*: 0x01b4,769
+*none*: 0x01b5,770
+ToReTry: 0x006d,774
+*none*: 0x006c,772
+ReTryA: 0x01ae,752
+T7Time: 0x007b,779
+ReadSt: 0x01b6,780
+*none*: 0x01b7,781
+*none*: 0x01b8,783
+*none*: 0x007c,784
+T7Attn1: 0x006f,788
+*none*: 0x006e,785
+TrnBad: 0x01b9,793
+LoopRec: 0x01bc,798
+*none*: 0x01bd,799
+*none*: 0x01be,800
+*none*: 0x01bf,802
+GetWd: 0x0082,805
+RData: 0x00df,806
+AddWd: 0x01c0,804
+*none*: 0x0043,498
+*none*: 0x015f,499
+*none*: 0x0054,501
+*none*: 0x0163,503
+*none*: 0x0046,505
+*none*: 0x0164,506
+CkLoop: 0x0056,508
+*none*: 0x0165,509
+*none*: 0x0166,512
+StatusBad: 0x0048,561
+*none*: 0x0053,562
+*none*: 0x0098,563
+Badt44: 0x00d0,670
+*none*: 0x0049,515
+*none*: 0x0059,517
+*none*: 0x0167,518
+*none*: 0x004b,519
+*none*: 0x0168,520
+*none*: 0x003e,521
+CkLoopL: 0x0030,320
+*none*: 0x011a,321
+*none*: 0x0080,322
+MemCheck: 0x0185,606
+*none*: 0x0186,607
+*none*: 0x0187,608
+MemCheck1: 0x0188,610
+*none*: 0x0189,611
+*none*: 0x018a,612
+*none*: 0x018b,614
+*none*: 0x018c,615
+*none*: 0x018d,616
+*none*: 0x018e,618
+*none*: 0x018f,619
+CheckErr: 0x005c,620
+Check: 0x005d,626
+*none*: 0x0192,627
+*none*: 0x0193,628
+*none*: 0x0066,629
+*none*: 0x0067,632
+*none*: 0x0194,633
+*none*: 0x0195,634
+*none*: 0x009d,635
+WdsGood: 0x0050,326
+*none*: 0x011b,327
+*none*: 0x011c,328
+Btest5: 0x00a1,335
+
diff --git a/D/CP/Source/MoonPortIn_map.txt b/D/CP/Source/MoonPortIn_map.txt
new file mode 100644
index 0000000..a0be39c
--- /dev/null
+++ b/D/CP/Source/MoonPortIn_map.txt
@@ -0,0 +1,17 @@
+#
+ # This file maps assembly source symbols to PROM/microcode addresses and source lines, forming a crude
+ # symbol table.
+ #
+ # Each source file is given a header a la:
+ # [FooSource.asm]
+ # (with brackets)
+
+ # Each line's syntax is:
+ # , .. , : ,
+ # where '*none*' is a special symbol name meaning no symbol mapping is present.
+[MoonPortIn.mc,v]
+START1: 0x003f,49
+*none*: 0x0004,50
+Wait: 0x0002,52
+*none*: 0x0005,53
+
diff --git a/D/CP/Source/MoonPortOut_map.txt b/D/CP/Source/MoonPortOut_map.txt
new file mode 100644
index 0000000..8d841a3
--- /dev/null
+++ b/D/CP/Source/MoonPortOut_map.txt
@@ -0,0 +1,27 @@
+#
+ # This file maps assembly source symbols to PROM/microcode addresses and source lines, forming a crude
+ # symbol table.
+ #
+ # Each source file is given a header a la:
+ # [FooSource.asm]
+ # (with brackets)
+
+ # Each line's syntax is:
+ # , .. , : ,
+ # where '*none*' is a special symbol name meaning no symbol mapping is present.
+[MoonPortOut.mc,v]
+*none*: 0x003f,48
+START: 0x0001,46
+*none*: 0x0004,49
+*none*: 0x0005,50
+Wait: 0x0002,52
+*none*: 0x0006,53
+In: 0x0003,55
+*none*: 0x0007,56
+*none*: 0x0008,57
+Bad: 0x0010,59
+*none*: 0x0011,60
+*none*: 0x0009,61
+*none*: 0x000a,62
+Wait1: 0x0ffe,64
+
diff --git a/D/CP/Source/Phase0Protected_map.txt b/D/CP/Source/Phase0Protected_map.txt
new file mode 100644
index 0000000..b79b3e5
--- /dev/null
+++ b/D/CP/Source/Phase0Protected_map.txt
@@ -0,0 +1,42 @@
+#
+ # This file maps assembly source symbols to PROM/microcode addresses and source lines, forming a crude
+ # symbol table.
+ #
+ # Each source file is given a header a la:
+ # [FooSource.asm]
+ # (with brackets)
+
+ # Each line's syntax is:
+ # , .. , : ,
+ # where '*none*' is a special symbol name meaning no symbol mapping is present.
+[Protected.mc,v]
+*none*: 0x001a,77
+Trap: 0x0000,59
+infinite: 0x0001,71
+
+[IOPBoot.mc,v]
+*none*: 0x0020,62
+*none*: 0x005f,63
+*none*: 0x0023,64
+IOPIdle: 0x000d,70
+IOPIdlex: 0x007f,72
+*none*: 0x0026,75
+CReadMem: 0x0009,84
+ReadWordx: 0x0005,185
+Noop1: 0x0014,208
+*none*: 0x0070,187
+*none*: 0x001b,145
+*none*: 0x002e,149
+*none*: 0x0032,150
+*none*: 0x0013,188
+*none*: 0x0019,87
+*none*: 0x0006,90
+Noop2: 0x000b,207
+*none*: 0x0076,95
+*none*: 0x0015,97
+SendAddress: 0x0075,103
+*none*: 0x0021,105
+*none*: 0x0029,106
+RLoByte: 0x0071,113
+*none*: 0x0028,114
+
diff --git a/D/CP/Source/Phase0_map.txt b/D/CP/Source/Phase0_map.txt
new file mode 100644
index 0000000..4347c1c
--- /dev/null
+++ b/D/CP/Source/Phase0_map.txt
@@ -0,0 +1,46 @@
+#
+ # This file maps assembly source symbols to PROM/microcode addresses and source lines, forming a crude
+ # symbol table.
+ #
+ # Each source file is given a header a la:
+ # [FooSource.asm]
+ # (with brackets)
+
+ # Each line's syntax is:
+ # , .. , : ,
+ # where '*none*' is a special symbol name meaning no symbol mapping is present.
+[Phase0.mc,v]
+go: 0x0108,97
+*none*: 0x011f,98
+*none*: 0x0146,99
+clear0: 0x0128,102
+*none*: 0x0148,103
+*none*: 0x014a,104
+Trident/SA: 0x013d,115
+*none*: 0x013c,108
+*none*: 0x014e,109
+*none*: 0x0168,110
+Trident: 0x013f,117
+enableIOP: 0x01ae,127
+*none*: 0x01b0,128
+*none*: 0x01c6,129
+*none*: 0x0130,134
+*none*: 0x01c7,135
+*none*: 0x01c8,136
+*none*: 0x016a,116
+SA: 0x013e,118
+pollDevices: 0x018a,120
+*none*: 0x019a,121
+*none*: 0x012b,123
+*none*: 0x012a,124
+
+[DiskBootDLion.mc,v]
+VerifyLp: 0x0255,97
+*none*: 0x0256,99
+MoreVerify: 0x01d4,101
+FinVerify: 0x01d5,105
+*none*: 0x0160,109
+FindSA1Sect0: 0x013a,110
+FindSA1Sect0Lp: 0x01a8,94
+Wait2: 0x013b,264
+
diff --git a/D/CP/Source/SunlightO2_map.txt b/D/CP/Source/SunlightO2_map.txt
new file mode 100644
index 0000000..cbc6328
--- /dev/null
+++ b/D/CP/Source/SunlightO2_map.txt
@@ -0,0 +1,18 @@
+#
+ # This file maps assembly source symbols to PROM/microcode addresses and source lines, forming a crude
+ # symbol table.
+ #
+ # Each source file is given a header a la:
+ # [FooSource.asm]
+ # (with brackets)
+
+ # Each line's syntax is:
+ # , .. , : ,
+ # where '*none*' is a special symbol name meaning no symbol mapping is present.
+[MoonSunlightO2.mc,v]
+Go: 0x00fe,46
+*none*: 0x007f,47
+*none*: 0x0100,48
+*none*: 0x0101,49
+*none*: 0x0016,51
+
diff --git a/D/CP/Source/SunlightO4_map.txt b/D/CP/Source/SunlightO4_map.txt
new file mode 100644
index 0000000..46c0c7d
--- /dev/null
+++ b/D/CP/Source/SunlightO4_map.txt
@@ -0,0 +1,164 @@
+#
+ # This file maps assembly source symbols to PROM/microcode addresses and source lines, forming a crude
+ # symbol table.
+ #
+ # Each source file is given a header a la:
+ # [FooSource.asm]
+ # (with brackets)
+
+ # Each line's syntax is:
+ # , .. , : ,
+ # where '*none*' is a special symbol name meaning no symbol mapping is present.
+[MoonSunlightO4.mc,v]
+ibTests: 0x0066,61
+*none*: 0x008f,62
+*none*: 0x0067,63
+*none*: 0x0068,64
+*none*: 0x0069,66
+*none*: 0x006a,67
+*none*: 0x006b,68
+IBPtr0Bad: 0x0018,257
+IBPtr0Good: 0x0019,71
+*none*: 0x006c,72
+*none*: 0x006d,73
+*none*: 0x006e,75
+*none*: 0x0070,76
+*none*: 0x0071,77
+IBPtr1Bad: 0x000c,258
+IBPtr1Good: 0x000d,80
+*none*: 0x0072,81
+*none*: 0x0073,82
+*none*: 0x0074,84
+*none*: 0x0075,85
+*none*: 0x0076,86
+*none*: 0x0077,88
+*none*: 0x0078,89
+*none*: 0x0079,90
+IBLeftaBad: 0x0030,259
+IBLeftaGood: 0x0031,92
+IBLeftbBad: 0x0020,261
+IBLeftbGood: 0x0021,93
+*none*: 0x007a,94
+*none*: 0x007b,96
+*none*: 0x007c,97
+IBRaBad: 0x0032,262
+IBRaGood: 0x0033,98
+IBRbBad: 0x0024,264
+IBRbGood: 0x0025,101
+*none*: 0x007d,102
+*none*: 0x007e,103
+IBHighBad: 0x0034,265
+IBHighGood: 0x0035,105
+*none*: 0x007f,106
+*none*: 0x0080,107
+IBLowBad: 0x0026,266
+IBLowGood: 0x0027,110
+*none*: 0x0081,111
+*none*: 0x0082,113
+*none*: 0x0083,114
+*none*: 0x0002,115
+*none*: 0x0084,117
+*none*: 0x0085,118
+*none*: 0x0006,119
+*none*: 0x0086,121
+*none*: 0x0087,122
+*none*: 0x0088,123
+*none*: 0x0089,125
+IBPtr1xBad: 0x0036,267
+IBPtr1xGood: 0x0037,128
+*none*: 0x008a,129
+*none*: 0x008b,130
+*none*: 0x008c,132
+*none*: 0x008d,133
+NETrap: 0x0500,135
+*none*: 0x008e,136
+NETrapBad: 0x0028,268
+NETrapGood: 0x0029,140
+*none*: 0x0090,141
+*none*: 0x0091,142
+*none*: 0x0092,143
+*none*: 0x0093,145
+*none*: 0x0094,146
+*none*: 0x0095,147
+IBaBad: 0x0038,269
+IBaGood: 0x0039,149
+*none*: 0x0096,150
+*none*: 0x0097,151
+IBbBad: 0x002a,270
+IBbGood: 0x002b,153
+*none*: 0x0098,154
+*none*: 0x0099,155
+IBcBad: 0x003a,271
+IBcGood: 0x003b,157
+*none*: 0x009a,158
+*none*: 0x009b,159
+IBdBad: 0x0040,272
+IBdGood: 0x0041,161
+*none*: 0x009c,162
+*none*: 0x009d,163
+ETrap: 0x0400,165
+*none*: 0x009e,166
+ETrapBad: 0x003c,273
+ETrapGood: 0x003d,170
+*none*: 0x009f,171
+*none*: 0x00a0,172
+*none*: 0x00a1,173
+NEMIntTrap: 0x0700,175
+*none*: 0x0600,177
+*none*: 0x00a2,178
+EMTrapG: 0x0043,181
+EMTrapBad: 0x0042,274
+*none*: 0x00a3,182
+*none*: 0x00a4,183
+*none*: 0x00a5,185
+*none*: 0x08af,231
+IBDispaG: 0x00a6,188
+*none*: 0x00a7,189
+*none*: 0x00a8,191
+*none*: 0x00a9,192
+*none*: 0x00aa,193
+*none*: 0x00ab,195
+*none*: 0x00b0,196
+*none*: 0x00b1,197
+*none*: 0x00b2,199
+*none*: 0x00b3,200
+*none*: 0x00b4,201
+IBDispbG: 0x085f,226
+IBDispbG: 0x00b5,204
+*none*: 0x00b6,205
+*none*: 0x00b7,206
+*none*: 0x00b8,208
+*none*: 0x00b9,209
+*none*: 0x08fa,247
+IBDispcG: 0x00ba,212
+*none*: 0x00bb,213
+*none*: 0x00bc,215
+*none*: 0x00bd,216
+*none*: 0x00be,217
+*none*: 0x08f5,242
+MemTest: 0x00c7,288
+*none*: 0x00c8,289
+*none*: 0x00c9,291
+*none*: 0x00ca,292
+*none*: 0x00cb,293
+*none*: 0x00cc,296
+*none*: 0x00cd,297
+*none*: 0x00ce,298
+*none*: 0x00d0,300
+*none*: 0x00d1,301
+*none*: 0x00d2,302
+*none*: 0x00d3,304
+*none*: 0x00d4,305
+*none*: 0x0045,306
+SimMARBad: 0x0044,284
+*none*: 0x00d5,309
+*none*: 0x00d6,310
+*none*: 0x0016,311
+*none*: 0x00d7,313
+*none*: 0x00d8,314
+*none*: 0x00d9,315
+*none*: 0x00da,317
+*none*: 0x00db,318
+MDRCanBad: 0x0052,285
+*none*: 0x0053,319
+
diff --git a/D/CP/Source/SunlightO5_map.txt b/D/CP/Source/SunlightO5_map.txt
new file mode 100644
index 0000000..a0f2dae
--- /dev/null
+++ b/D/CP/Source/SunlightO5_map.txt
@@ -0,0 +1,183 @@
+#
+ # This file maps assembly source symbols to PROM/microcode addresses and source lines, forming a crude
+ # symbol table.
+ #
+ # Each source file is given a header a la:
+ # [FooSource.asm]
+ # (with brackets)
+
+ # Each line's syntax is:
+ # , .. , : ,
+ # where '*none*' is a special symbol name meaning no symbol mapping is present.
+[MoonSunlightO5.mc,v]
+*none*: 0x002f,78
+TrapTest: 0x0074,77
+*none*: 0x0075,79
+StkUF: 0x0076,82
+*none*: 0x007f,83
+WaitTrapc3: 0x0099,188
+WaitTrapc1: 0x009a,189
+*none*: 0x009b,190
+FastTrapc3: 0x009c,191
+*none*: 0x009d,192
+*none*: 0x005f,45
+*none*: 0x006a,46
+TrapType: 0x0010,49
+*none*: 0x0011,50
+*none*: 0x0012,51
+*none*: 0x0013,52
+NotCSPar: 0x006b,54
+*none*: 0x006c,55
+*none*: 0x006d,58
+*none*: 0x006e,59
+*none*: 0x0024,60
+StkSimUF: 0x0027,85
+*none*: 0x0026,62
+*none*: 0x0001,86
+*none*: 0x001c,63
+StkSim2UF: 0x001d,88
+*none*: 0x0037,89
+*none*: 0x0077,90
+WaitTrapc2: 0x0098,187
+*none*: 0x0028,64
+Stk2UF: 0x0029,92
+*none*: 0x0041,93
+*none*: 0x0078,94
+DidntTrap: 0x00cd,296
+*none*: 0x0030,66
+StkOF: 0x0031,96
+*none*: 0x0039,97
+*none*: 0x002a,67
+StkOFp: 0x002b,99
+*none*: 0x0043,100
+*none*: 0x0079,101
+*none*: 0x0032,68
+StkEReg: 0x0033,104
+*none*: 0x003b,105
+StkEE: 0x0004,107
+*none*: 0x0005,108
+*none*: 0x0006,109
+*none*: 0x0007,110
+Memf: 0x007a,114
+*none*: 0x007b,115
+MWait: 0x0045,117
+*none*: 0x007c,118
+*none*: 0x007d,119
+MemF2: 0x0044,122
+*none*: 0x007e,123
+*none*: 0x0080,125
+*none*: 0x0081,126
+*none*: 0x0082,127
+*none*: 0x0083,129
+*none*: 0x0084,130
+*none*: 0x0085,131
+*none*: 0x006f,70
+*none*: 0x0072,71
+*none*: 0x002c,72
+MemEReg: 0x002d,134
+*none*: 0x003d,135
+MemEE: 0x0014,137
+*none*: 0x0015,138
+MemStatE: 0x0086,142
+*none*: 0x0087,143
+MStatBad0: 0x0009,289
+*none*: 0x000b,144
+*none*: 0x0088,145
+IBTestc1: 0x0021,149
+*none*: 0x0089,150
+*none*: 0x008a,151
+*none*: 0x008b,153
+*none*: 0x008c,154
+*none*: 0x008d,155
+*none*: 0x0034,74
+IBTestc2: 0x0035,158
+*none*: 0x0051,159
+*none*: 0x008e,160
+*none*: 0x008f,162
+*none*: 0x0090,163
+IBEReg: 0x0047,166
+*none*: 0x0053,167
+IBEE: 0x0018,169
+*none*: 0x0019,170
+*none*: 0x001a,171
+*none*: 0x001b,174
+*none*: 0x0091,175
+*none*: 0x0092,176
+*none*: 0x0093,179
+*none*: 0x0094,180
+*none*: 0x0095,181
+*none*: 0x0096,183
+*none*: 0x0097,184
+IBEMemW: 0x0054,302
+CritTime: 0x0055,196
+*none*: 0x009e,199
+*none*: 0x009f,200
+*none*: 0x00a0,201
+*none*: 0x00a1,204
+UZeroBrBad: 0x0048,306
+UNeg: 0x0049,205
+*none*: 0x00a2,206
+*none*: 0x00a3,208
+UNegBrBad: 0x0056,307
+UStkp: 0x0057,209
+*none*: 0x00a4,210
+*none*: 0x00a5,213
+*none*: 0x00a6,214
+*none*: 0x00a7,215
+*none*: 0x00a8,217
+UstkpBad: 0x004a,308
+URot: 0x004b,218
+*none*: 0x00a9,219
+*none*: 0x00aa,222
+*none*: 0x00ab,223
+*none*: 0x00ac,224
+*none*: 0x00ad,226
+*none*: 0x00ae,227
+*none*: 0x0058,309
+UPage: 0x0059,228
+*none*: 0x00af,231
+*none*: 0x00b0,232
+*none*: 0x00b1,233
+*none*: 0x00b2,235
+MemNib: 0x00b3,236
+UByPgCyBad: 0x004c,310
+*none*: 0x004d,237
+*none*: 0x00b4,240
+*none*: 0x00b5,241
+*none*: 0x00b6,242
+*none*: 0x00b7,244
+*none*: 0x00b8,245
+*none*: 0x00b9,246
+*none*: 0x00ba,248
+*none*: 0x00bb,249
+*none*: 0x00bc,250
+MNibByBad: 0x005a,311
+*none*: 0x005b,253
+*none*: 0x00bd,254
+*none*: 0x00be,255
+*none*: 0x00bf,257
+*none*: 0x00c0,258
+*none*: 0x00c1,259
+UFZeroT: 0x004e,261
+*none*: 0x00c2,262
+*none*: 0x00c3,263
+*none*: 0x00c4,265
+*none*: 0x00c5,266
+*none*: 0x005c,267
+rhPage: 0x004f,270
+UFZeroBad: 0x005d,315
+*none*: 0x00c6,271
+*none*: 0x00c7,272
+*none*: 0x00c8,274
+*none*: 0x00c9,275
+*none*: 0x0061,276
+*none*: 0x00ca,279
+RHByArBad: 0x0070,313
+ByCarry: 0x0071,280
+*none*: 0x00cb,281
+*none*: 0x00cc,283
+ByCyBrBad: 0x0062,314
+*none*: 0x0063,284
+NOERROR1: 0x00d3,318
+NOERROR: 0x0fff,319
+
diff --git a/D/CP/Source/load_map.txt b/D/CP/Source/load_map.txt
new file mode 100644
index 0000000..b3426b8
--- /dev/null
+++ b/D/CP/Source/load_map.txt
@@ -0,0 +1,13 @@
+BootKernel,BootKernel_map.txt,fd8,fff,08db70caa4585b9a8c7f5ba9215eb34c
+Phase0Protected,Phase0Protected_map.txt,000,0ff,c73c5996d9a9ac6ee37a2d92ae7f6c15
+Phase0,Phase0_map.txt,100,fd7,d9d9f75e0f9539fa911488c3bd36e262
+FloppyInitial,FloppyInitial_map.txt,000,fff,0bd42231451c66d8043867fd390580ac
+Main,Main_map.txt,000,fd7,7f64459937a5a3104343bc7a0ad5dbd7
+MoonPortIn,MoonPortIn_map.txt,000,fff,00960fada4edd268b6fc49c918d49582
+MoonPortOut,MoonPortOut_map.txt,000,fff,de001dba5266a6fda17d35f88741fa1b
+SunlightO2,SunlightO2_map.txt,000,fff,00a2160753bd3a6968dfffba0a8e566b
+SunlightO4,SunlightO4_map.txt,000,fff,6c22068f622d7afb5d5ba9a74e2f8312
+SunlightO5,SunlightO5_map.txt,000,fff,6a1971a8953f36e3777f1940e43f2d46
+CPMemTest,CPMemTest_map.txt,000,fff,930c63cb19215d1140e742d86a3ca760
+MoonCycle,MoonCycle_map.txt,000,fff,7936738bb3be4498cdf1f5169f35c1f7
+MoonEthBTest,MoonEthBTest_map.txt,000,fff,990b5b14754ae7785838ace650384671
diff --git a/D/Configuration.cs b/D/Configuration.cs
new file mode 100644
index 0000000..701bdbc
--- /dev/null
+++ b/D/Configuration.cs
@@ -0,0 +1,459 @@
+/*
+ BSD 2-Clause License
+
+ Copyright Vulcan Inc. 2017-2018 and Living Computer Museum + Labs 2018
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+using D.IOP;
+using D.Logging;
+using System;
+using System.Collections.Specialized;
+using System.IO;
+using System.Reflection;
+
+namespace D
+{
+ public enum PlatformType
+ {
+ Windows,
+ Unix
+ }
+
+ ///
+ /// Encapsulates user-configurable settings. To be enhanced.
+ ///
+ public static class Configuration
+ {
+ static Configuration()
+ {
+ // Initialize things to defaults.
+ MemorySize = 768;
+ HostID = 0x0000aa012345;
+ ThrottleSpeed = true;
+ DisplayScale = 1;
+ SlowPhosphor = true;
+ HostPacketInterfaceName = String.Empty;
+
+ TODDateTime = new DateTime(1979, 12, 10);
+ TODDate = new DateTime(1955, 11, 5);
+ TODSetMode = TODPowerUpSetMode.HostTimeY2K;
+
+ switch (Environment.OSVersion.Platform)
+ {
+ case PlatformID.MacOSX:
+ case PlatformID.Unix:
+ Platform = PlatformType.Unix;
+ break;
+
+ default:
+ Platform = PlatformType.Windows;
+ break;
+ }
+
+ // See if PCap is available.
+ TestPCap();
+
+ try
+ {
+ ReadConfiguration();
+ }
+ catch
+ {
+ Log.Write(LogType.Error, LogComponent.Configuration,
+ "Unable to load configuration. Assuming default settings.");
+ }
+
+ //
+ // Sanity-check settings that need sanity-checking.
+ //
+ if (MemorySize > 1024 ||
+ MemorySize == 0 ||
+ (MemorySize % 128) != 0)
+ {
+ Log.Write(LogType.Error, LogComponent.Configuration,
+ "MemorySize configuration parameter is incorrect, defaulting to 768KW.");
+
+ MemorySize = 768;
+ }
+
+ if (DisplayScale < 1)
+ {
+ Log.Write(LogType.Error, LogComponent.Configuration,
+ "DisplayScale configuration parameter is incorrect, defaulting to 1.");
+
+ DisplayScale = 1;
+ }
+ }
+
+ ///
+ /// What kind of system we're running on. (Not technically configurable.)
+ ///
+ public static PlatformType Platform;
+
+ ///
+ /// System memory size, in KW.
+ ///
+ public static uint MemorySize;
+
+ ///
+ /// The currently loaded image for the hard disk.
+ ///
+ public static string HardDriveImage;
+
+ ///
+ /// The currently loaded image for the floppy drive.
+ ///
+ public static string FloppyDriveImage;
+
+ ///
+ /// The Ethernet host address for this Star.
+ ///
+ public static ulong HostID;
+
+ ///
+ /// The name of the Ethernet adaptor on the emulator host to use for Ethernet emulation
+ ///
+ public static string HostPacketInterfaceName;
+
+ ///
+ /// Whether any packet interfaces are available on the host
+ ///
+ public static bool HostRawEthernetInterfacesAvailable;
+
+ ///
+ /// Whether to cap execution speed at native execution speed or not.
+ ///
+ public static bool ThrottleSpeed;
+
+ ///
+ /// Scale factor to apply to the display.
+ ///
+ public static uint DisplayScale;
+
+ ///
+ /// Whether to apply a fake "slow phosphor" persistence to the emulated display.
+ ///
+ public static bool SlowPhosphor;
+
+ ///
+ /// How to set the TOD clock at power up/reset
+ ///
+ public static TODPowerUpSetMode TODSetMode;
+
+ ///
+ /// The specific date/time to set the TOD clock to if TODSetMode is "SpecificDateAndTime"
+ ///
+ public static DateTime TODDateTime;
+
+ ///
+ /// The specific date to set the TOD clock to if TODSetMode is "SpecificDate"
+ ///
+ public static DateTime TODDate;
+
+ ///
+ /// The components to enable debug logging for.
+ ///
+ public static LogComponent LogComponents;
+
+ ///
+ /// The types of logging to enable.
+ ///
+ public static LogType LogTypes;
+
+ ///
+ /// Reads the current configuration file from the appropriate place.
+ ///
+ public static void ReadConfiguration()
+ {
+ if (Configuration.Platform == PlatformType.Windows)
+ // && string.IsNullOrWhiteSpace(StartupOptions.ConfigurationFile))
+ {
+ //
+ // By default, on Windows we use the app Settings functionality
+ // to store settings in the registry on a per-user basis.
+ // If a configuration file is specified, we will use it instead.
+ //
+ ReadConfigurationWindows();
+ }
+ else
+ {
+ //
+ // On UNIX platforms we read in a configuration file.
+ // This is mostly because Mono's support for Properties.Settings
+ // is broken in inexplicable ways and I'm tired of fighting with it.
+ //
+ ReadConfigurationUnix();
+ }
+ }
+
+ ///
+ /// Commits the current configuration to the app's settings.
+ ///
+ public static void WriteConfiguration()
+ {
+ if (Configuration.Platform == PlatformType.Windows)
+ {
+ WriteConfigurationWindows();
+ }
+ else
+ {
+ //
+ // At the moment the configuration files are read-only
+ // on UNIX platforms.
+ //
+ }
+ }
+
+ private static void ReadConfigurationWindows()
+ {
+ MemorySize = Properties.Settings.Default.MemorySize;
+ HardDriveImage = Properties.Settings.Default.HardDriveImage;
+ FloppyDriveImage = Properties.Settings.Default.FloppyDriveImage;
+ HostID = Properties.Settings.Default.HostAddress;
+ HostPacketInterfaceName = Properties.Settings.Default.HostPacketInterfaceName;
+ ThrottleSpeed = Properties.Settings.Default.ThrottleSpeed;
+ DisplayScale = Properties.Settings.Default.DisplayScale;
+ SlowPhosphor = Properties.Settings.Default.SlowPhosphor;
+ TODSetMode = (TODPowerUpSetMode)Properties.Settings.Default.TODSetMode;
+ TODDateTime = Properties.Settings.Default.TODDateTime;
+ TODDate = Properties.Settings.Default.TODDate;
+ }
+
+ private static void WriteConfigurationWindows()
+ {
+ Properties.Settings.Default.MemorySize = MemorySize;
+ Properties.Settings.Default.HardDriveImage = HardDriveImage;
+ Properties.Settings.Default.FloppyDriveImage = FloppyDriveImage;
+ Properties.Settings.Default.HostAddress = HostID;
+ Properties.Settings.Default.HostPacketInterfaceName = HostPacketInterfaceName;
+ Properties.Settings.Default.ThrottleSpeed = ThrottleSpeed;
+ Properties.Settings.Default.DisplayScale = DisplayScale;
+ Properties.Settings.Default.SlowPhosphor = SlowPhosphor;
+ Properties.Settings.Default.TODSetMode = (int)TODSetMode;
+ Properties.Settings.Default.TODDateTime = TODDateTime;
+ Properties.Settings.Default.TODDate = TODDate;
+ Properties.Settings.Default.Save();
+ }
+
+ private static void ReadConfigurationUnix()
+ {
+ string configFilePath = null;
+
+ if (false) //!string.IsNullOrWhiteSpace(StartupOptions.ConfigurationFile))
+ {
+ // configFilePath = StartupOptions.ConfigurationFile;
+ }
+ else
+ {
+ // No config file specified, default.
+ configFilePath = "Darkstar.cfg";
+ }
+
+ //
+ // Check that the configuration file exists.
+ // If not, we will warn the user and use default settings.
+ //
+ if (!File.Exists(configFilePath))
+ {
+ Console.WriteLine("Configuration file {0} does not exist or cannot be accessed. Using default settings.", configFilePath);
+ return;
+ }
+
+ using (StreamReader configStream = new StreamReader(configFilePath))
+ {
+ //
+ // Config file consists of text lines containing name / value pairs:
+ // =
+ // Whitespace is ignored.
+ //
+ int lineNumber = 0;
+ while (!configStream.EndOfStream)
+ {
+ lineNumber++;
+ string line = configStream.ReadLine().Trim();
+
+ if (string.IsNullOrEmpty(line))
+ {
+ // Empty line, ignore.
+ continue;
+ }
+
+ if (line.StartsWith("#"))
+ {
+ // Comment to EOL, ignore.
+ continue;
+ }
+
+ // Find the '=' separating tokens and ensure there are just two.
+ string[] tokens = line.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
+
+ if (tokens.Length < 2)
+ {
+ Console.WriteLine(
+ "{0} line {1}: Invalid syntax.", configFilePath, lineNumber);
+ continue;
+ }
+
+ string parameter = tokens[0].Trim();
+ string value = tokens[1].Trim();
+
+ // Reflect over the public, static properties in this class and see if the parameter matches one of them
+ // If not, it's an error, if it is then we attempt to coerce the value to the correct type.
+ System.Reflection.FieldInfo[] info = typeof(Configuration).GetFields(BindingFlags.Public | BindingFlags.Static);
+
+ bool bMatch = false;
+ foreach (FieldInfo field in info)
+ {
+ // Case-insensitive compare.
+ if (field.Name.ToLowerInvariant() == parameter.ToLowerInvariant())
+ {
+ bMatch = true;
+
+ //
+ // Switch on the type of the field and attempt to convert the value to the appropriate type.
+ // At this time we support only strings and integers.
+ //
+ try
+ {
+ switch (field.FieldType.Name)
+ {
+ case "Int32":
+ {
+ int v = Convert.ToInt32(value, 10);
+ field.SetValue(null, v);
+ }
+ break;
+
+ case "UInt16":
+ {
+ UInt16 v = Convert.ToUInt16(value, 16);
+ field.SetValue(null, v);
+ }
+ break;
+
+ case "Byte":
+ {
+ byte v = Convert.ToByte(value, 16);
+ field.SetValue(null, v);
+ }
+ break;
+
+ case "String":
+ {
+ field.SetValue(null, value);
+ }
+ break;
+
+ case "Boolean":
+ {
+ bool v = bool.Parse(value);
+ field.SetValue(null, v);
+ }
+ break;
+
+ case "UInt64":
+ {
+ UInt64 v = Convert.ToUInt64(value, 16);
+ field.SetValue(null, v);
+ }
+ break;
+
+ case "TODPowerUpSetMode":
+ {
+ field.SetValue(null, Enum.Parse(typeof(TODPowerUpSetMode), value, true));
+ }
+ break;
+
+ case "DateTime":
+ {
+ field.SetValue(null, DateTime.Parse(value));
+ }
+ break;
+
+ case "LogType":
+ {
+ field.SetValue(null, Enum.Parse(typeof(LogType), value, true));
+ }
+ break;
+
+ case "LogComponent":
+ {
+ field.SetValue(null, Enum.Parse(typeof(LogComponent), value, true));
+ }
+ break;
+
+ case "StringCollection":
+ {
+ // value is expected to be a comma-delimited set.
+ StringCollection sc = new StringCollection();
+ string[] strings = value.Split(',');
+
+ foreach (string s in strings)
+ {
+ sc.Add(s);
+ }
+
+ field.SetValue(null, sc);
+ }
+ break;
+ }
+ }
+ catch
+ {
+ Console.WriteLine(
+ "{0} line {1}: Value '{2}' is invalid for parameter '{3}'.", configFilePath, lineNumber, value, parameter);
+ }
+ }
+ }
+
+ if (!bMatch)
+ {
+ Console.WriteLine(
+ "{0} line {1}: Unknown configuration parameter '{2}'.", configFilePath, lineNumber, parameter);
+ }
+ }
+ }
+ }
+
+ private static void TestPCap()
+ {
+ // Just try enumerating interfaces, if this fails for any reason we assume
+ // PCap is not properly installed.
+ try
+ {
+ SharpPcap.CaptureDeviceList devices = SharpPcap.CaptureDeviceList.Instance;
+ Configuration.HostRawEthernetInterfacesAvailable = true;
+ }
+ catch
+ {
+ Configuration.HostRawEthernetInterfacesAvailable = false;
+ }
+ }
+
+
+ }
+
+}
diff --git a/D/Conversion.cs b/D/Conversion.cs
new file mode 100644
index 0000000..0019d5d
--- /dev/null
+++ b/D/Conversion.cs
@@ -0,0 +1,49 @@
+/*
+ BSD 2-Clause License
+
+ Copyright Vulcan Inc. 2017-2018 and Living Computer Museum + Labs 2018
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+namespace D
+{
+ public static class Conversion
+ {
+ ///
+ /// Conversion from millseconds to nanoseconds
+ ///
+ public static readonly ulong MsecToNsec = 1000000;
+
+ ///
+ /// Conversion from nanoseconds to milliseconds
+ ///
+ public static readonly double NsecToMsec = 0.000001;
+
+ ///
+ /// Conversion from microseconds to nanoseconds
+ ///
+ public static readonly ulong UsecToNsec = 1000;
+ }
+}
diff --git a/D/Dandelion.ico b/D/Dandelion.ico
new file mode 100644
index 0000000..6fea64e
Binary files /dev/null and b/D/Dandelion.ico differ
diff --git a/D/Darkstar.cfg b/D/Darkstar.cfg
new file mode 100644
index 0000000..c3b1bd5
--- /dev/null
+++ b/D/Darkstar.cfg
@@ -0,0 +1,34 @@
+# darkstar.cfg:
+#
+# This file contains configuration parameters for Darkstar.
+# All integers are specified in hexadecimal.
+#
+
+# System configuration
+MemorySize = 0x400
+HostID = 0x0000aa012345
+
+# Disk options
+# FloppyDriveImage =
+# HardDriveImage =
+
+# Ethernet configuration
+# HostPacketInterfaceName =
+
+# Display options
+DisplayScale = 1
+SlowPhosphor = true
+
+# TOD (Time Of Day) Clock options
+# TODSetMode specifies how to set the TOD clock at reset
+# (see readme.txt). Possible values are:
+# HostTimeY2K
+# HostTime
+# SpecificDateAndTime
+# SpecificDate
+# NoChange
+#
+TODSetMode = NoChange
+# TODDate = 1990/11/09
+# TODDateTime = 1990/11/09 12:00:00
+
diff --git a/D/Darkstar.csproj b/D/Darkstar.csproj
new file mode 100644
index 0000000..1140bf5
--- /dev/null
+++ b/D/Darkstar.csproj
@@ -0,0 +1,306 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {0590465E-1D91-4591-946E-EE3F7D82834B}
+ Exe
+ D
+ Darkstar
+ v4.5.2
+ 512
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+ app.manifest
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE
+ full
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x64\Release\
+ TRACE
+ true
+ pdbonly
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+
+ ..\packages\Sharp_Pcap.4.2.0\lib\PacketDotNet.dll
+
+
+ ..\packages\SDL2-CS.dll.2.0.0.0\lib\net20\SDL2-CS.dll
+
+
+ ..\packages\Sharp_Pcap.4.2.0\lib\SharpPcap.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ CPDebugger.cs
+
+
+ Form
+
+
+ DebuggerMain.cs
+
+
+ Form
+
+
+ IOPDebugger.cs
+
+
+ Form
+
+
+ LoadMapDialog.cs
+
+
+
+ Component
+
+
+ Component
+
+
+
+
+
+
+ True
+ True
+ Settings.settings
+
+
+ Form
+
+
+ AboutBox.cs
+
+
+ Form
+
+
+ ConfigurationDialog.cs
+
+
+ Form
+
+
+ Form
+
+
+ DWindow.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+ PreserveNewest
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
+ CPDebugger.cs
+
+
+ DebuggerMain.cs
+
+
+ IOPDebugger.cs
+
+
+ LoadMapDialog.cs
+
+
+ AboutBox.cs
+
+
+ ConfigurationDialog.cs
+
+
+ DWindow.cs
+
+
+
+
\ No newline at end of file
diff --git a/D/Debugger/BreakpointManager.cs b/D/Debugger/BreakpointManager.cs
new file mode 100644
index 0000000..5efdb5e
--- /dev/null
+++ b/D/Debugger/BreakpointManager.cs
@@ -0,0 +1,178 @@
+/*
+ BSD 2-Clause License
+
+ Copyright Vulcan Inc. 2017-2018 and Living Computer Museum + Labs 2018
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+using System;
+using System.Collections.Generic;
+
+namespace D.Debugger
+{
+ [Flags]
+ public enum BreakpointType
+ {
+ None = 0,
+ Execution = 1,
+ Read = 2,
+ Write = 4,
+ }
+
+ public enum BreakpointProcessor
+ {
+ IOP = 0,
+ CP,
+ Mesa,
+ }
+
+ public struct BreakpointEntry
+ {
+ public BreakpointEntry(BreakpointProcessor processor, BreakpointType type, int address)
+ {
+ Processor = processor;
+ Type = type;
+ Address = address;
+ }
+
+ public BreakpointProcessor Processor;
+ public BreakpointType Type;
+ public int Address;
+ }
+
+ public static class BreakpointManager
+ {
+ static BreakpointManager()
+ {
+ // We use a flat array to make lookup as
+ // cheap as possible across the various address spaces.
+ _iopBreakpoints = new BreakpointType[0x10000];
+ _cpBreakpoints = new BreakpointType[0x1000];
+ _mesaBreakpoints = new BreakpointType[0x200000]; // 2mb (1mw).
+ _enableBreakpoints = true;
+ }
+
+ public static bool BreakpointsEnabled
+ {
+ get { return _enableBreakpoints; }
+ set { _enableBreakpoints = value; }
+ }
+
+ public static void SetBreakpoint(BreakpointEntry entry)
+ {
+ BreakpointType[] _bkpts = GetBreakpointsForProcessor(entry.Processor);
+
+ if (entry.Type == BreakpointType.None)
+ {
+ _bkpts[entry.Address] = BreakpointType.None;
+ }
+ else
+ {
+ _bkpts[entry.Address] |= entry.Type;
+ }
+ }
+
+ public static BreakpointType GetBreakpoint(BreakpointProcessor processor, ushort address)
+ {
+ BreakpointType[] _bkpts = GetBreakpointsForProcessor(processor);
+ return _bkpts[address];
+ }
+
+ public static bool TestBreakpoint(BreakpointEntry entry)
+ {
+ if (!_enableBreakpoints)
+ {
+ return false;
+ }
+
+ BreakpointType[] _bkpts = GetBreakpointsForProcessor(entry.Processor);
+ return (_bkpts[entry.Address] & entry.Type) != 0;
+ }
+
+ public static bool TestBreakpoint(BreakpointProcessor processor, BreakpointType type, int address)
+ {
+ if (!_enableBreakpoints)
+ {
+ return false;
+ }
+
+ BreakpointType[] _bkpts = GetBreakpointsForProcessor(processor);
+ return (_bkpts[address] & type) != 0;
+ }
+
+ public static List EnumerateBreakpoints()
+ {
+ List breakpoints = new List();
+
+ for (ushort i = 0; i < _iopBreakpoints.Length; i++)
+ {
+ if (_iopBreakpoints[i] != BreakpointType.None)
+ {
+ breakpoints.Add(new BreakpointEntry(BreakpointProcessor.IOP, _iopBreakpoints[i], i));
+ }
+ }
+
+ for (ushort i = 0; i < _cpBreakpoints.Length; i++)
+ {
+ if (_cpBreakpoints[i] != BreakpointType.None)
+ {
+ breakpoints.Add(new BreakpointEntry(BreakpointProcessor.CP, _cpBreakpoints[i], i));
+ }
+ }
+
+ for (ushort i = 0; i < _mesaBreakpoints.Length; i++)
+ {
+ if (_mesaBreakpoints[i] != BreakpointType.None)
+ {
+ breakpoints.Add(new BreakpointEntry(BreakpointProcessor.Mesa, _mesaBreakpoints[i], i));
+ }
+ }
+
+ return breakpoints;
+ }
+
+ private static BreakpointType[] GetBreakpointsForProcessor(BreakpointProcessor processor)
+ {
+ switch (processor)
+ {
+ case BreakpointProcessor.CP:
+ return _cpBreakpoints;
+
+ case BreakpointProcessor.IOP:
+ return _iopBreakpoints;
+
+ case BreakpointProcessor.Mesa:
+ return _mesaBreakpoints;
+ }
+
+ return null;
+ }
+
+ private static BreakpointType[] _iopBreakpoints;
+ private static BreakpointType[] _cpBreakpoints;
+ private static BreakpointType[] _mesaBreakpoints;
+ private static bool _enableBreakpoints;
+ }
+}
diff --git a/D/Debugger/CPDebugger.Designer.cs b/D/Debugger/CPDebugger.Designer.cs
new file mode 100644
index 0000000..8e823e6
--- /dev/null
+++ b/D/Debugger/CPDebugger.Designer.cs
@@ -0,0 +1,457 @@
+/*
+ BSD 2-Clause License
+
+ Copyright Vulcan Inc. 2017-2018 and Living Computer Museum + Labs 2018
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+namespace D.Debugger
+{
+ partial class CPDebugger
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle();
+ this.IOPSourceBox = new System.Windows.Forms.GroupBox();
+ this.Disassembly = new D.Debugger.MicrocodeDisplay();
+ this.SourceFiles = new System.Windows.Forms.ListBox();
+ this.SourceDisplay = new D.Debugger.SourceDisplay();
+ this.dataGridViewCheckBoxColumn3 = new System.Windows.Forms.DataGridViewCheckBoxColumn();
+ this.dataGridViewTextBoxColumn5 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewTextBoxColumn6 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewCheckBoxColumn1 = new System.Windows.Forms.DataGridViewCheckBoxColumn();
+ this.dataGridViewTextBoxColumn1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewTextBoxColumn2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewCheckBoxColumn2 = new System.Windows.Forms.DataGridViewCheckBoxColumn();
+ this.dataGridViewTextBoxColumn3 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewTextBoxColumn4 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewCheckBoxColumn4 = new System.Windows.Forms.DataGridViewCheckBoxColumn();
+ this.dataGridViewTextBoxColumn7 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewTextBoxColumn8 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewCheckBoxColumn5 = new System.Windows.Forms.DataGridViewCheckBoxColumn();
+ this.dataGridViewTextBoxColumn9 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewTextBoxColumn10 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewCheckBoxColumn6 = new System.Windows.Forms.DataGridViewCheckBoxColumn();
+ this.dataGridViewTextBoxColumn11 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewTextBoxColumn12 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewCheckBoxColumn7 = new System.Windows.Forms.DataGridViewCheckBoxColumn();
+ this.dataGridViewTextBoxColumn13 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewTextBoxColumn14 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewCheckBoxColumn8 = new System.Windows.Forms.DataGridViewCheckBoxColumn();
+ this.dataGridViewTextBoxColumn15 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewTextBoxColumn16 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewCheckBoxColumn9 = new System.Windows.Forms.DataGridViewCheckBoxColumn();
+ this.dataGridViewTextBoxColumn17 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewTextBoxColumn18 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.IOPSourceBox.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.Disassembly)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.SourceDisplay)).BeginInit();
+ this.SuspendLayout();
+ //
+ // IOPSourceBox
+ //
+ this.IOPSourceBox.Controls.Add(this.Disassembly);
+ this.IOPSourceBox.Controls.Add(this.SourceFiles);
+ this.IOPSourceBox.Controls.Add(this.SourceDisplay);
+ this.IOPSourceBox.Location = new System.Drawing.Point(10, 5);
+ this.IOPSourceBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
+ this.IOPSourceBox.Name = "IOPSourceBox";
+ this.IOPSourceBox.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
+ this.IOPSourceBox.Size = new System.Drawing.Size(1256, 1129);
+ this.IOPSourceBox.TabIndex = 2;
+ this.IOPSourceBox.TabStop = false;
+ this.IOPSourceBox.Text = "Microcode Source";
+ //
+ // Disassembly
+ //
+ this.Disassembly.AllowUserToAddRows = false;
+ this.Disassembly.AllowUserToDeleteRows = false;
+ this.Disassembly.AllowUserToResizeColumns = false;
+ this.Disassembly.AllowUserToResizeRows = false;
+ dataGridViewCellStyle1.BackColor = System.Drawing.Color.Silver;
+ this.Disassembly.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle1;
+ this.Disassembly.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+ dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle2.BackColor = System.Drawing.SystemColors.Window;
+ dataGridViewCellStyle2.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle2.ForeColor = System.Drawing.SystemColors.ControlText;
+ dataGridViewCellStyle2.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle2.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this.Disassembly.DefaultCellStyle = dataGridViewCellStyle2;
+ this.Disassembly.Location = new System.Drawing.Point(230, 712);
+ this.Disassembly.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
+ this.Disassembly.Name = "Disassembly";
+ this.Disassembly.RowHeadersVisible = false;
+ this.Disassembly.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.CellSelect;
+ this.Disassembly.Size = new System.Drawing.Size(1017, 403);
+ this.Disassembly.TabIndex = 2;
+ this.Disassembly.VirtualMode = true;
+ this.Disassembly.SelectionChanged += new System.EventHandler(this.OnDisassemblySelectionChanged);
+ //
+ // SourceFiles
+ //
+ this.SourceFiles.FormattingEnabled = true;
+ this.SourceFiles.ItemHeight = 20;
+ this.SourceFiles.Location = new System.Drawing.Point(10, 31);
+ this.SourceFiles.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
+ this.SourceFiles.Name = "SourceFiles";
+ this.SourceFiles.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended;
+ this.SourceFiles.Size = new System.Drawing.Size(206, 1084);
+ this.SourceFiles.TabIndex = 1;
+ this.SourceFiles.Click += new System.EventHandler(this.OnSourceFilesClicked);
+ this.SourceFiles.DoubleClick += new System.EventHandler(this.OnSourceFilesDoubleClicked);
+ //
+ // SourceDisplay
+ //
+ this.SourceDisplay.AllowUserToAddRows = false;
+ this.SourceDisplay.AllowUserToDeleteRows = false;
+ this.SourceDisplay.AllowUserToResizeColumns = false;
+ this.SourceDisplay.AllowUserToResizeRows = false;
+ this.SourceDisplay.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ this.SourceDisplay.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.SingleVertical;
+ this.SourceDisplay.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+ dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle3.BackColor = System.Drawing.SystemColors.Window;
+ dataGridViewCellStyle3.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle3.ForeColor = System.Drawing.SystemColors.ControlText;
+ dataGridViewCellStyle3.NullValue = null;
+ dataGridViewCellStyle3.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle3.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle3.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this.SourceDisplay.DefaultCellStyle = dataGridViewCellStyle3;
+ this.SourceDisplay.Location = new System.Drawing.Point(228, 29);
+ this.SourceDisplay.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
+ this.SourceDisplay.Name = "SourceDisplay";
+ this.SourceDisplay.RowHeadersVisible = false;
+ this.SourceDisplay.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;
+ this.SourceDisplay.RowTemplate.Height = 18;
+ this.SourceDisplay.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
+ this.SourceDisplay.Size = new System.Drawing.Size(1018, 672);
+ this.SourceDisplay.TabIndex = 0;
+ this.SourceDisplay.VirtualMode = true;
+ this.SourceDisplay.SelectionChanged += new System.EventHandler(this.OnSourceDisplaySelectionChanged);
+ this.SourceDisplay.MouseClick += new System.Windows.Forms.MouseEventHandler(this.OnSourceDisplayMouseClick);
+ //
+ // dataGridViewCheckBoxColumn3
+ //
+ this.dataGridViewCheckBoxColumn3.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewCheckBoxColumn3.HeaderText = "B";
+ this.dataGridViewCheckBoxColumn3.Name = "dataGridViewCheckBoxColumn3";
+ this.dataGridViewCheckBoxColumn3.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ //
+ // dataGridViewTextBoxColumn5
+ //
+ this.dataGridViewTextBoxColumn5.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewTextBoxColumn5.HeaderText = "Address";
+ this.dataGridViewTextBoxColumn5.Name = "dataGridViewTextBoxColumn5";
+ this.dataGridViewTextBoxColumn5.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn5.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewTextBoxColumn6
+ //
+ this.dataGridViewTextBoxColumn6.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+ this.dataGridViewTextBoxColumn6.HeaderText = "Source";
+ this.dataGridViewTextBoxColumn6.Name = "dataGridViewTextBoxColumn6";
+ this.dataGridViewTextBoxColumn6.ReadOnly = true;
+ this.dataGridViewTextBoxColumn6.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn6.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewCheckBoxColumn1
+ //
+ this.dataGridViewCheckBoxColumn1.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewCheckBoxColumn1.HeaderText = "B";
+ this.dataGridViewCheckBoxColumn1.Name = "dataGridViewCheckBoxColumn1";
+ this.dataGridViewCheckBoxColumn1.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ //
+ // dataGridViewTextBoxColumn1
+ //
+ this.dataGridViewTextBoxColumn1.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewTextBoxColumn1.HeaderText = "Address";
+ this.dataGridViewTextBoxColumn1.Name = "dataGridViewTextBoxColumn1";
+ this.dataGridViewTextBoxColumn1.ReadOnly = true;
+ this.dataGridViewTextBoxColumn1.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn1.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewTextBoxColumn2
+ //
+ this.dataGridViewTextBoxColumn2.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+ this.dataGridViewTextBoxColumn2.HeaderText = "Disassembly";
+ this.dataGridViewTextBoxColumn2.Name = "dataGridViewTextBoxColumn2";
+ this.dataGridViewTextBoxColumn2.ReadOnly = true;
+ this.dataGridViewTextBoxColumn2.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn2.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewCheckBoxColumn2
+ //
+ this.dataGridViewCheckBoxColumn2.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewCheckBoxColumn2.HeaderText = "B";
+ this.dataGridViewCheckBoxColumn2.Name = "dataGridViewCheckBoxColumn2";
+ this.dataGridViewCheckBoxColumn2.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ //
+ // dataGridViewTextBoxColumn3
+ //
+ this.dataGridViewTextBoxColumn3.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewTextBoxColumn3.HeaderText = "Address";
+ this.dataGridViewTextBoxColumn3.Name = "dataGridViewTextBoxColumn3";
+ this.dataGridViewTextBoxColumn3.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn3.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewTextBoxColumn4
+ //
+ this.dataGridViewTextBoxColumn4.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+ this.dataGridViewTextBoxColumn4.HeaderText = "Source";
+ this.dataGridViewTextBoxColumn4.Name = "dataGridViewTextBoxColumn4";
+ this.dataGridViewTextBoxColumn4.ReadOnly = true;
+ this.dataGridViewTextBoxColumn4.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn4.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewCheckBoxColumn4
+ //
+ this.dataGridViewCheckBoxColumn4.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewCheckBoxColumn4.HeaderText = "B";
+ this.dataGridViewCheckBoxColumn4.Name = "dataGridViewCheckBoxColumn4";
+ this.dataGridViewCheckBoxColumn4.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ //
+ // dataGridViewTextBoxColumn7
+ //
+ this.dataGridViewTextBoxColumn7.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewTextBoxColumn7.HeaderText = "Address";
+ this.dataGridViewTextBoxColumn7.Name = "dataGridViewTextBoxColumn7";
+ this.dataGridViewTextBoxColumn7.ReadOnly = true;
+ this.dataGridViewTextBoxColumn7.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn7.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewTextBoxColumn8
+ //
+ this.dataGridViewTextBoxColumn8.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+ this.dataGridViewTextBoxColumn8.HeaderText = "Disassembly";
+ this.dataGridViewTextBoxColumn8.Name = "dataGridViewTextBoxColumn8";
+ this.dataGridViewTextBoxColumn8.ReadOnly = true;
+ this.dataGridViewTextBoxColumn8.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn8.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewCheckBoxColumn5
+ //
+ this.dataGridViewCheckBoxColumn5.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewCheckBoxColumn5.HeaderText = "B";
+ this.dataGridViewCheckBoxColumn5.Name = "dataGridViewCheckBoxColumn5";
+ this.dataGridViewCheckBoxColumn5.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ //
+ // dataGridViewTextBoxColumn9
+ //
+ this.dataGridViewTextBoxColumn9.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewTextBoxColumn9.HeaderText = "Address";
+ this.dataGridViewTextBoxColumn9.Name = "dataGridViewTextBoxColumn9";
+ this.dataGridViewTextBoxColumn9.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn9.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewTextBoxColumn10
+ //
+ this.dataGridViewTextBoxColumn10.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+ this.dataGridViewTextBoxColumn10.HeaderText = "Source";
+ this.dataGridViewTextBoxColumn10.Name = "dataGridViewTextBoxColumn10";
+ this.dataGridViewTextBoxColumn10.ReadOnly = true;
+ this.dataGridViewTextBoxColumn10.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn10.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewCheckBoxColumn6
+ //
+ this.dataGridViewCheckBoxColumn6.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewCheckBoxColumn6.HeaderText = "B";
+ this.dataGridViewCheckBoxColumn6.Name = "dataGridViewCheckBoxColumn6";
+ this.dataGridViewCheckBoxColumn6.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ //
+ // dataGridViewTextBoxColumn11
+ //
+ this.dataGridViewTextBoxColumn11.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewTextBoxColumn11.HeaderText = "Address";
+ this.dataGridViewTextBoxColumn11.Name = "dataGridViewTextBoxColumn11";
+ this.dataGridViewTextBoxColumn11.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn11.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewTextBoxColumn12
+ //
+ this.dataGridViewTextBoxColumn12.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+ this.dataGridViewTextBoxColumn12.HeaderText = "Disassembly";
+ this.dataGridViewTextBoxColumn12.Name = "dataGridViewTextBoxColumn12";
+ this.dataGridViewTextBoxColumn12.ReadOnly = true;
+ this.dataGridViewTextBoxColumn12.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn12.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewCheckBoxColumn7
+ //
+ this.dataGridViewCheckBoxColumn7.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewCheckBoxColumn7.HeaderText = "B";
+ this.dataGridViewCheckBoxColumn7.Name = "dataGridViewCheckBoxColumn7";
+ this.dataGridViewCheckBoxColumn7.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ //
+ // dataGridViewTextBoxColumn13
+ //
+ this.dataGridViewTextBoxColumn13.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewTextBoxColumn13.HeaderText = "Address";
+ this.dataGridViewTextBoxColumn13.Name = "dataGridViewTextBoxColumn13";
+ this.dataGridViewTextBoxColumn13.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn13.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewTextBoxColumn14
+ //
+ this.dataGridViewTextBoxColumn14.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+ this.dataGridViewTextBoxColumn14.HeaderText = "Source";
+ this.dataGridViewTextBoxColumn14.Name = "dataGridViewTextBoxColumn14";
+ this.dataGridViewTextBoxColumn14.ReadOnly = true;
+ this.dataGridViewTextBoxColumn14.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn14.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewCheckBoxColumn8
+ //
+ this.dataGridViewCheckBoxColumn8.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewCheckBoxColumn8.HeaderText = "B";
+ this.dataGridViewCheckBoxColumn8.Name = "dataGridViewCheckBoxColumn8";
+ this.dataGridViewCheckBoxColumn8.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ //
+ // dataGridViewTextBoxColumn15
+ //
+ this.dataGridViewTextBoxColumn15.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewTextBoxColumn15.HeaderText = "Address";
+ this.dataGridViewTextBoxColumn15.Name = "dataGridViewTextBoxColumn15";
+ this.dataGridViewTextBoxColumn15.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn15.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewTextBoxColumn16
+ //
+ this.dataGridViewTextBoxColumn16.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+ this.dataGridViewTextBoxColumn16.HeaderText = "Disassembly";
+ this.dataGridViewTextBoxColumn16.Name = "dataGridViewTextBoxColumn16";
+ this.dataGridViewTextBoxColumn16.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn16.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewCheckBoxColumn9
+ //
+ this.dataGridViewCheckBoxColumn9.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewCheckBoxColumn9.HeaderText = "B";
+ this.dataGridViewCheckBoxColumn9.Name = "dataGridViewCheckBoxColumn9";
+ this.dataGridViewCheckBoxColumn9.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ //
+ // dataGridViewTextBoxColumn17
+ //
+ this.dataGridViewTextBoxColumn17.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader;
+ this.dataGridViewTextBoxColumn17.HeaderText = "Address";
+ this.dataGridViewTextBoxColumn17.Name = "dataGridViewTextBoxColumn17";
+ this.dataGridViewTextBoxColumn17.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn17.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // dataGridViewTextBoxColumn18
+ //
+ this.dataGridViewTextBoxColumn18.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+ this.dataGridViewTextBoxColumn18.HeaderText = "Source";
+ this.dataGridViewTextBoxColumn18.Name = "dataGridViewTextBoxColumn18";
+ this.dataGridViewTextBoxColumn18.ReadOnly = true;
+ this.dataGridViewTextBoxColumn18.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn18.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
+ // CPDebugger
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(1274, 1138);
+ this.ControlBox = false;
+ this.Controls.Add(this.IOPSourceBox);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.KeyPreview = true;
+ this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "CPDebugger";
+ this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+ this.Text = "CP Debugger";
+ this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.CPDebugger_FormClosed);
+ this.IOPSourceBox.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this.Disassembly)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.SourceDisplay)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+ private System.Windows.Forms.GroupBox IOPSourceBox;
+ private SourceDisplay SourceDisplay;
+ private System.Windows.Forms.ListBox SourceFiles;
+ private System.Windows.Forms.DataGridViewCheckBoxColumn dataGridViewCheckBoxColumn3;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn5;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn6;
+ private MicrocodeDisplay Disassembly;
+ private System.Windows.Forms.DataGridViewCheckBoxColumn dataGridViewCheckBoxColumn1;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn1;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn2;
+ private System.Windows.Forms.DataGridViewCheckBoxColumn dataGridViewCheckBoxColumn2;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn3;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn4;
+ private System.Windows.Forms.DataGridViewCheckBoxColumn dataGridViewCheckBoxColumn4;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn7;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn8;
+ private System.Windows.Forms.DataGridViewCheckBoxColumn dataGridViewCheckBoxColumn5;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn9;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn10;
+ private System.Windows.Forms.DataGridViewCheckBoxColumn dataGridViewCheckBoxColumn6;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn11;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn12;
+ private System.Windows.Forms.DataGridViewCheckBoxColumn dataGridViewCheckBoxColumn7;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn13;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn14;
+ private System.Windows.Forms.DataGridViewCheckBoxColumn dataGridViewCheckBoxColumn8;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn15;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn16;
+ private System.Windows.Forms.DataGridViewCheckBoxColumn dataGridViewCheckBoxColumn9;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn17;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn18;
+ }
+}
\ No newline at end of file
diff --git a/D/Debugger/CPDebugger.cs b/D/Debugger/CPDebugger.cs
new file mode 100644
index 0000000..1b81a0b
--- /dev/null
+++ b/D/Debugger/CPDebugger.cs
@@ -0,0 +1,304 @@
+/*
+ BSD 2-Clause License
+
+ Copyright Vulcan Inc. 2017-2018 and Living Computer Museum + Labs 2018
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Windows.Forms;
+
+namespace D.Debugger
+{
+ public partial class CPDebugger : Form
+ {
+ public CPDebugger(DSystem system)
+ {
+ InitializeComponent();
+
+ _system = system;
+
+ SourceDisplay.SetSourceRoot(Path.Combine("CP", "Source"));
+
+ _loadMap = new MicrocodeLoadMap();
+ _loadMap.Load(Path.Combine("CP", "Source", "load_map.txt"));
+
+ _sourceMaps = new List();
+
+ Disassembly.AttachCP(system.CP);
+
+ PopulateSourceList();
+ }
+
+ public void DisplayCurrentCode()
+ {
+ RefreshSourceMaps();
+
+ //
+ // Select active files in the source file list
+ //
+ SourceFiles.ClearSelected();
+
+ foreach(SourceMap s in _sourceMaps)
+ {
+ foreach(string fileName in s.GetSourceFiles())
+ {
+ for (int i = 0; i < SourceFiles.Items.Count; i++)
+ {
+ if (fileName == (string)SourceFiles.Items[i])
+ {
+ SourceFiles.SetSelected(i, true);
+ }
+ }
+ }
+ }
+
+ //
+ // Find the source line that matches the current TPC, if any.
+ //
+ int tpc = _system.CP.TPC[(int)_system.CP.CurrentTask];
+
+ foreach (SourceMap s in _sourceMaps)
+ {
+ SourceEntry entry = s.GetExactSourceForAddress((ushort)tpc);
+
+ if (entry != null)
+ {
+ // WE GOT ONE!!!
+ SourceDisplay.AttachMap(s);
+ SourceDisplay.SelectSourceEntry(entry, false, false /* cp */);
+
+ // Select the source file in the source list
+ for (int i = 0; i < SourceFiles.Items.Count; i++)
+ {
+ if (entry.SourcePath == (string)SourceFiles.Items[i])
+ {
+ SourceFiles.SetSelected(i, true);
+ }
+ }
+
+ break;
+ }
+ }
+
+ //
+ // Highlight the line in the disassembly as well.
+ //
+ Disassembly.SelectAddress(tpc);
+ }
+
+ public SourceEntry GetSymbolForAddress(int address)
+ {
+ RefreshSourceMaps();
+
+ SourceEntry entry = null;
+
+ foreach (SourceMap s in _sourceMaps)
+ {
+ entry = s.GetSourceForAddress((ushort)address);
+
+ if (entry != null)
+ {
+ break;
+ }
+ }
+
+ return entry;
+ }
+
+ public void Save()
+ {
+ SaveSourceMaps();
+ }
+
+ private void PopulateSourceList()
+ {
+ SourceFiles.Items.Clear();
+
+ // TODO: factor out path generation
+ IEnumerable files = Directory.EnumerateFiles(Path.Combine("CP", "Source"), "*.mc,v", SearchOption.TopDirectoryOnly);
+
+ foreach(string file in files)
+ {
+ SourceFiles.Items.Add(Path.GetFileName(file));
+ }
+ }
+
+ private void OnSourceFilesClicked(object sender, EventArgs e)
+ {
+
+ }
+
+ private void OnSourceDisplayMouseClick(object sender, MouseEventArgs e)
+ {
+ //
+ // On right click when unmapped file is displayed, we will bring up the map dialog.
+ //
+ if (e.Button == MouseButtons.Right)
+ {
+ if (SourceDisplay.ReadOnly)
+ {
+ LoadMapDialog mapDialog = new LoadMapDialog(SourceDisplay.CurrentSourceFile, _loadMap, _sourceMaps, _system.CP.MicrocodeRam);
+ DialogResult res = mapDialog.ShowDialog(this);
+
+ if (res == DialogResult.OK)
+ {
+ RefreshSourceMaps();
+ SourceDisplay.ReadOnly = false;
+ SourceDisplay.AttachMap(mapDialog.SelectedMap);
+ }
+ }
+ }
+ }
+
+ private void OnSourceFilesDoubleClicked(object sender, EventArgs e)
+ {
+ string selectedFile = (string)SourceFiles.SelectedItem;
+
+ //
+ // If none of the source maps contain this file, we will display the source in read-only mode
+ // (no annotations allowed).
+ //
+ RefreshSourceMaps();
+
+ bool mapped = false;
+
+ foreach (SourceMap m in _sourceMaps)
+ {
+ if (m.GetSourceFiles().Contains(selectedFile))
+ {
+ SourceDisplay.AttachMap(m);
+ mapped = true;
+ break;
+ }
+ }
+
+ SourceDisplay.SelectSourceEntry(new SourceEntry((string)SourceFiles.SelectedItem, new string[] { }, 0, 1), !mapped, false /* cp */);
+ }
+
+ private void CPDebugger_FormClosed(object sender, FormClosedEventArgs e)
+ {
+ _loadMap.Save(Path.Combine("CP", "Source", "load_map.txt")); // TODO: move to constant
+ SaveSourceMaps();
+ }
+
+ private void RefreshSourceMaps()
+ {
+ List mapEntries = _loadMap.FindEntries(_system.CP.MicrocodeRam);
+
+ //
+ // See if any entries have changed, if so reload source maps.
+ //
+ bool changed = _mapEntries == null || mapEntries.Count != _mapEntries.Count;
+
+ if (!changed)
+ {
+ for (int i = 0; i < mapEntries.Count; i++)
+ {
+ //
+ // This assumes that ordering remains constant, which works at the moment.
+ //
+ if (mapEntries[i].Name != _mapEntries[i].Name)
+ {
+ changed = true;
+ break;
+ }
+ }
+ }
+
+ if (changed)
+ {
+ //
+ // Commit any existing source maps back to disk.
+ //
+ SaveSourceMaps();
+
+ // Build a new set of source maps.
+ _sourceMaps.Clear();
+ _mapEntries = mapEntries;
+
+ foreach (LoadMapEntry e in _mapEntries)
+ {
+ SourceMap newMap = new SourceMap(
+ e.Name,
+ Path.Combine("CP", "Source", e.MapName),
+ Path.Combine("CP", "Source"));
+
+ _sourceMaps.Add(newMap);
+ }
+ }
+ }
+
+ private void SaveSourceMaps()
+ {
+ foreach (SourceMap m in _sourceMaps)
+ {
+ m.Save();
+ }
+ }
+
+ private MicrocodeLoadMap _loadMap;
+ private List _mapEntries;
+ private List _sourceMaps;
+
+ private DSystem _system;
+
+ private void OnSourceDisplaySelectionChanged(object sender, EventArgs e)
+ {
+ //
+ // Sync the disassembly display with the selected source address, if possible.
+ //
+ int address = SourceDisplay.SelectedAddress;
+
+ if (address != -1 && Disassembly.SelectedAddress != address)
+ {
+ Disassembly.SelectAddress(address);
+ }
+ }
+
+ private void OnDisassemblySelectionChanged(object sender, EventArgs e)
+ {
+ //
+ // Sync the source display with the selected disassembly address, if possible.
+ //
+ int address = Disassembly.SelectedAddress;
+
+ //
+ // TODO: we should search through all source maps, not just the current one.
+ //
+ if (SourceDisplay.SourceMap != null && address != -1 && SourceDisplay.SelectedAddress != address)
+ {
+ SourceEntry entry = SourceDisplay.SourceMap.GetSourceForAddress((ushort)address);
+
+ if (entry != null && !string.IsNullOrWhiteSpace(entry.SourcePath))
+ {
+ SourceDisplay.SelectSourceEntry(entry, false, false /* cp */);
+ }
+ }
+ }
+ }
+}
diff --git a/D/Debugger/CPDebugger.resx b/D/Debugger/CPDebugger.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/D/Debugger/CPDebugger.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/D/Debugger/DebuggerMain.Designer.cs b/D/Debugger/DebuggerMain.Designer.cs
new file mode 100644
index 0000000..56d675f
--- /dev/null
+++ b/D/Debugger/DebuggerMain.Designer.cs
@@ -0,0 +1,109 @@
+/*
+ BSD 2-Clause License
+
+ Copyright Vulcan Inc. 2017-2018 and Living Computer Museum + Labs 2018
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+namespace D.Debugger
+{
+ partial class DebuggerMain
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.DebugOutput = new System.Windows.Forms.TextBox();
+ this.DebuggerInput = new System.Windows.Forms.TextBox();
+ this.SuspendLayout();
+ //
+ // DebugOutput
+ //
+ this.DebugOutput.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.DebugOutput.Location = new System.Drawing.Point(3, 12);
+ this.DebugOutput.Multiline = true;
+ this.DebugOutput.Name = "DebugOutput";
+ this.DebugOutput.ReadOnly = true;
+ this.DebugOutput.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
+ this.DebugOutput.Size = new System.Drawing.Size(837, 605);
+ this.DebugOutput.TabIndex = 3;
+ //
+ // DebuggerInput
+ //
+ this.DebuggerInput.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.DebuggerInput.Location = new System.Drawing.Point(3, 622);
+ this.DebuggerInput.Multiline = true;
+ this.DebuggerInput.Name = "DebuggerInput";
+ this.DebuggerInput.Size = new System.Drawing.Size(837, 20);
+ this.DebuggerInput.TabIndex = 2;
+ this.DebuggerInput.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.DebuggerInput_PreviewKeyDown);
+ //
+ // DebuggerMain
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(845, 647);
+ this.Controls.Add(this.DebugOutput);
+ this.Controls.Add(this.DebuggerInput);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.KeyPreview = true;
+ this.MaximizeBox = false;
+ this.Name = "DebuggerMain";
+ this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+ this.Text = "Debugger Console";
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.OnFormClosing);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TextBox DebugOutput;
+ private System.Windows.Forms.TextBox DebuggerInput;
+ }
+}
\ No newline at end of file
diff --git a/D/Debugger/DebuggerMain.cs b/D/Debugger/DebuggerMain.cs
new file mode 100644
index 0000000..eda5ff6
--- /dev/null
+++ b/D/Debugger/DebuggerMain.cs
@@ -0,0 +1,1336 @@
+/*
+ BSD 2-Clause License
+
+ Copyright Vulcan Inc. 2017-2018 and Living Computer Museum + Labs 2018
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+using D.CP;
+using D.IO;
+using D.IOP;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Windows.Forms;
+
+namespace D.Debugger
+{
+ public enum DebuggerReason
+ {
+ UserInvoked,
+ Error,
+ }
+
+ public partial class DebuggerMain : Form
+ {
+ public DebuggerMain(DSystem system, DebuggerReason reason, string message)
+ {
+ InitializeComponent();
+
+ _reason = reason;
+ _entryMessage = message;
+ _system = system;
+ }
+
+ protected override void OnLoad(EventArgs e)
+ {
+ //
+ // Pop up some debugger source windows.
+ //
+ _iopDebugger = new IOPDebugger(_system);
+ _iopDebugger.Show();
+
+ _cpDebugger = new CPDebugger(_system);
+ _cpDebugger.Show();
+
+ this.BringToFront();
+
+ switch(_reason)
+ {
+ case DebuggerReason.UserInvoked:
+ WriteLine(_entryMessage);
+ break;
+
+ case DebuggerReason.Error:
+ WriteLine(_entryMessage);
+ PrintIOPStatus();
+ PrintCPStatus();
+ PrintMesaStatus();
+ break;
+ }
+
+ base.OnLoad(e);
+ }
+
+ protected override void OnKeyDown(KeyEventArgs e)
+ {
+ // We just intercept Ctrl+C here
+ if (e.Control && e.KeyCode == Keys.C && _system.IsExecuting)
+ {
+ WriteLine("*user break*");
+ StopExecution();
+ DisplayCurrentCode();
+ e.Handled = true;
+ }
+ else
+ {
+ base.OnKeyDown(e);
+ }
+ }
+
+ private void DebuggerInput_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
+ {
+ if (e.KeyCode == Keys.Enter)
+ {
+ WriteLine(String.Format("> {0}", DebuggerInput.Text));
+
+ try
+ {
+ ExecuteCommand(DebuggerInput.Text);
+ }
+ catch(Exception ex)
+ {
+ WriteLine(ex.Message);
+ }
+
+ // Clear input line for next input
+ DebuggerInput.Text = String.Empty;
+ }
+ }
+
+ private void ExecuteCommand(string command)
+ {
+ if (string.IsNullOrWhiteSpace(command))
+ {
+ command = _lastCommand;
+ }
+
+ string[] tokens = command.Trim().Split(' ');
+
+ if (tokens.Length == 0)
+ {
+ // Nothing to do
+ return;
+ }
+
+ switch (tokens[0].ToLowerInvariant())
+ {
+ case ".": // redisplay status
+ DisplayCurrentCode();
+ PrintIOPStatus();
+ PrintCPStatus();
+ break;
+
+ case "i": // single step IOP
+ StartExecution(true, false, false);
+ StopExecution(); // wait for exec to finish
+ DisplayCurrentCode();
+ PrintIOPStatus();
+ break;
+
+ case "s": // single step CP
+ _stepCount = 0;
+ StartExecution(false, true, false);
+ StopExecution(); // wait for exec to finish
+ DisplayCurrentCode();
+ PrintCPStatus();
+ break;
+
+ case "m": // single step Mesa macrocode
+ StartExecution(false, false, true);
+ StopExecution(); // wait for exec to finish
+ DisplayCurrentCode();
+ PrintMesaStatus();
+ break;
+
+ case "g": // run system
+ StartExecution(false, false, false /* normal execution */);
+ break;
+
+ case "r": // reset system
+ _system.Reset();
+ WriteLine("System reset.");
+ break;
+
+ case "tpc": // print TPC registers
+ DisplayTPCRegisters();
+ break;
+
+ case "task": // select Task to debug (skips over microcode execution for other tasks while single-stepping)
+ switch (tokens.Length)
+ {
+ case 2:
+ if (tokens[1].ToLowerInvariant() != "all")
+ {
+ // Step through a specific task only.
+ _debugTask = (TaskType)Enum.Parse(typeof(TaskType), tokens[1], true);
+ _debugSpecificTask = true;
+ }
+ else
+ {
+ // Step through all tasks
+ _debugSpecificTask = false;
+ }
+ break;
+
+ default:
+ WriteLine("task ");
+ break;
+ }
+ break;
+
+ case "id": // dump IOP memory
+ switch(tokens.Length)
+ {
+ case 2:
+ DumpMemory(Convert.ToUInt16(tokens[1], 16), 1, null);
+ break;
+
+ case 3:
+ DumpMemory(Convert.ToUInt16(tokens[1], 16), Convert.ToUInt16(tokens[2], 16), null);
+ break;
+
+ case 4:
+ DumpMemory(Convert.ToUInt16(tokens[1], 16), Convert.ToUInt16(tokens[2], 16), tokens[3]);
+ break;
+
+ default:
+ WriteLine("id [count] [file]");
+ break;
+ }
+ break;
+
+ case "cd": // dump CP memory
+ switch (tokens.Length)
+ {
+ case 2:
+ DumpCPMemory(Convert.ToUInt32(tokens[1], 16), 1, null);
+ break;
+
+ case 3:
+ DumpCPMemory(Convert.ToUInt32(tokens[1], 16), Convert.ToUInt16(tokens[2], 16), null);
+ break;
+
+ case 4:
+ DumpCPMemory(Convert.ToUInt32(tokens[1], 16), Convert.ToUInt16(tokens[2], 16), tokens[3]);
+ break;
+
+ default:
+ WriteLine("cd [count] [file]");
+ break;
+ }
+ break;
+
+ case "fd": // dump floppy sector
+ switch(tokens.Length)
+ {
+ case 4:
+ DumpFloppySector(Convert.ToUInt16(tokens[1], 10),
+ Convert.ToUInt16(tokens[2], 10),
+ Convert.ToUInt16(tokens[3], 10),
+ null);
+ break;
+
+ case 5:
+ DumpFloppySector(Convert.ToUInt16(tokens[1], 10),
+ Convert.ToUInt16(tokens[2], 10),
+ Convert.ToUInt16(tokens[3], 10),
+ tokens[4]);
+ break;
+
+ default:
+ WriteLine("id