mirror of
https://github.com/livingcomputermuseum/Darkstar.git
synced 2026-03-30 19:58:59 +00:00
Initial commit to public repository.
This commit is contained in:
63
.gitattributes
vendored
Normal file
63
.gitattributes
vendored
Normal file
@@ -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
|
||||
261
.gitignore
vendored
Normal file
261
.gitignore
vendored
Normal file
@@ -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
|
||||
73
D.sln
Normal file
73
D.sln
Normal file
@@ -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
|
||||
48
D/App.config
Normal file
48
D/App.config
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||
<section name="D.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
</startup>
|
||||
<userSettings>
|
||||
<D.Properties.Settings>
|
||||
<setting name="HardDriveImage" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="FloppyDriveImage" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="ThrottleSpeed" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="DisplayScale" serializeAs="String">
|
||||
<value>1</value>
|
||||
</setting>
|
||||
<setting name="HostAddress" serializeAs="String">
|
||||
<value>2852201285</value>
|
||||
</setting>
|
||||
<setting name="HostPacketInterfaceName" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="MemorySize" serializeAs="String">
|
||||
<value>1024</value>
|
||||
</setting>
|
||||
<setting name="SlowPhosphor" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="TODDateTime" serializeAs="String">
|
||||
<value>1979-12-10</value>
|
||||
</setting>
|
||||
<setting name="TODSetMode" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
<setting name="TODDate" serializeAs="String">
|
||||
<value>1955-11-05</value>
|
||||
</setting>
|
||||
</D.Properties.Settings>
|
||||
</userSettings>
|
||||
</configuration>
|
||||
807
D/CP/AM2901.cs
Normal file
807
D/CP/AM2901.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public class AM2901
|
||||
{
|
||||
static AM2901()
|
||||
{
|
||||
BuildTables();
|
||||
}
|
||||
|
||||
public AM2901()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ushort[] R
|
||||
{
|
||||
get { return _r; }
|
||||
}
|
||||
|
||||
public ushort Q
|
||||
{
|
||||
get { return _q; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the ALU operation specified by the given microinstruction.
|
||||
/// </summary>
|
||||
/// <param name="i">The microinstruction</param>
|
||||
/// <param name="d">The ALU D input</param>
|
||||
/// <param name="carryIn">The ALU Carry in</param>
|
||||
/// <param name="loadMAR">Whether this operation is taking place during an MAR<- operation,
|
||||
/// in which case the top half of the ALU needs to be treated specially.</param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the ALU operation specified by the given microinstruction with all condition flags
|
||||
/// calculated, even for logical operations. This is significantly slower than Execute().
|
||||
/// </summary>
|
||||
/// <param name="i">The microinstruction</param>
|
||||
/// <param name="d">The ALU D input</param>
|
||||
/// <param name="carryIn">The ALU Carry in</param>
|
||||
/// <param name="loadMAR">Whether this operation is taking place during an MAR<- operation,
|
||||
/// in which case the top half of the ALU needs to be treated specially.</param>
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// TODO: replace with a nice table lookup.
|
||||
/// </summary>
|
||||
/// <param name="r"></param>
|
||||
/// <param name="s"></param>
|
||||
/// <param name="cIn"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
1634
D/CP/CentralProcessor.cs
Normal file
1634
D/CP/CentralProcessor.cs
Normal file
File diff suppressed because it is too large
Load Diff
712
D/CP/CentralProcessorIO.cs
Normal file
712
D/CP/CentralProcessorIO.cs
Normal file
@@ -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,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Dandelion Central Processor, I/O implmentation.
|
||||
/// This partial class implements the CP<->IOP communication channel,
|
||||
/// and IOP microcode loading logic.
|
||||
/// </summary>
|
||||
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
|
||||
//
|
||||
/// <summary>
|
||||
/// DMA Request: device request to obtain a DMA cycle from the DMA controller
|
||||
/// </summary>
|
||||
public bool DRQ
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_cpDmaMode) // DMA is enabled
|
||||
{
|
||||
if (_cpDmaIn)
|
||||
{
|
||||
return _outLatched;
|
||||
}
|
||||
else
|
||||
{
|
||||
return !_inLatched;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a single byte to the device from the DMA controller
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void DMAWrite(byte value)
|
||||
{
|
||||
WriteCPInBuffer(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a single byte from the device to the DMA controller
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes one byte of the microcode word currently pointed to by
|
||||
/// TPC[6].
|
||||
/// </summary>
|
||||
/// <param name="b"></param>
|
||||
/// <param name="value"></param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads one byte of the microcode word currently pointed to by
|
||||
/// TPC[6].
|
||||
/// </summary>
|
||||
/// <param name="b"></param>
|
||||
/// <param name="value"></param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
641
D/CP/MacroInstruction.cs
Normal file
641
D/CP/MacroInstruction.cs
Normal file
@@ -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,
|
||||
}
|
||||
/// <summary>
|
||||
/// Provides facilities for interpreting Mesa bytecodes
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
1267
D/CP/Microinstruction.cs
Normal file
1267
D/CP/Microinstruction.cs
Normal file
File diff suppressed because it is too large
Load Diff
43
D/CP/Source/BootKernel_map.txt
Normal file
43
D/CP/Source/BootKernel_map.txt
Normal file
@@ -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:
|
||||
# <symbol name 1>, .. , <symbol name N>: <address or value (hex)>,<line number(decimal) in current source file>
|
||||
# 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
|
||||
|
||||
256
D/CP/Source/CPMemTest_map.txt
Normal file
256
D/CP/Source/CPMemTest_map.txt
Normal file
@@ -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:
|
||||
# <symbol name 1>, .. , <symbol name N>: <address or value (hex)>,<line number(decimal) in current source file>
|
||||
# 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
|
||||
|
||||
263
D/CP/Source/FloppyInitial_map.txt
Normal file
263
D/CP/Source/FloppyInitial_map.txt
Normal file
@@ -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:
|
||||
# <symbol name 1>, .. , <symbol name N>: <address or value (hex)>,<line number(decimal) in current source file>
|
||||
# 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
|
||||
|
||||
572
D/CP/Source/Main_map.txt
Normal file
572
D/CP/Source/Main_map.txt
Normal file
@@ -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:
|
||||
# <symbol name 1>, .. , <symbol name N>: <address or value (hex)>,<line number(decimal) in current source file>
|
||||
# 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
|
||||
|
||||
89
D/CP/Source/MoonCycle_map.txt
Normal file
89
D/CP/Source/MoonCycle_map.txt
Normal file
@@ -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:
|
||||
# <symbol name 1>, .. , <symbol name N>: <address or value (hex)>,<line number(decimal) in current source file>
|
||||
# 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
|
||||
|
||||
267
D/CP/Source/MoonEthBTest_map.txt
Normal file
267
D/CP/Source/MoonEthBTest_map.txt
Normal file
@@ -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:
|
||||
# <symbol name 1>, .. , <symbol name N>: <address or value (hex)>,<line number(decimal) in current source file>
|
||||
# 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
|
||||
|
||||
17
D/CP/Source/MoonPortIn_map.txt
Normal file
17
D/CP/Source/MoonPortIn_map.txt
Normal file
@@ -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:
|
||||
# <symbol name 1>, .. , <symbol name N>: <address or value (hex)>,<line number(decimal) in current source file>
|
||||
# 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
|
||||
|
||||
27
D/CP/Source/MoonPortOut_map.txt
Normal file
27
D/CP/Source/MoonPortOut_map.txt
Normal file
@@ -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:
|
||||
# <symbol name 1>, .. , <symbol name N>: <address or value (hex)>,<line number(decimal) in current source file>
|
||||
# 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
|
||||
|
||||
42
D/CP/Source/Phase0Protected_map.txt
Normal file
42
D/CP/Source/Phase0Protected_map.txt
Normal file
@@ -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:
|
||||
# <symbol name 1>, .. , <symbol name N>: <address or value (hex)>,<line number(decimal) in current source file>
|
||||
# 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
|
||||
|
||||
46
D/CP/Source/Phase0_map.txt
Normal file
46
D/CP/Source/Phase0_map.txt
Normal file
@@ -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:
|
||||
# <symbol name 1>, .. , <symbol name N>: <address or value (hex)>,<line number(decimal) in current source file>
|
||||
# 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
|
||||
|
||||
18
D/CP/Source/SunlightO2_map.txt
Normal file
18
D/CP/Source/SunlightO2_map.txt
Normal file
@@ -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:
|
||||
# <symbol name 1>, .. , <symbol name N>: <address or value (hex)>,<line number(decimal) in current source file>
|
||||
# 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
|
||||
|
||||
164
D/CP/Source/SunlightO4_map.txt
Normal file
164
D/CP/Source/SunlightO4_map.txt
Normal file
@@ -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:
|
||||
# <symbol name 1>, .. , <symbol name N>: <address or value (hex)>,<line number(decimal) in current source file>
|
||||
# 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
|
||||
|
||||
183
D/CP/Source/SunlightO5_map.txt
Normal file
183
D/CP/Source/SunlightO5_map.txt
Normal file
@@ -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:
|
||||
# <symbol name 1>, .. , <symbol name N>: <address or value (hex)>,<line number(decimal) in current source file>
|
||||
# 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
|
||||
|
||||
13
D/CP/Source/load_map.txt
Normal file
13
D/CP/Source/load_map.txt
Normal file
@@ -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
|
||||
459
D/Configuration.cs
Normal file
459
D/Configuration.cs
Normal file
@@ -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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encapsulates user-configurable settings. To be enhanced.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// What kind of system we're running on. (Not technically configurable.)
|
||||
/// </summary>
|
||||
public static PlatformType Platform;
|
||||
|
||||
/// <summary>
|
||||
/// System memory size, in KW.
|
||||
/// </summary>
|
||||
public static uint MemorySize;
|
||||
|
||||
/// <summary>
|
||||
/// The currently loaded image for the hard disk.
|
||||
/// </summary>
|
||||
public static string HardDriveImage;
|
||||
|
||||
/// <summary>
|
||||
/// The currently loaded image for the floppy drive.
|
||||
/// </summary>
|
||||
public static string FloppyDriveImage;
|
||||
|
||||
/// <summary>
|
||||
/// The Ethernet host address for this Star.
|
||||
/// </summary>
|
||||
public static ulong HostID;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the Ethernet adaptor on the emulator host to use for Ethernet emulation
|
||||
/// </summary>
|
||||
public static string HostPacketInterfaceName;
|
||||
|
||||
/// <summary>
|
||||
/// Whether any packet interfaces are available on the host
|
||||
/// </summary>
|
||||
public static bool HostRawEthernetInterfacesAvailable;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to cap execution speed at native execution speed or not.
|
||||
/// </summary>
|
||||
public static bool ThrottleSpeed;
|
||||
|
||||
/// <summary>
|
||||
/// Scale factor to apply to the display.
|
||||
/// </summary>
|
||||
public static uint DisplayScale;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to apply a fake "slow phosphor" persistence to the emulated display.
|
||||
/// </summary>
|
||||
public static bool SlowPhosphor;
|
||||
|
||||
/// <summary>
|
||||
/// How to set the TOD clock at power up/reset
|
||||
/// </summary>
|
||||
public static TODPowerUpSetMode TODSetMode;
|
||||
|
||||
/// <summary>
|
||||
/// The specific date/time to set the TOD clock to if TODSetMode is "SpecificDateAndTime"
|
||||
/// </summary>
|
||||
public static DateTime TODDateTime;
|
||||
|
||||
/// <summary>
|
||||
/// The specific date to set the TOD clock to if TODSetMode is "SpecificDate"
|
||||
/// </summary>
|
||||
public static DateTime TODDate;
|
||||
|
||||
/// <summary>
|
||||
/// The components to enable debug logging for.
|
||||
/// </summary>
|
||||
public static LogComponent LogComponents;
|
||||
|
||||
/// <summary>
|
||||
/// The types of logging to enable.
|
||||
/// </summary>
|
||||
public static LogType LogTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Reads the current configuration file from the appropriate place.
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Commits the current configuration to the app's settings.
|
||||
/// </summary>
|
||||
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:
|
||||
// <Name>=<Value>
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
49
D/Conversion.cs
Normal file
49
D/Conversion.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Conversion from millseconds to nanoseconds
|
||||
/// </summary>
|
||||
public static readonly ulong MsecToNsec = 1000000;
|
||||
|
||||
/// <summary>
|
||||
/// Conversion from nanoseconds to milliseconds
|
||||
/// </summary>
|
||||
public static readonly double NsecToMsec = 0.000001;
|
||||
|
||||
/// <summary>
|
||||
/// Conversion from microseconds to nanoseconds
|
||||
/// </summary>
|
||||
public static readonly ulong UsecToNsec = 1000;
|
||||
}
|
||||
}
|
||||
BIN
D/Dandelion.ico
Normal file
BIN
D/Dandelion.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
34
D/Darkstar.cfg
Normal file
34
D/Darkstar.cfg
Normal file
@@ -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
|
||||
|
||||
306
D/Darkstar.csproj
Normal file
306
D/Darkstar.csproj
Normal file
@@ -0,0 +1,306 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{0590465E-1D91-4591-946E-EE3F7D82834B}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>D</RootNamespace>
|
||||
<AssemblyName>Darkstar</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="PacketDotNet, Version=0.13.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Sharp_Pcap.4.2.0\lib\PacketDotNet.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SDL2-CS, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SDL2-CS.dll.2.0.0.0\lib\net20\SDL2-CS.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SharpPcap, Version=4.2.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Sharp_Pcap.4.2.0\lib\SharpPcap.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Configuration.cs" />
|
||||
<Compile Include="Conversion.cs" />
|
||||
<Compile Include="CP\AM2901.cs" />
|
||||
<Compile Include="CP\CentralProcessor.cs" />
|
||||
<Compile Include="CP\CentralProcessorIO.cs" />
|
||||
<Compile Include="CP\MacroInstruction.cs" />
|
||||
<Compile Include="CP\Microinstruction.cs" />
|
||||
<Compile Include="Debugger\BreakpointManager.cs" />
|
||||
<Compile Include="Debugger\CPDebugger.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\CPDebugger.Designer.cs">
|
||||
<DependentUpon>CPDebugger.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\DebuggerMain.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\DebuggerMain.Designer.cs">
|
||||
<DependentUpon>DebuggerMain.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\IOPDebugger.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\IOPDebugger.Designer.cs">
|
||||
<DependentUpon>IOPDebugger.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\LoadMapDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\LoadMapDialog.Designer.cs">
|
||||
<DependentUpon>LoadMapDialog.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\MicrocodeLoadMap.cs" />
|
||||
<Compile Include="Debugger\SourceDisplay.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\MicrocodeDisplay.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\SourceMap.cs" />
|
||||
<Compile Include="Display\DisplayController.cs" />
|
||||
<Compile Include="Ethernet\HostEthernet.cs" />
|
||||
<Compile Include="Ethernet\IPacketInterface.cs" />
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UI\AboutBox.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\AboutBox.Designer.cs">
|
||||
<DependentUpon>AboutBox.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UI\ConfigurationDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\ConfigurationDialog.Designer.cs">
|
||||
<DependentUpon>ConfigurationDialog.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UI\DWindow-IO.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\DWindow.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UI\DWindow.Designer.cs">
|
||||
<DependentUpon>DWindow.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Ethernet\CRC32.cs" />
|
||||
<Compile Include="Ethernet\EthernetController.cs" />
|
||||
<Compile Include="HighResTimer.cs" />
|
||||
<Compile Include="IOP\DMAController.cs" />
|
||||
<Compile Include="IOP\FloppyController.cs" />
|
||||
<Compile Include="IOP\Keyboard.cs" />
|
||||
<Compile Include="IOP\Mouse.cs" />
|
||||
<Compile Include="IOP\TODClock.cs" />
|
||||
<Compile Include="IOP\Printer.cs" />
|
||||
<Compile Include="IO\FloppyDisk.cs" />
|
||||
<Compile Include="IO\FloppyDrive.cs" />
|
||||
<Compile Include="IOP\i8085.cs" />
|
||||
<Compile Include="IOP\I8085IOBus.cs" />
|
||||
<Compile Include="IOP\I8085MemoryBus.cs" />
|
||||
<Compile Include="IOP\IIOPDevice.cs" />
|
||||
<Compile Include="IOP\IOProcessor.cs" />
|
||||
<Compile Include="IOP\IOPMemoryBus.cs" />
|
||||
<Compile Include="IOP\IOPIOBus.cs" />
|
||||
<Compile Include="IOP\MiscIO.cs" />
|
||||
<Compile Include="IO\SA1000.cs" />
|
||||
<Compile Include="IO\ShugartController.cs" />
|
||||
<Compile Include="Logging\Log.cs" />
|
||||
<Compile Include="Memory\Memory.cs" />
|
||||
<Compile Include="Memory\MemoryController.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Scheduler.cs" />
|
||||
<Compile Include="System.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="app.manifest" />
|
||||
<None Include="Disks\130P26300-diags.IMD">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Disks\130P26301-install.IMD">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Disks\Harmony.img">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Disks\Lyric.img">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Disks\Medley.img">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Disks\ViewPoint-11-9-1990-18-38.img">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Disks\XDE.img">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Disks\XDE_5.0_BO1.IMD">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="IOP\PROM\537P03029.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="IOP\PROM\537P03030.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="IOP\PROM\537P03032.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="IOP\PROM\537P03700.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="CP\Source\BootKernel_map.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="CP\Source\CPMemTest_map.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="CP\Source\FloppyInitial_map.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="CP\Source\load_map.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="CP\Source\Main_map.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="CP\Source\MoonCycle_map.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="CP\Source\MoonEthBTest_map.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="CP\Source\MoonPortIn_map.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="CP\Source\MoonPortOut_map.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="CP\Source\Phase0Protected_map.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="CP\Source\Phase0_map.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="CP\Source\SunlightO2_map.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="CP\Source\SunlightO4_map.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="CP\Source\SunlightO5_map.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Dandelion.ico" />
|
||||
<Content Include="IOP\Source\SourceMap.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Notes\IOP.txt" />
|
||||
<Content Include="Notes\8085 code annotation.txt" />
|
||||
<Content Include="Notes\Ethernet.txt" />
|
||||
<Content Include="readme.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="SDL2.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="Darkstar.cfg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Debugger\CPDebugger.resx">
|
||||
<DependentUpon>CPDebugger.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\DebuggerMain.resx">
|
||||
<DependentUpon>DebuggerMain.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\IOPDebugger.resx">
|
||||
<DependentUpon>IOPDebugger.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\LoadMapDialog.resx">
|
||||
<DependentUpon>LoadMapDialog.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="UI\AboutBox.resx">
|
||||
<DependentUpon>AboutBox.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="UI\ConfigurationDialog.resx">
|
||||
<DependentUpon>ConfigurationDialog.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="UI\DWindow.resx">
|
||||
<DependentUpon>DWindow.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
178
D/Debugger/BreakpointManager.cs
Normal file
178
D/Debugger/BreakpointManager.cs
Normal file
@@ -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<BreakpointEntry> EnumerateBreakpoints()
|
||||
{
|
||||
List<BreakpointEntry> breakpoints = new List<BreakpointEntry>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
457
D/Debugger/CPDebugger.Designer.cs
generated
Normal file
457
D/Debugger/CPDebugger.Designer.cs
generated
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
304
D/Debugger/CPDebugger.cs
Normal file
304
D/Debugger/CPDebugger.cs
Normal file
@@ -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<SourceMap>();
|
||||
|
||||
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<string> 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<LoadMapEntry> 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<LoadMapEntry> _mapEntries;
|
||||
private List<SourceMap> _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 */);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
120
D/Debugger/CPDebugger.resx
Normal file
120
D/Debugger/CPDebugger.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
109
D/Debugger/DebuggerMain.Designer.cs
generated
Normal file
109
D/Debugger/DebuggerMain.Designer.cs
generated
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
1336
D/Debugger/DebuggerMain.cs
Normal file
1336
D/Debugger/DebuggerMain.cs
Normal file
File diff suppressed because it is too large
Load Diff
120
D/Debugger/DebuggerMain.resx
Normal file
120
D/Debugger/DebuggerMain.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
142
D/Debugger/IOPDebugger.Designer.cs
generated
Normal file
142
D/Debugger/IOPDebugger.Designer.cs
generated
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
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 IOPDebugger
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
|
||||
this.IOPSourceBox = new System.Windows.Forms.GroupBox();
|
||||
this.SourceFiles = new System.Windows.Forms.ListBox();
|
||||
this.SourceDisplay = new D.Debugger.SourceDisplay();
|
||||
this.IOPSourceBox.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.SourceDisplay)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// IOPSourceBox
|
||||
//
|
||||
this.IOPSourceBox.Controls.Add(this.SourceFiles);
|
||||
this.IOPSourceBox.Controls.Add(this.SourceDisplay);
|
||||
this.IOPSourceBox.Location = new System.Drawing.Point(7, 3);
|
||||
this.IOPSourceBox.Name = "IOPSourceBox";
|
||||
this.IOPSourceBox.Size = new System.Drawing.Size(837, 725);
|
||||
this.IOPSourceBox.TabIndex = 2;
|
||||
this.IOPSourceBox.TabStop = false;
|
||||
this.IOPSourceBox.Text = "IOP Source";
|
||||
//
|
||||
// SourceFiles
|
||||
//
|
||||
this.SourceFiles.FormattingEnabled = true;
|
||||
this.SourceFiles.Location = new System.Drawing.Point(7, 20);
|
||||
this.SourceFiles.Name = "SourceFiles";
|
||||
this.SourceFiles.Size = new System.Drawing.Size(139, 693);
|
||||
this.SourceFiles.TabIndex = 1;
|
||||
this.SourceFiles.DoubleClick += new System.EventHandler(this.SourceFiles_DoubleClick);
|
||||
//
|
||||
// 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;
|
||||
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.NullValue = null;
|
||||
dataGridViewCellStyle2.SelectionBackColor = System.Drawing.SystemColors.Highlight;
|
||||
dataGridViewCellStyle2.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
|
||||
dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
|
||||
this.SourceDisplay.DefaultCellStyle = dataGridViewCellStyle2;
|
||||
this.SourceDisplay.Location = new System.Drawing.Point(152, 19);
|
||||
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(679, 694);
|
||||
this.SourceDisplay.TabIndex = 0;
|
||||
this.SourceDisplay.VirtualMode = true;
|
||||
//
|
||||
// IOPDebugger
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoSize = true;
|
||||
this.ClientSize = new System.Drawing.Size(851, 732);
|
||||
this.ControlBox = false;
|
||||
this.Controls.Add(this.IOPSourceBox);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.KeyPreview = true;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "IOPDebugger";
|
||||
this.Text = "IOP Debugger - MP {0}";
|
||||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.IOPDebugger_FormClosed);
|
||||
this.IOPSourceBox.ResumeLayout(false);
|
||||
((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;
|
||||
}
|
||||
}
|
||||
119
D/Debugger/IOPDebugger.cs
Normal file
119
D/Debugger/IOPDebugger.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
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 IOPDebugger : Form
|
||||
{
|
||||
public IOPDebugger(DSystem system)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_system = system;
|
||||
|
||||
_sourceMap = new SourceMap("8085 ROM", "IOP\\Source\\SourceMap.txt", "IOP\\Source");
|
||||
|
||||
SourceDisplay.SetSourceRoot(Path.Combine("IOP", "Source"));
|
||||
SourceDisplay.AttachMap(_sourceMap);
|
||||
|
||||
PopulateSourceList();
|
||||
|
||||
DisplayCurrentCode();
|
||||
}
|
||||
|
||||
public SourceMap SourceMap
|
||||
{
|
||||
get { return _sourceMap; }
|
||||
}
|
||||
|
||||
public void DisplayCurrentCode()
|
||||
{
|
||||
SourceEntry entry = _sourceMap.GetSourceForAddress(_system.IOP.CPU.PC);
|
||||
|
||||
if (entry != null && !string.IsNullOrWhiteSpace(entry.SourcePath))
|
||||
{
|
||||
SourceDisplay.SelectSourceEntry(entry, false, true /* iop */);
|
||||
|
||||
|
||||
// Find the source entry in the file list and select it.
|
||||
for (int i = 0; i < SourceFiles.Items.Count; i++)
|
||||
{
|
||||
if ((string)SourceFiles.Items[i] == entry.SourcePath)
|
||||
{
|
||||
SourceFiles.SelectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Should show disassembly instead
|
||||
}
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
_sourceMap.Save();
|
||||
}
|
||||
|
||||
private void PopulateSourceList()
|
||||
{
|
||||
SourceFiles.Items.Clear();
|
||||
|
||||
// TODO: factor out path generation
|
||||
IEnumerable<string> files = Directory.EnumerateFiles(Path.Combine("IOP", "Source"), "*.asm,v", SearchOption.TopDirectoryOnly);
|
||||
|
||||
foreach(string file in files)
|
||||
{
|
||||
SourceFiles.Items.Add(Path.GetFileName(file));
|
||||
}
|
||||
}
|
||||
|
||||
private void SourceFiles_DoubleClick(object sender, EventArgs e)
|
||||
{
|
||||
SourceDisplay.SelectSourceEntry(new SourceEntry((string)SourceFiles.SelectedItem, new string[] { }, 0, 1), false, true /* iop */);
|
||||
}
|
||||
|
||||
private void IOPDebugger_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
_sourceMap.Save();
|
||||
}
|
||||
|
||||
private SourceMap _sourceMap;
|
||||
|
||||
private DSystem _system;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
120
D/Debugger/IOPDebugger.resx
Normal file
120
D/Debugger/IOPDebugger.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
235
D/Debugger/LoadMapDialog.Designer.cs
generated
Normal file
235
D/Debugger/LoadMapDialog.Designer.cs
generated
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
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 LoadMapDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.CurrentLoadsList = new System.Windows.Forms.ListBox();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.LoadNameText = new System.Windows.Forms.TextBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.LoadStartBox = new System.Windows.Forms.TextBox();
|
||||
this.LoadEndBox = new System.Windows.Forms.TextBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.CreateLoadButton = new System.Windows.Forms.Button();
|
||||
this.CancelCreateButton = new System.Windows.Forms.Button();
|
||||
this.AddButton = new System.Windows.Forms.Button();
|
||||
this.CancelAddButton = new System.Windows.Forms.Button();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.CancelAddButton);
|
||||
this.groupBox1.Controls.Add(this.AddButton);
|
||||
this.groupBox1.Controls.Add(this.CurrentLoadsList);
|
||||
this.groupBox1.Location = new System.Drawing.Point(5, 5);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(171, 137);
|
||||
this.groupBox1.TabIndex = 0;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "Add to Existing Microcode Load";
|
||||
//
|
||||
// CurrentLoadsList
|
||||
//
|
||||
this.CurrentLoadsList.FormattingEnabled = true;
|
||||
this.CurrentLoadsList.Location = new System.Drawing.Point(7, 16);
|
||||
this.CurrentLoadsList.Name = "CurrentLoadsList";
|
||||
this.CurrentLoadsList.Size = new System.Drawing.Size(156, 82);
|
||||
this.CurrentLoadsList.TabIndex = 0;
|
||||
this.CurrentLoadsList.SelectedIndexChanged += new System.EventHandler(this.OnSelectionChanged);
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.CancelCreateButton);
|
||||
this.groupBox2.Controls.Add(this.CreateLoadButton);
|
||||
this.groupBox2.Controls.Add(this.label3);
|
||||
this.groupBox2.Controls.Add(this.label2);
|
||||
this.groupBox2.Controls.Add(this.LoadEndBox);
|
||||
this.groupBox2.Controls.Add(this.LoadStartBox);
|
||||
this.groupBox2.Controls.Add(this.label1);
|
||||
this.groupBox2.Controls.Add(this.LoadNameText);
|
||||
this.groupBox2.Location = new System.Drawing.Point(182, 5);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(178, 137);
|
||||
this.groupBox2.TabIndex = 1;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "Add to New Microcode Load";
|
||||
//
|
||||
// LoadNameText
|
||||
//
|
||||
this.LoadNameText.Location = new System.Drawing.Point(51, 17);
|
||||
this.LoadNameText.Name = "LoadNameText";
|
||||
this.LoadNameText.Size = new System.Drawing.Size(103, 20);
|
||||
this.LoadNameText.TabIndex = 0;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(10, 20);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(38, 13);
|
||||
this.label1.TabIndex = 1;
|
||||
this.label1.Text = "Name:";
|
||||
//
|
||||
// LoadStartBox
|
||||
//
|
||||
this.LoadStartBox.Location = new System.Drawing.Point(51, 44);
|
||||
this.LoadStartBox.Name = "LoadStartBox";
|
||||
this.LoadStartBox.Size = new System.Drawing.Size(100, 20);
|
||||
this.LoadStartBox.TabIndex = 2;
|
||||
//
|
||||
// LoadEndBox
|
||||
//
|
||||
this.LoadEndBox.Location = new System.Drawing.Point(51, 71);
|
||||
this.LoadEndBox.Name = "LoadEndBox";
|
||||
this.LoadEndBox.Size = new System.Drawing.Size(100, 20);
|
||||
this.LoadEndBox.TabIndex = 3;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(10, 47);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(32, 13);
|
||||
this.label2.TabIndex = 4;
|
||||
this.label2.Text = "Start:";
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(10, 74);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(29, 13);
|
||||
this.label3.TabIndex = 5;
|
||||
this.label3.Text = "End:";
|
||||
//
|
||||
// CreateLoadButton
|
||||
//
|
||||
this.CreateLoadButton.Location = new System.Drawing.Point(13, 104);
|
||||
this.CreateLoadButton.Name = "CreateLoadButton";
|
||||
this.CreateLoadButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.CreateLoadButton.TabIndex = 6;
|
||||
this.CreateLoadButton.Text = "Create";
|
||||
this.CreateLoadButton.UseVisualStyleBackColor = true;
|
||||
this.CreateLoadButton.Click += new System.EventHandler(this.CreateLoadButton_Click);
|
||||
//
|
||||
// CancelCreateButton
|
||||
//
|
||||
this.CancelCreateButton.Location = new System.Drawing.Point(94, 104);
|
||||
this.CancelCreateButton.Name = "CancelCreateButton";
|
||||
this.CancelCreateButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.CancelCreateButton.TabIndex = 7;
|
||||
this.CancelCreateButton.Text = "Cancel";
|
||||
this.CancelCreateButton.UseVisualStyleBackColor = true;
|
||||
this.CancelCreateButton.Click += new System.EventHandler(this.CancelCreateButton_Click);
|
||||
//
|
||||
// AddButton
|
||||
//
|
||||
this.AddButton.Location = new System.Drawing.Point(7, 104);
|
||||
this.AddButton.Name = "AddButton";
|
||||
this.AddButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.AddButton.TabIndex = 7;
|
||||
this.AddButton.Text = "Add";
|
||||
this.AddButton.UseVisualStyleBackColor = true;
|
||||
this.AddButton.Click += new System.EventHandler(this.AddButton_Click);
|
||||
//
|
||||
// CancelAddButton
|
||||
//
|
||||
this.CancelAddButton.Location = new System.Drawing.Point(88, 104);
|
||||
this.CancelAddButton.Name = "CancelAddButton";
|
||||
this.CancelAddButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.CancelAddButton.TabIndex = 8;
|
||||
this.CancelAddButton.Text = "Cancel";
|
||||
this.CancelAddButton.UseVisualStyleBackColor = true;
|
||||
this.CancelAddButton.Click += new System.EventHandler(this.CancelAddButton_Click);
|
||||
//
|
||||
// LoadMapDialog
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(365, 146);
|
||||
this.Controls.Add(this.groupBox2);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.Name = "LoadMapDialog";
|
||||
this.Text = "Select Microcode Load For File";
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
this.groupBox2.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.Button CancelAddButton;
|
||||
private System.Windows.Forms.Button AddButton;
|
||||
private System.Windows.Forms.ListBox CurrentLoadsList;
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
private System.Windows.Forms.Button CancelCreateButton;
|
||||
private System.Windows.Forms.Button CreateLoadButton;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.TextBox LoadEndBox;
|
||||
private System.Windows.Forms.TextBox LoadStartBox;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.TextBox LoadNameText;
|
||||
}
|
||||
}
|
||||
140
D/Debugger/LoadMapDialog.cs
Normal file
140
D/Debugger/LoadMapDialog.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
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 LoadMapDialog : Form
|
||||
{
|
||||
/// <summary>
|
||||
/// Provide basic UI for adding new entries.
|
||||
/// TODO: It's kind of ugly that this is directly modifying input parameters; likely there should be a
|
||||
/// singleton LoadMap that maintains all of this that can be used to modify things.
|
||||
/// </summary>
|
||||
/// <param name="newFilePath"></param>
|
||||
/// <param name="loadMap"></param>
|
||||
/// <param name="sourceMaps"></param>
|
||||
/// <param name="microcodeRAM"></param>
|
||||
public LoadMapDialog(string newFilePath, MicrocodeLoadMap loadMap, List<SourceMap> sourceMaps, ulong[] microcodeRAM)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_newFilePath = newFilePath;
|
||||
_loadMap = loadMap;
|
||||
_sourceMaps = sourceMaps;
|
||||
_microcodeRAM = microcodeRAM;
|
||||
|
||||
_selectedMap = null;
|
||||
|
||||
//
|
||||
// Populate the existing map list
|
||||
//
|
||||
foreach (SourceMap s in sourceMaps)
|
||||
{
|
||||
CurrentLoadsList.Items.Add(s.MapName);
|
||||
}
|
||||
|
||||
CurrentLoadsList.ClearSelected();
|
||||
|
||||
DialogResult = DialogResult.Cancel;
|
||||
}
|
||||
|
||||
public SourceMap SelectedMap
|
||||
{
|
||||
get { return _selectedMap; }
|
||||
}
|
||||
|
||||
private void OnSelectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
AddButton.Enabled = CurrentLoadsList.SelectedItem != null;
|
||||
}
|
||||
|
||||
private void CancelAddButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
DialogResult = DialogResult.Cancel;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void CancelCreateButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
DialogResult = DialogResult.Cancel;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void AddButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
//
|
||||
// Add the file to the selected map.
|
||||
//
|
||||
_selectedMap = _sourceMaps[CurrentLoadsList.SelectedIndex];
|
||||
|
||||
_selectedMap.AddSourceFile(_newFilePath);
|
||||
DialogResult = DialogResult.OK;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void CreateLoadButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
LoadMapEntry newEntry = _loadMap.AddEntry(
|
||||
LoadNameText.Text,
|
||||
Convert.ToInt32(LoadStartBox.Text.Trim(), 16),
|
||||
Convert.ToInt32(LoadEndBox.Text.Trim(), 16),
|
||||
_microcodeRAM
|
||||
);
|
||||
|
||||
_selectedMap = new SourceMap(
|
||||
newEntry.Name,
|
||||
Path.Combine("CP", "Source", newEntry.MapName),
|
||||
Path.Combine("CP", "Source")); // TODO: define this path somewheres.
|
||||
|
||||
_sourceMaps.Add(_selectedMap);
|
||||
|
||||
DialogResult = DialogResult.OK;
|
||||
this.Close();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
MessageBox.Show("Error: {0}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private SourceMap _selectedMap;
|
||||
|
||||
private string _newFilePath;
|
||||
private MicrocodeLoadMap _loadMap;
|
||||
private List<SourceMap> _sourceMaps;
|
||||
private ulong[] _microcodeRAM;
|
||||
}
|
||||
}
|
||||
120
D/Debugger/LoadMapDialog.resx
Normal file
120
D/Debugger/LoadMapDialog.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
202
D/Debugger/MicrocodeDisplay.cs
Normal file
202
D/Debugger/MicrocodeDisplay.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
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 System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace D.Debugger
|
||||
{
|
||||
/// <summary>
|
||||
/// Presents a view of microcode disassembly, with addresses and breakpoints.
|
||||
///
|
||||
/// MicrocodeDisplay provides a three-column view:
|
||||
///
|
||||
/// | Breakpoint | Address | Disassembly |
|
||||
/// -------------------------------------------------------------------------
|
||||
///
|
||||
/// Breakpoint is editable (to allow setting breakpoints)
|
||||
///
|
||||
/// TODO: This is pretty similar in functionality to the IOP source view. I'm
|
||||
/// sure there's some code that could be shared...
|
||||
///
|
||||
/// </summary>
|
||||
public class MicrocodeDisplay : DataGridView
|
||||
{
|
||||
public MicrocodeDisplay()
|
||||
{
|
||||
this.VirtualMode = true;
|
||||
this.RowHeadersVisible = false;
|
||||
this.ReadOnly = false;
|
||||
|
||||
AddCheckboxColumn("B", DataGridViewAutoSizeColumnMode.ColumnHeader);
|
||||
AddColumn("Address", true, DataGridViewAutoSizeColumnMode.ColumnHeader);
|
||||
AddColumn("Disassembly", true, DataGridViewAutoSizeColumnMode.Fill);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the address selected in the disassembly. Since the row index and the
|
||||
/// address are identical, we just return the selected row index (if any).
|
||||
/// Returns -1 if nothing is selected.
|
||||
/// </summary>
|
||||
public int SelectedAddress
|
||||
{
|
||||
get { return this.SelectedCells.Count > 0 ? this.SelectedCells[0].RowIndex : -1; }
|
||||
}
|
||||
|
||||
public void AttachCP(CentralProcessor cp)
|
||||
{
|
||||
_cp = cp;
|
||||
|
||||
this.RowCount = cp.MicrocodeRam.Length;
|
||||
}
|
||||
|
||||
public void SelectAddress(int address)
|
||||
{
|
||||
if (address < 0 || address > _cp.MicrocodeRam.Length)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid address.");
|
||||
}
|
||||
|
||||
//
|
||||
// Clear the current selection and move the selection to the first cell
|
||||
// of the requested line.
|
||||
//
|
||||
this.ClearSelection();
|
||||
this.Rows[address].Selected = true;
|
||||
this.CurrentCell = this.Rows[address].Cells[0];
|
||||
}
|
||||
|
||||
protected override void OnCurrentCellDirtyStateChanged(EventArgs e)
|
||||
{
|
||||
if (IsCurrentCellDirty)
|
||||
{
|
||||
//
|
||||
// Force checkbox changes to commit immediately (rather than
|
||||
// the default, which is to commit them when focus leaves the cell, which
|
||||
// is really annoying.
|
||||
//
|
||||
if (CurrentCell is DataGridViewCheckBoxCell)
|
||||
{
|
||||
CommitEdit(DataGridViewDataErrorContexts.Commit);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnCurrentCellDirtyStateChanged(e);
|
||||
}
|
||||
|
||||
protected override void OnCellValueChanged(DataGridViewCellEventArgs e)
|
||||
{
|
||||
if (e.RowIndex < 0 || e.RowIndex > _cp.MicrocodeRam.Length)
|
||||
{
|
||||
base.OnCellValueChanged(e);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.ColumnIndex)
|
||||
{
|
||||
case 0: // breakpoint
|
||||
{
|
||||
// grab the check value
|
||||
bool cellValue = (bool)this.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue;
|
||||
|
||||
if (cellValue)
|
||||
{
|
||||
BreakpointManager.SetBreakpoint(new BreakpointEntry(BreakpointProcessor.CP, BreakpointType.Execution, (ushort)e.RowIndex));
|
||||
}
|
||||
else
|
||||
{
|
||||
BreakpointManager.SetBreakpoint(new BreakpointEntry(BreakpointProcessor.CP, BreakpointType.None, (ushort)e.RowIndex));
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
base.OnCellValueChanged(e);
|
||||
}
|
||||
|
||||
protected override void OnCellValueNeeded(DataGridViewCellValueEventArgs e)
|
||||
{
|
||||
if (e.RowIndex > _cp.MicrocodeRam.Length)
|
||||
{
|
||||
// Past end of microcode, nothing to do.
|
||||
base.OnCellValueNeeded(e);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.ColumnIndex)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
ushort address = (ushort)e.RowIndex;
|
||||
|
||||
e.Value = BreakpointManager.GetBreakpoint(BreakpointProcessor.CP, address) != BreakpointType.None;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
e.Value = String.Format("{0:x3}", e.RowIndex);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
e.Value = new Microinstruction(_cp.MicrocodeRam[e.RowIndex]).Disassemble(-1);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("Unhandled column.");
|
||||
}
|
||||
|
||||
base.OnCellValueNeeded(e);
|
||||
}
|
||||
|
||||
private void AddColumn(string name, bool readOnly, DataGridViewAutoSizeColumnMode sizeMode)
|
||||
{
|
||||
int index = this.Columns.Add(name, name);
|
||||
|
||||
this.Columns[index].ReadOnly = readOnly;
|
||||
this.Columns[index].Resizable = DataGridViewTriState.False;
|
||||
this.Columns[index].SortMode = DataGridViewColumnSortMode.NotSortable;
|
||||
this.Columns[index].AutoSizeMode = sizeMode;
|
||||
}
|
||||
|
||||
private void AddCheckboxColumn(string name, DataGridViewAutoSizeColumnMode sizeMode)
|
||||
{
|
||||
int index = this.Columns.Add(new DataGridViewCheckBoxColumn());
|
||||
|
||||
this.Columns[index].HeaderText = name;
|
||||
this.Columns[index].ReadOnly = false;
|
||||
this.Columns[index].Resizable = DataGridViewTriState.False;
|
||||
this.Columns[index].SortMode = DataGridViewColumnSortMode.NotSortable;
|
||||
this.Columns[index].AutoSizeMode = sizeMode;
|
||||
}
|
||||
|
||||
private CentralProcessor _cp;
|
||||
}
|
||||
}
|
||||
252
D/Debugger/MicrocodeLoadMap.cs
Normal file
252
D/Debugger/MicrocodeLoadMap.cs
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
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.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace D.Debugger
|
||||
{
|
||||
|
||||
public struct LoadMapEntry
|
||||
{
|
||||
public LoadMapEntry(string name, string mapName, int start, int end, byte[] hash)
|
||||
{
|
||||
Name = name;
|
||||
MapName = mapName;
|
||||
Start = start;
|
||||
End = end;
|
||||
Hash = hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A friendly name for this load (i.e. "Phase 0 Microcode")
|
||||
/// </summary>
|
||||
public string Name;
|
||||
|
||||
/// <summary>
|
||||
/// The file name for the source map for this load
|
||||
/// </summary>
|
||||
public string MapName;
|
||||
|
||||
/// <summary>
|
||||
/// Beginning of address range for microcode load
|
||||
/// </summary>
|
||||
public int Start;
|
||||
|
||||
/// <summary>
|
||||
/// End of range (inclusive)
|
||||
/// </summary>
|
||||
public int End;
|
||||
|
||||
/// <summary>
|
||||
/// MD5 hash of microcode memory for range
|
||||
/// </summary>
|
||||
public byte[] Hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MicrocodeLoadMap keeps track of a set of LoadMapEntries, each of which
|
||||
/// specifies a map from a memory range + checksum to a source code mapping (i.e. symbol table).
|
||||
/// This source code map is identical to the map used for the 8085 source map.
|
||||
///
|
||||
/// This should in theory allow for more-or-less automagical mapping of whatever's in microcode
|
||||
/// RAM to the appropriate source files (assuming I've done the gruntwork of actually doing the
|
||||
/// mapping beforehand.)
|
||||
///
|
||||
/// </summary>
|
||||
public class MicrocodeLoadMap
|
||||
{
|
||||
public MicrocodeLoadMap()
|
||||
{
|
||||
_mapEntries = new List<LoadMapEntry>();
|
||||
}
|
||||
|
||||
public LoadMapEntry AddEntry(string name, int start, int end, ulong[] microcodeRAM)
|
||||
{
|
||||
if (end <= start || start > microcodeRAM.Length || end > microcodeRAM.Length)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid start/end parameters.");
|
||||
}
|
||||
|
||||
//
|
||||
// Ensure no duplicate entries (by name, anyway...)
|
||||
//
|
||||
foreach(LoadMapEntry e in _mapEntries)
|
||||
{
|
||||
if (e.Name.ToLowerInvariant() == name.ToLowerInvariant())
|
||||
{
|
||||
throw new InvalidOperationException("Duplicate map entry name.");
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a map name
|
||||
string mapName = name + "_map.txt";
|
||||
|
||||
// If the map file doesn't exist, create it now.
|
||||
|
||||
|
||||
// calculate the MD5 hash
|
||||
byte[] hash = ComputeHash(start, end, microcodeRAM);
|
||||
|
||||
LoadMapEntry newEntry = new LoadMapEntry(name, mapName, start, end, hash);
|
||||
|
||||
_mapEntries.Add(newEntry);
|
||||
|
||||
return newEntry;
|
||||
}
|
||||
|
||||
public List<LoadMapEntry> FindEntries(ulong[] microcodeRAM)
|
||||
{
|
||||
//
|
||||
// Given the provided microcode RAM, Walk the entries we know about and
|
||||
// see which ones match, if any.
|
||||
//
|
||||
List<LoadMapEntry> foundEntries = new List<LoadMapEntry>();
|
||||
|
||||
foreach(LoadMapEntry e in _mapEntries)
|
||||
{
|
||||
//
|
||||
// Hash the memory range specified by this entry and see if it matches.
|
||||
//
|
||||
byte[] hash = ComputeHash(e.Start, e.End, microcodeRAM);
|
||||
bool match = true;
|
||||
|
||||
for (int i = 0; i < hash.Length; i++)
|
||||
{
|
||||
if (hash[i] != e.Hash[i])
|
||||
{
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
foundEntries.Add(e);
|
||||
}
|
||||
}
|
||||
|
||||
return foundEntries;
|
||||
}
|
||||
|
||||
public void Save(string path)
|
||||
{
|
||||
using (StreamWriter sw = new StreamWriter(path))
|
||||
{
|
||||
//
|
||||
// Each entry looks like:
|
||||
//
|
||||
// <name>,<mapname>,<start>,<end>,<hash>
|
||||
// where:
|
||||
// <name> and <mapname> are strings,
|
||||
// <start> and <end> are hexadecimal values
|
||||
// <hash> is written as a series of ascii hex digits
|
||||
//
|
||||
// empty lines or lines beginning with "#" are ignored.
|
||||
//
|
||||
// And that's it!
|
||||
//
|
||||
foreach (LoadMapEntry e in _mapEntries)
|
||||
{
|
||||
StringBuilder hashText = new StringBuilder();
|
||||
for (int i = 0; i < e.Hash.Length; i++)
|
||||
{
|
||||
hashText.AppendFormat("{0:x2}", e.Hash[i]);
|
||||
}
|
||||
|
||||
sw.WriteLine("{0},{1},{2:x3},{3:x3},{4}", e.Name, e.MapName, e.Start, e.End, hashText.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Load(string path)
|
||||
{
|
||||
using (StreamReader sr = new StreamReader(path))
|
||||
{
|
||||
_mapEntries.Clear();
|
||||
|
||||
//
|
||||
// See "Save" for the format we're dealing with here.
|
||||
//
|
||||
while(!sr.EndOfStream)
|
||||
{
|
||||
string line = sr.ReadLine();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string[] tokens = line.Split(',');
|
||||
|
||||
string hashString = tokens[4].Trim();
|
||||
byte[] hash = new byte[hashString.Length / 2];
|
||||
|
||||
for (int i = 0; i < hashString.Length; i += 2)
|
||||
{
|
||||
hash[i / 2] = Convert.ToByte(hashString.Substring(i, 2), 16);
|
||||
}
|
||||
|
||||
LoadMapEntry e = new LoadMapEntry(
|
||||
tokens[0], // name
|
||||
tokens[1], // mapname
|
||||
Convert.ToInt32(tokens[2].Trim(), 16), // start
|
||||
Convert.ToInt32(tokens[3].Trim(), 16), // end
|
||||
hash);
|
||||
|
||||
_mapEntries.Add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] ComputeHash(int start, int end, ulong[] microcodeRAM)
|
||||
{
|
||||
//
|
||||
// Create a byte[] of the microcode data because why not.
|
||||
//
|
||||
byte[] microcodeBytes = new byte[(end - start) * 8];
|
||||
int microcodeIndex = 0;
|
||||
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
byte[] wordBytes = BitConverter.GetBytes(microcodeRAM[i]);
|
||||
wordBytes.CopyTo(microcodeBytes, microcodeIndex);
|
||||
microcodeIndex += 8;
|
||||
}
|
||||
|
||||
MD5 md5 = MD5.Create();
|
||||
return md5.ComputeHash(microcodeBytes);
|
||||
}
|
||||
|
||||
private List<LoadMapEntry> _mapEntries;
|
||||
}
|
||||
}
|
||||
435
D/Debugger/SourceDisplay.cs
Normal file
435
D/Debugger/SourceDisplay.cs
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
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.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace D.Debugger
|
||||
{
|
||||
/// <summary>
|
||||
/// Presents a source code view aligned with symbol addresses (where applicable)
|
||||
/// and breakpoints. One source file is loaded into a SourceDisplay at a time.
|
||||
///
|
||||
/// SourceDisplay provides a three-column view:
|
||||
///
|
||||
/// | Breakpoint | Address | Source text |
|
||||
/// -------------------------------------------------------------------------
|
||||
///
|
||||
/// Breakpoint and Address are editable (to allow setting breakpoints and to
|
||||
/// allow modifying symbol table data)
|
||||
///
|
||||
/// </summary>
|
||||
public class SourceDisplay : DataGridView
|
||||
{
|
||||
public SourceDisplay()
|
||||
{
|
||||
this.VirtualMode = true;
|
||||
this.RowHeadersVisible = false;
|
||||
|
||||
AddCheckboxColumn("B", DataGridViewAutoSizeColumnMode.ColumnHeader);
|
||||
AddColumn("Address", false, DataGridViewAutoSizeColumnMode.ColumnHeader);
|
||||
AddColumn("Source", true, DataGridViewAutoSizeColumnMode.Fill);
|
||||
}
|
||||
|
||||
public string CurrentSourceFile
|
||||
{
|
||||
get { return _currentSourceFile; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the address of the selected line, if any has been assigned. Returns
|
||||
/// -1 if there is no selection or if no address is available for the selected line.
|
||||
/// </summary>
|
||||
public int SelectedAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
int address = -1;
|
||||
|
||||
if (_sourceMap != null &&
|
||||
_currentSourceFile != null &&
|
||||
this.SelectedCells.Count > 0)
|
||||
{
|
||||
int rowIndex = this.SelectedCells[0].RowIndex;
|
||||
// TODO: factor this logic out w/cell input logic.
|
||||
string cellValue = (string)this.Rows[rowIndex].Cells[1].Value;
|
||||
|
||||
try
|
||||
{
|
||||
// strip leading $ if any.
|
||||
if (cellValue.StartsWith("$"))
|
||||
{
|
||||
cellValue = cellValue.Substring(1);
|
||||
}
|
||||
|
||||
address = Convert.ToUInt16(cellValue, 16);
|
||||
}
|
||||
catch
|
||||
{
|
||||
address = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
public SourceMap SourceMap
|
||||
{
|
||||
get { return _sourceMap; }
|
||||
}
|
||||
|
||||
public void SetSourceRoot(string sourceRoot)
|
||||
{
|
||||
_sourceRoot = sourceRoot;
|
||||
}
|
||||
|
||||
public void AttachMap(SourceMap sourceMap)
|
||||
{
|
||||
_sourceMap = sourceMap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the appropriate source file, brings the specified line into view
|
||||
/// and highlights the specified line.
|
||||
/// </summary>
|
||||
/// <param name="entry"></param>
|
||||
public void SelectSourceEntry(SourceEntry entry, bool readOnly, bool iop)
|
||||
{
|
||||
LoadSourceFile(entry.SourcePath);
|
||||
SelectLine(entry.LineNumber);
|
||||
|
||||
this.ReadOnly = readOnly;
|
||||
_iopCode = iop;
|
||||
}
|
||||
|
||||
protected override void OnCurrentCellDirtyStateChanged(EventArgs e)
|
||||
{
|
||||
if (IsCurrentCellDirty)
|
||||
{
|
||||
//
|
||||
// Force checkbox changes to commit immediately (rather than
|
||||
// the default, which is to commit them when focus leaves the cell, which
|
||||
// is really annoying.
|
||||
//
|
||||
if (CurrentCell is DataGridViewCheckBoxCell)
|
||||
{
|
||||
CommitEdit(DataGridViewDataErrorContexts.Commit);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnCurrentCellDirtyStateChanged(e);
|
||||
}
|
||||
|
||||
protected override void OnCellValueChanged(DataGridViewCellEventArgs e)
|
||||
{
|
||||
if (e.RowIndex < 0 || e.RowIndex > _source.Count)
|
||||
{
|
||||
base.OnCellValueChanged(e);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.ColumnIndex)
|
||||
{
|
||||
case 0: // breakpoint
|
||||
{
|
||||
// grab the check value
|
||||
bool cellValue = (bool)this.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue;
|
||||
|
||||
ushort address = 0;
|
||||
bool addressAvailable = _sourceMap != null ? _sourceMap.GetAddressForSource(new SourceEntry(_currentSourceFile, new string[] { }, 0, e.RowIndex), out address) : false;
|
||||
|
||||
if (addressAvailable)
|
||||
{
|
||||
if (cellValue)
|
||||
{
|
||||
BreakpointManager.SetBreakpoint(new BreakpointEntry(_iopCode ? BreakpointProcessor.IOP : BreakpointProcessor.CP, BreakpointType.Execution, address));
|
||||
}
|
||||
else
|
||||
{
|
||||
BreakpointManager.SetBreakpoint(new BreakpointEntry(_iopCode ? BreakpointProcessor.IOP : BreakpointProcessor.CP, BreakpointType.None, address));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // address
|
||||
{
|
||||
string oldCellValue = ((string)this.Rows[e.RowIndex].Cells[e.ColumnIndex].Value).Trim();
|
||||
|
||||
string[] symbolTokens = ((string)this.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue).Trim().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (symbolTokens.Length > 2)
|
||||
{
|
||||
MessageBox.Show("Invalid syntax.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldCellValue.StartsWith("$"))
|
||||
{
|
||||
oldCellValue = oldCellValue.Substring(1);
|
||||
}
|
||||
|
||||
if (symbolTokens.Length == 0)
|
||||
{
|
||||
// cell is empty, delete the current source map entry if present.
|
||||
// TODO: use source map for this instead?
|
||||
|
||||
if (_sourceMap != null && !string.IsNullOrEmpty(oldCellValue))
|
||||
{
|
||||
ushort oldAddress = Convert.ToUInt16(oldCellValue, 16);
|
||||
_sourceMap.RemoveSourceEntry(new SourceEntry(_currentSourceFile, new string[] { }, oldAddress, e.RowIndex));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Valid new cell value.
|
||||
//
|
||||
string cellValue = symbolTokens[0];
|
||||
string symbolName = symbolTokens.Length == 2 ? symbolTokens[1] : "*none*";
|
||||
|
||||
// strip leading $ if any.
|
||||
if (cellValue.StartsWith("$"))
|
||||
{
|
||||
cellValue = cellValue.Substring(1);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ushort address = Convert.ToUInt16(cellValue, 16);
|
||||
ushort oldAddress = string.IsNullOrWhiteSpace(oldCellValue) ? (ushort)0 : Convert.ToUInt16(oldCellValue, 16);
|
||||
|
||||
if (_sourceMap != null && address != oldAddress)
|
||||
{
|
||||
//
|
||||
// Set the new value first.
|
||||
//
|
||||
_sourceMap.AddSourceEntry(new SourceEntry(_currentSourceFile, new string[] { symbolName }, address, e.RowIndex));
|
||||
|
||||
//
|
||||
// Remove the old value from the database if there is one.
|
||||
//
|
||||
if (!string.IsNullOrWhiteSpace(oldCellValue))
|
||||
{
|
||||
_sourceMap.RemoveSourceEntry(new SourceEntry(_currentSourceFile, new string[] { }, oldAddress, e.RowIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, "Hey!");
|
||||
// Invalid value, clear it.
|
||||
// this.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = String.Empty;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
base.OnCellValueChanged(e);
|
||||
}
|
||||
|
||||
protected override void OnCellValueNeeded(DataGridViewCellValueEventArgs e)
|
||||
{
|
||||
if (e.RowIndex > _source.Count)
|
||||
{
|
||||
// Past end of source, nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.ColumnIndex)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
ushort address = 0;
|
||||
bool addressAvailable = _sourceMap != null ? _sourceMap.GetAddressForSource(new SourceEntry(_currentSourceFile, new string[] { }, 0, e.RowIndex), out address) : false;
|
||||
if (addressAvailable)
|
||||
{
|
||||
e.Value = BreakpointManager.GetBreakpoint(_iopCode ? BreakpointProcessor.IOP : BreakpointProcessor.CP, address) != BreakpointType.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Value = false; // TODO: hook to breakpoint system
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
ushort address = 0;
|
||||
bool addressAvailable = _sourceMap != null ? _sourceMap.GetAddressForSource(new SourceEntry(_currentSourceFile, new string[] { }, 0, e.RowIndex), out address) : false;
|
||||
e.Value = addressAvailable ? String.Format("${0:x4}", address) : String.Empty;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
e.Value = _source[e.RowIndex];
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("Unhandled column.");
|
||||
}
|
||||
|
||||
base.OnCellValueNeeded(e);
|
||||
}
|
||||
|
||||
private void LoadSourceFile(string sourcePath)
|
||||
{
|
||||
//
|
||||
// Only do this if the file isn't currently loaded.
|
||||
//
|
||||
try
|
||||
{
|
||||
if (_currentSourceFile != sourcePath)
|
||||
{
|
||||
this.Invalidate();
|
||||
|
||||
_source = new List<string>();
|
||||
|
||||
using (StreamReader sr = new StreamReader(Path.Combine(_sourceRoot, sourcePath), Encoding.UTF8))
|
||||
{
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
_source.Add(UnTabify(sr.ReadLine()));
|
||||
}
|
||||
}
|
||||
|
||||
this.RowCount = _source.Count;
|
||||
|
||||
_currentSourceFile = sourcePath;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
_source = new List<string>();
|
||||
_source.Add(
|
||||
String.Format("Unable to load source file {0}. Error: {1}",
|
||||
sourcePath, e.Message));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts tabs in the given string to 4 space tabulation. As it should be.
|
||||
/// </summary>
|
||||
/// <param name="tabified"></param>
|
||||
/// <returns></returns>
|
||||
private string UnTabify(string tabified)
|
||||
{
|
||||
StringBuilder untabified = new StringBuilder();
|
||||
|
||||
int column = 0;
|
||||
|
||||
foreach(char c in tabified)
|
||||
{
|
||||
if (c == '\t')
|
||||
{
|
||||
untabified.Append(" ");
|
||||
column++;
|
||||
while ((column % 4) != 0)
|
||||
{
|
||||
untabified.Append(" ");
|
||||
column++;
|
||||
}
|
||||
}
|
||||
if (c == _unicodeUnknown)
|
||||
{
|
||||
// TODO:
|
||||
// We assume that if this happens it's the microcode source "arrow" symbol.
|
||||
// C#'s StreamReader supports only Unicode/UTF and ASCII (7-bit) encodings and the
|
||||
// Star's backarrow is an 8-bit character. I should really just rewrite the code
|
||||
// to read the bytes in myself, this is a bodge for the time being.
|
||||
untabified.Append(_arrowChar);
|
||||
}
|
||||
else
|
||||
{
|
||||
untabified.Append(c);
|
||||
column++;
|
||||
}
|
||||
}
|
||||
|
||||
return untabified.ToString();
|
||||
}
|
||||
|
||||
private void SelectLine(int lineNumber)
|
||||
{
|
||||
//
|
||||
// Clear the current selection and move the selection to the first cell
|
||||
// of the requested line.
|
||||
//
|
||||
|
||||
if (lineNumber < this.Rows.Count)
|
||||
{
|
||||
this.Rows[lineNumber].Selected = true;
|
||||
this.CurrentCell = this.Rows[lineNumber].Cells[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ClearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private void AddColumn(string name, bool readOnly, DataGridViewAutoSizeColumnMode sizeMode)
|
||||
{
|
||||
int index = this.Columns.Add(name, name);
|
||||
|
||||
this.Columns[index].ReadOnly = readOnly;
|
||||
this.Columns[index].Resizable = DataGridViewTriState.False;
|
||||
this.Columns[index].SortMode = DataGridViewColumnSortMode.NotSortable;
|
||||
this.Columns[index].AutoSizeMode = sizeMode;
|
||||
}
|
||||
|
||||
private void AddCheckboxColumn(string name, DataGridViewAutoSizeColumnMode sizeMode)
|
||||
{
|
||||
int index = this.Columns.Add(new DataGridViewCheckBoxColumn());
|
||||
|
||||
this.Columns[index].HeaderText = name;
|
||||
this.Columns[index].ReadOnly = false;
|
||||
this.Columns[index].Resizable = DataGridViewTriState.False;
|
||||
this.Columns[index].SortMode = DataGridViewColumnSortMode.NotSortable;
|
||||
this.Columns[index].AutoSizeMode = sizeMode;
|
||||
}
|
||||
|
||||
private string _currentSourceFile;
|
||||
private string _sourceRoot;
|
||||
private List<string> _source;
|
||||
private bool _iopCode;
|
||||
private SourceMap _sourceMap;
|
||||
|
||||
//
|
||||
// Character substitutions
|
||||
//
|
||||
private const char _arrowChar = '←';
|
||||
private const char _unicodeUnknown = (char)0xfffd;
|
||||
|
||||
}
|
||||
}
|
||||
442
D/Debugger/SourceMap.cs
Normal file
442
D/Debugger/SourceMap.cs
Normal file
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
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.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace D.Debugger
|
||||
{
|
||||
public class SourceEntry
|
||||
{
|
||||
public SourceEntry(string sourcePath, string[] symbolNames, ushort address, int lineNumber)
|
||||
{
|
||||
SourcePath = sourcePath;
|
||||
SymbolNames = symbolNames;
|
||||
Address = address;
|
||||
LineNumber = lineNumber;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0}, line {1} address 0x{2:x4}", SourcePath, LineNumber, Address);
|
||||
}
|
||||
|
||||
public string SourcePath;
|
||||
public string[] SymbolNames;
|
||||
public ushort Address;
|
||||
public int LineNumber;
|
||||
|
||||
public static readonly SourceEntry Empty = new SourceEntry(String.Empty, new string[] { "*none*" }, 0, 0);
|
||||
}
|
||||
|
||||
public class SourceMap
|
||||
{
|
||||
public SourceMap(string mapName, string mapFile, string sourceRoot)
|
||||
{
|
||||
_sourceFileToSourceEntryMap = new Dictionary<string, List<SourceEntry>>();
|
||||
_orderedSourceEntries = new List<SourceEntry>();
|
||||
|
||||
ReadMap(mapFile, sourceRoot);
|
||||
|
||||
_mapName = mapName;
|
||||
_mapFile = mapFile;
|
||||
_sourceRoot = sourceRoot;
|
||||
}
|
||||
|
||||
public string MapName
|
||||
{
|
||||
get { return _mapName; }
|
||||
}
|
||||
|
||||
public string SourceRoot
|
||||
{
|
||||
get { return _sourceRoot; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the list of source files referenced by this map.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<string> GetSourceFiles()
|
||||
{
|
||||
return _sourceFileToSourceEntryMap.Keys.ToList();
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
string header =
|
||||
@"#
|
||||
# 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:
|
||||
# <symbol name 1>, .. , <symbol name N>: <address or value (hex)>,<line number(decimal) in current source file>
|
||||
# where '*none*' is a special symbol name meaning no symbol mapping is present.";
|
||||
|
||||
using (StreamWriter sw = new StreamWriter(_mapFile))
|
||||
{
|
||||
// Write out a nice header
|
||||
sw.Write(header);
|
||||
|
||||
sw.WriteLine();
|
||||
|
||||
// Write out each source file
|
||||
foreach(string sourceFile in _sourceFileToSourceEntryMap.Keys)
|
||||
{
|
||||
sw.WriteLine("[{0}]", sourceFile);
|
||||
|
||||
foreach(SourceEntry entry in _sourceFileToSourceEntryMap[sourceFile])
|
||||
{
|
||||
StringBuilder symbolList = new StringBuilder();
|
||||
for (int i = 0; i < entry.SymbolNames.Length; i++)
|
||||
{
|
||||
symbolList.AppendFormat(i < entry.SymbolNames.Length - 1 ? "{0}," : "{0}", entry.SymbolNames[i]);
|
||||
}
|
||||
|
||||
sw.WriteLine("{0}: 0x{1:x4},{2}", symbolList.ToString(), entry.Address, entry.LineNumber + 1); // line numbers are 1-indexed
|
||||
}
|
||||
|
||||
sw.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SourceEntry GetSourceForAddress(ushort address)
|
||||
{
|
||||
SourceEntry result = null;
|
||||
|
||||
//
|
||||
// Find the SourceEntry nearest this address, if there is one.
|
||||
//
|
||||
foreach(SourceEntry entry in _orderedSourceEntries)
|
||||
{
|
||||
if (entry.Address > address)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
result = entry;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public SourceEntry GetExactSourceForAddress(ushort address)
|
||||
{
|
||||
//
|
||||
// Find the SourceEntry for this address, if there is one.
|
||||
//
|
||||
foreach (SourceEntry entry in _orderedSourceEntries)
|
||||
{
|
||||
if (entry.Address == address)
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public SourceEntry GetNearestSymbolForAddress(ushort address)
|
||||
{
|
||||
SourceEntry result = null;
|
||||
|
||||
//
|
||||
// Find the SourceEntry nearest this address that has a symbol name defined, if there is one.
|
||||
//
|
||||
foreach (SourceEntry entry in _orderedSourceEntries)
|
||||
{
|
||||
if (entry.Address > address)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (entry.SymbolNames.Length > 0 &&
|
||||
entry.SymbolNames[0] != "*none*") // TODO: move to constant
|
||||
{
|
||||
result = entry;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool GetAddressForSource(SourceEntry entry, out ushort address)
|
||||
{
|
||||
bool found = false;
|
||||
address = 0;
|
||||
|
||||
//
|
||||
// Find the source line entry that matches.
|
||||
//
|
||||
if (_sourceFileToSourceEntryMap.ContainsKey(entry.SourcePath))
|
||||
{
|
||||
foreach(SourceEntry line in _sourceFileToSourceEntryMap[entry.SourcePath])
|
||||
{
|
||||
if (line.LineNumber == entry.LineNumber)
|
||||
{
|
||||
found = true;
|
||||
address = line.Address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
public void AddSourceEntry(SourceEntry entry)
|
||||
{
|
||||
// InsertAddressEntry will ensure that no duplicate addresses are added.
|
||||
InsertAddressEntry(entry);
|
||||
InsertSourceEntry(entry);
|
||||
}
|
||||
|
||||
public void AddSourceFile(string sourcePath)
|
||||
{
|
||||
if (!_sourceFileToSourceEntryMap.ContainsKey(sourcePath))
|
||||
{
|
||||
List<SourceEntry> newList = new List<SourceEntry>();
|
||||
_sourceFileToSourceEntryMap.Add(sourcePath, newList);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Source file already exists in map.");
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveSourceEntry(SourceEntry entry)
|
||||
{
|
||||
// Remove from address table
|
||||
for (int i = 0; i < _orderedSourceEntries.Count; i++)
|
||||
{
|
||||
if (_orderedSourceEntries[i].Address == entry.Address)
|
||||
{
|
||||
_orderedSourceEntries.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from source table if present
|
||||
if (_sourceFileToSourceEntryMap.ContainsKey(entry.SourcePath))
|
||||
{
|
||||
for (int i = 0; i < _sourceFileToSourceEntryMap[entry.SourcePath].Count; i++)
|
||||
{
|
||||
if (_sourceFileToSourceEntryMap[entry.SourcePath][i].Address == entry.Address)
|
||||
{
|
||||
_sourceFileToSourceEntryMap[entry.SourcePath].RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void ReadMap(string mapFile, string sourceRoot)
|
||||
{
|
||||
//
|
||||
// If the file does not exist, we will just start with an empty map.
|
||||
//
|
||||
if (!File.Exists(mapFile))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (StreamReader map = new StreamReader(mapFile))
|
||||
{
|
||||
string sourceFile = string.Empty;
|
||||
ReadState state = ReadState.NextFileHeader;
|
||||
int mapLineNumber = 0;
|
||||
|
||||
while (!map.EndOfStream)
|
||||
{
|
||||
string line = map.ReadLine().Trim();
|
||||
mapLineNumber++;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(line) ||
|
||||
line.StartsWith("#"))
|
||||
{
|
||||
// Nothing of note here, continue.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.StartsWith("["))
|
||||
{
|
||||
// Looks like the start of a file header.
|
||||
state = ReadState.NextFileHeader;
|
||||
}
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case ReadState.NextFileHeader:
|
||||
// We expect the line to be in the form "[<source path>]"
|
||||
// If this is not the case, then the map file is incorrectly formed.
|
||||
if (line.StartsWith("["))
|
||||
{
|
||||
int closingBracket = line.LastIndexOf(']');
|
||||
|
||||
if (closingBracket < 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
String.Format("Badly formed source file entry on line {0}", mapLineNumber));
|
||||
}
|
||||
|
||||
sourceFile = line.Substring(1, closingBracket - 1).Trim();
|
||||
state = ReadState.NextSymbolEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
String.Format("Expected file header on line {0}", mapLineNumber));
|
||||
}
|
||||
break;
|
||||
|
||||
case ReadState.NextSymbolEntry:
|
||||
//
|
||||
// This is expected to be a symbol map entry, which looks like
|
||||
// <symbol name 1>, .. , <symbol name N> : <address or value (hex)>,<line number(decimal) in current source file>
|
||||
//
|
||||
string[] symbolAddressTokens = line.Split(':');
|
||||
|
||||
if (symbolAddressTokens.Length != 2)
|
||||
{
|
||||
// Should be two tokens here, one on each side of the ':'
|
||||
throw new InvalidOperationException(
|
||||
String.Format("Badly formed symbol entry on line {0}", mapLineNumber));
|
||||
}
|
||||
|
||||
// Grab the symbol names. There must be at least one present since the above split succeeded.
|
||||
string[] symbolNames = symbolAddressTokens[0].Trim().Split(',');
|
||||
|
||||
// Grab the source information. There must be exactly two entries.
|
||||
string[] sourceData = symbolAddressTokens[1].Trim().Split(',');
|
||||
|
||||
if (sourceData.Length != 2)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
String.Format("Badly formed symbol entry on line {0} -- source information is invalid.", mapLineNumber));
|
||||
}
|
||||
|
||||
// Convert source info into integers and build a new SourceEntry.
|
||||
int lineNumber = 0;
|
||||
ushort address = 0;
|
||||
try
|
||||
{
|
||||
address = (ushort)Convert.ToInt32(sourceData[0].Trim(), 16);
|
||||
lineNumber = int.Parse(sourceData[1].Trim()) - 1; // line numbers are 1-indexed
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
String.Format("Badly formed symbol entry on line {0} -- source information is invalid.", mapLineNumber));
|
||||
}
|
||||
|
||||
SourceEntry newEntry = new SourceEntry(sourceFile, symbolNames, address, lineNumber);
|
||||
|
||||
AddSourceEntry(newEntry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InsertAddressEntry(SourceEntry entry)
|
||||
{
|
||||
if (_orderedSourceEntries.Count == 0)
|
||||
{
|
||||
_orderedSourceEntries.Add(entry);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the first entry that has an address greater than the new entry's.
|
||||
//
|
||||
for(int i=0;i<_orderedSourceEntries.Count;i++)
|
||||
{
|
||||
// Sanity check -- if these entries have equal addresses then we need to stop here.
|
||||
if (_orderedSourceEntries[i].Address == entry.Address)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
String.Format("Duplicate address {0:x4} in source map.", entry.Address));
|
||||
}
|
||||
|
||||
if (_orderedSourceEntries[i].Address > entry.Address)
|
||||
{
|
||||
_orderedSourceEntries.Insert(i, entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// If we get here, then this address is greater than any already in the list, so we add it at the end.
|
||||
//
|
||||
_orderedSourceEntries.Add(entry);
|
||||
}
|
||||
|
||||
private void InsertSourceEntry(SourceEntry entry)
|
||||
{
|
||||
if (!_sourceFileToSourceEntryMap.ContainsKey(entry.SourcePath))
|
||||
{
|
||||
List<SourceEntry> newList = new List<SourceEntry>();
|
||||
newList.Add(entry);
|
||||
_sourceFileToSourceEntryMap.Add(entry.SourcePath, newList);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sourceFileToSourceEntryMap[entry.SourcePath].Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Maps for quick lookups
|
||||
//
|
||||
private Dictionary<string, List<SourceEntry>> _sourceFileToSourceEntryMap;
|
||||
|
||||
//
|
||||
// Ordered list for quick search by address
|
||||
//
|
||||
private List<SourceEntry> _orderedSourceEntries;
|
||||
|
||||
private string _mapName;
|
||||
private string _mapFile;
|
||||
private string _sourceRoot;
|
||||
|
||||
enum ReadState
|
||||
{
|
||||
NextFileHeader,
|
||||
NextSymbolEntry,
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
D/Disks/130P26300-diags.IMD
Normal file
BIN
D/Disks/130P26300-diags.IMD
Normal file
Binary file not shown.
BIN
D/Disks/130P26301-install.IMD
Normal file
BIN
D/Disks/130P26301-install.IMD
Normal file
Binary file not shown.
BIN
D/Disks/Harmony.img
Normal file
BIN
D/Disks/Harmony.img
Normal file
Binary file not shown.
BIN
D/Disks/Koto.img
Normal file
BIN
D/Disks/Koto.img
Normal file
Binary file not shown.
BIN
D/Disks/Lyric.img
Normal file
BIN
D/Disks/Lyric.img
Normal file
Binary file not shown.
BIN
D/Disks/Medley.img
Normal file
BIN
D/Disks/Medley.img
Normal file
Binary file not shown.
BIN
D/Disks/ViewPoint-11-9-1990-18-38.img
Normal file
BIN
D/Disks/ViewPoint-11-9-1990-18-38.img
Normal file
Binary file not shown.
BIN
D/Disks/XDE.img
Normal file
BIN
D/Disks/XDE.img
Normal file
Binary file not shown.
BIN
D/Disks/XDE_5.0_BO1.IMD
Normal file
BIN
D/Disks/XDE_5.0_BO1.IMD
Normal file
Binary file not shown.
295
D/Display/DisplayController.cs
Normal file
295
D/Display/DisplayController.cs
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
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.Logging;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace D.Display
|
||||
{
|
||||
public class DisplayController
|
||||
{
|
||||
public DisplayController(DSystem system)
|
||||
{
|
||||
_system = system;
|
||||
|
||||
_lostSyncEvent = new Event(_lostSyncInterval, null, LostSyncCallback);
|
||||
|
||||
_fifo = new Queue<ushort>(16);
|
||||
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_displayOn = false;
|
||||
_blank = false;
|
||||
_picture = false;
|
||||
_invert = false;
|
||||
_oddLine = false;
|
||||
|
||||
_scanline = 0;
|
||||
|
||||
_fifo.Clear();
|
||||
|
||||
if (_system.Display != null)
|
||||
{
|
||||
_system.Display.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public bool DisplayOn
|
||||
{
|
||||
get { return _displayOn; }
|
||||
}
|
||||
|
||||
public void ClrDpRq()
|
||||
{
|
||||
//
|
||||
// Put the display task to sleep
|
||||
//
|
||||
_system.CP.SleepTask(TaskType.Display);
|
||||
}
|
||||
|
||||
public void SetDCtlFifo(ushort value)
|
||||
{
|
||||
// if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.DisplayControl, "DCtlFIFO<-0x{0:x4}", value);
|
||||
if (_fifo.Count < 16)
|
||||
{
|
||||
_fifo.Enqueue(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogType.Error, LogComponent.DisplayControl, "DCtlFIFO: FIFO overflow, word dropped.");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDCtl(ushort value)
|
||||
{
|
||||
bool displayOn = _displayOn;
|
||||
_displayOn = (value & 0x01) != 0;
|
||||
_blank = (value & 0x02) != 0;
|
||||
_picture = (value & 0x04) != 0;
|
||||
_invert = (value & 0x08) != 0;
|
||||
|
||||
if ((value & 0x20) != 0)
|
||||
{
|
||||
// Vertical Sync -- back to the top of the screen
|
||||
_scanline = 0;
|
||||
_oddLine = (value & 0x10) != 0;
|
||||
_syncPresent = true;
|
||||
_system.Display.Render();
|
||||
}
|
||||
|
||||
if ((value & 0x40) == 0)
|
||||
{
|
||||
// Clear control fifo
|
||||
_fifo.Clear();
|
||||
}
|
||||
|
||||
if (!displayOn && _displayOn)
|
||||
{
|
||||
// Kick off the horizontal retrace callback since we're turning the display on.
|
||||
_system.Scheduler.Schedule(_horizontalRetraceDelay, HorizontalRetraceCallback);
|
||||
|
||||
_system.Scheduler.Cancel(_lostSyncEvent);
|
||||
_lostSyncEvent = _system.Scheduler.Schedule(_lostSyncInterval, LostSyncCallback);
|
||||
}
|
||||
else if (!_displayOn)
|
||||
{
|
||||
//
|
||||
// Put the display task to sleep.
|
||||
//
|
||||
_system.CP.SleepTask(TaskType.Display);
|
||||
}
|
||||
|
||||
if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.DisplayControl, "DCtl<-0x{0:x4}: On={1} Blank={2} Picture={3} Invert={4} Odd={5}"
|
||||
, value,
|
||||
_displayOn,
|
||||
_blank,
|
||||
_picture,
|
||||
_invert,
|
||||
_oddLine);
|
||||
}
|
||||
|
||||
public void SetDBorder(ushort value)
|
||||
{
|
||||
_displayBorder = value;
|
||||
if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.DisplayControl, "DBorder<-0x{0:x4}", value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked at the end of every scanline: Wake display task, update state, schedule next callback
|
||||
/// as necessary.
|
||||
/// </summary>
|
||||
/// <param name="skewNsec"></param>
|
||||
/// <param name="context"></param>
|
||||
private void HorizontalRetraceCallback(ulong skewNsec, object context)
|
||||
{
|
||||
int visibleOffset = _oddLine ? 37 : 36;
|
||||
int effectiveScanline = _scanline - visibleOffset;
|
||||
|
||||
//
|
||||
// Render this scanline, if there's anything to do.
|
||||
//
|
||||
if (_blank)
|
||||
{
|
||||
// Render blank scanline (no border, no picture)
|
||||
for (int i = 0; i < _scanlineData.Length; i++)
|
||||
{
|
||||
_scanlineData[i] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_picture)
|
||||
{
|
||||
// Normal line : 32 bits of border pattern, 1024 bits of display, 32 bits of border pattern
|
||||
// Border pattern: low byte on lines 4n, 4n+1; high byte on 4n+2, 4n+3.
|
||||
int patternByte = (effectiveScanline & 0x2) == 0 ? _displayBorder & 0xff : _displayBorder >> 8;
|
||||
ushort patternWord = (ushort)(patternByte | (patternByte << 8));
|
||||
|
||||
_scanlineData[0] = patternWord;
|
||||
_scanlineData[1] = patternWord;
|
||||
|
||||
if (_fifo.Count > 0)
|
||||
{
|
||||
// Grab first segment from FIFO
|
||||
ushort fifoWord = _fifo.Dequeue();
|
||||
int lastWord = fifoWord >> 10;
|
||||
int lineNumber = fifoWord & 0x3ff;
|
||||
bool valid = false;
|
||||
for (int word = 0; word < 64; word++)
|
||||
{
|
||||
_scanlineData[word + 2] = _system.MemoryController.DebugMemory.ReadWord((lineNumber << 6) | word, out valid);
|
||||
|
||||
// Grab next segment if this isn't the last word in the scanline.
|
||||
if (word != 63 && word == lastWord && _fifo.Count > 0)
|
||||
{
|
||||
fifoWord = _fifo.Dequeue();
|
||||
lastWord = fifoWord >> 10;
|
||||
lineNumber = fifoWord & 0x3ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Blank out display words, nothing in the FIFO.
|
||||
for (int i = 2; i < 64; i++)
|
||||
{
|
||||
_scanlineData[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_scanlineData[66] = patternWord;
|
||||
_scanlineData[67] = patternWord;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just display the border pattern everywhere:
|
||||
// low byte on lines 4n, 4n+1; high byte on 4n+2, 4n+3.
|
||||
int patternByte = (effectiveScanline & 0x2) == 0 ? _displayBorder & 0xff : _displayBorder >> 8;
|
||||
ushort patternWord = (ushort)(patternByte | (patternByte << 8));
|
||||
|
||||
for (int i = 0; i < _scanlineData.Length; i++)
|
||||
{
|
||||
_scanlineData[i] = patternWord;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (effectiveScanline > 0 && effectiveScanline < 860)
|
||||
{
|
||||
// Render to screen
|
||||
_system.Display.DrawScanline(effectiveScanline, _scanlineData, _invert);
|
||||
}
|
||||
|
||||
// Move to next scanline
|
||||
_scanline += 2;
|
||||
|
||||
//
|
||||
// Schedule next retrace as long as the display is still on.
|
||||
//
|
||||
if (_displayOn)
|
||||
{
|
||||
_system.Scheduler.Schedule(_horizontalRetraceDelay, HorizontalRetraceCallback);
|
||||
|
||||
//
|
||||
// End of scanline: Wake up the display task.
|
||||
//
|
||||
_system.CP.WakeTask(TaskType.Display);
|
||||
}
|
||||
}
|
||||
|
||||
private void LostSyncCallback(ulong skewNsec, object context)
|
||||
{
|
||||
if (_syncPresent)
|
||||
{
|
||||
//
|
||||
// Got sync, keep the display alive and reschedule ourselves.
|
||||
_lostSyncEvent = _system.Scheduler.Schedule(_lostSyncInterval, LostSyncCallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No sync since the last callback, blank the display and stop the sync callback.
|
||||
_system.Display.Clear();
|
||||
}
|
||||
|
||||
_syncPresent = false;
|
||||
}
|
||||
|
||||
// Control bits
|
||||
private bool _displayOn;
|
||||
private bool _blank;
|
||||
private bool _picture;
|
||||
private bool _invert;
|
||||
private bool _oddLine;
|
||||
|
||||
// Border bitmap
|
||||
private ushort _displayBorder;
|
||||
|
||||
// Control FIFO. Max 16 entries.
|
||||
private Queue<ushort> _fifo;
|
||||
|
||||
// Scanline
|
||||
private int _scanline;
|
||||
private ushort[] _scanlineData = new ushort[64 + 4]; // 1024 bits picture, 32 bits border on either side
|
||||
|
||||
private bool _syncPresent;
|
||||
|
||||
private DSystem _system;
|
||||
|
||||
//
|
||||
// Timing and events
|
||||
//
|
||||
private readonly ulong _horizontalRetraceDelay = (ulong)(28.8 * Conversion.UsecToNsec); // 28.8uS
|
||||
|
||||
private Event _lostSyncEvent;
|
||||
private readonly ulong _lostSyncInterval = (ulong)(52.91 * Conversion.MsecToNsec); // 53ms (one frame time)
|
||||
}
|
||||
}
|
||||
94
D/Ethernet/CRC32.cs
Normal file
94
D/Ethernet/CRC32.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
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.Ethernet
|
||||
{
|
||||
public class CRC32
|
||||
{
|
||||
static CRC32()
|
||||
{
|
||||
//
|
||||
// Initialize the CRC table.
|
||||
//
|
||||
uint temp = 0;
|
||||
for (uint i = 0; i < _crcTable.Length; i++)
|
||||
{
|
||||
temp = i;
|
||||
|
||||
for (int j = 8; j > 0; j--)
|
||||
{
|
||||
if ((temp & 1) == 1)
|
||||
{
|
||||
temp = (uint)((temp >> 1) ^ _polynomial);
|
||||
}
|
||||
else
|
||||
{
|
||||
temp >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
_crcTable[i] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
public CRC32()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
public uint Checksum
|
||||
{
|
||||
get { return ~_checksum; }
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_checksum = 0xffffffff;
|
||||
}
|
||||
|
||||
public void AddToChecksum(ushort word)
|
||||
{
|
||||
byte[] bytes = new byte[2];
|
||||
bytes[0] = (byte)(word >> 8);
|
||||
bytes[1] = (byte)word;
|
||||
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
byte index = (byte)((_checksum ^ bytes[i]) & 0xff);
|
||||
_checksum = (_checksum >> 8) ^ _crcTable[index];
|
||||
}
|
||||
}
|
||||
|
||||
private uint _checksum;
|
||||
|
||||
private static uint[] _crcTable = new uint[256];
|
||||
private const uint _polynomial = 0xedb88320;
|
||||
}
|
||||
|
||||
}
|
||||
849
D/Ethernet/EthernetController.cs
Normal file
849
D/Ethernet/EthernetController.cs
Normal file
@@ -0,0 +1,849 @@
|
||||
/*
|
||||
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.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace D.Ethernet
|
||||
{
|
||||
/// <summary>
|
||||
/// EthernetController implements the Star's Ethernet controller.
|
||||
/// At this time, no official documentation exists; only microcode listings and the schematic drawings.
|
||||
/// The code is implemented based on study of the schematics and diagnostic microcode.
|
||||
/// As such there is a lot of handwavy stuff in here, especially around loopback. At this time enough
|
||||
/// is implemented to get boot diagnostics to pass.
|
||||
///
|
||||
/// Questions remaining to be answered:
|
||||
/// - What is the distinction between Loopback and LocalLoopback? Initially it looked like LocalLoopback only
|
||||
/// looped back through the FIFO, but it appears to invoke CRC generation and microcode comments make it look
|
||||
/// like transmission actually takes place? At this time both are treated identically.
|
||||
/// - How is the FIFO actually controlled during loopback? (How does the transmit hardware know when to stop
|
||||
/// transmitting when the FIFO is (apparently) being used for both transmit and receive at the same time during
|
||||
/// a loopback operation?)
|
||||
///
|
||||
/// - Why is CRC calculation not working the way I expect? The residual sum does not appear to work out to
|
||||
/// the expected value for Ethernet CRC32.
|
||||
///
|
||||
/// </summary>
|
||||
public class EthernetController
|
||||
{
|
||||
public EthernetController(DSystem system)
|
||||
{
|
||||
_system = system;
|
||||
_fifo = new Queue<ushort>();
|
||||
_inputPacket = new Queue<ushort>();
|
||||
_outputPacket = new Queue<ushort>();
|
||||
_pendingPackets = new Queue<MemoryStream>();
|
||||
|
||||
_crc32 = new CRC32();
|
||||
|
||||
// Attach real Ethernet device if user has specified one, otherwise leave unattached; output data
|
||||
// will go into a bit-bucket.
|
||||
try
|
||||
{
|
||||
|
||||
if (Configuration.HostRawEthernetInterfacesAvailable &&
|
||||
!string.IsNullOrWhiteSpace(Configuration.HostPacketInterfaceName))
|
||||
{
|
||||
_hostInterface = new HostEthernetEncapsulation(Configuration.HostPacketInterfaceName);
|
||||
_hostInterface.RegisterReceiveCallback(OnHostPacketReceived);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_hostInterface = null;
|
||||
Log.Write(LogComponent.HostEthernet, "Unable to configure network interface. Error {0}", e.Message);
|
||||
}
|
||||
|
||||
_readerLock = new ReaderWriterLockSlim();
|
||||
|
||||
// Start the ethernet reciever poll event, this will run forever.
|
||||
_system.Scheduler.Schedule(_receiverPollInterval, ReceiverPollCallback);
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_turnOff_ = false;
|
||||
_rxEvenLen = false;
|
||||
_rxGoodCRC = false;
|
||||
_rxOverrun_ = true;
|
||||
_txUnderrun = false;
|
||||
_txCollision_ = true;
|
||||
_rxMode_ = true;
|
||||
_enableTx = false;
|
||||
_lastWord = false;
|
||||
_enableRcv = false;
|
||||
_localLoop = false;
|
||||
_loopBack = false;
|
||||
_defer = false;
|
||||
|
||||
_purge = false;
|
||||
_tickElapsed = false;
|
||||
_outAttn = false;
|
||||
_inAttn = false;
|
||||
_transmitterRunning = false;
|
||||
|
||||
_outputData = 0;
|
||||
_outputDataLatched = false;
|
||||
_fifo.Clear();
|
||||
_inputPacket.Clear();
|
||||
_crc32.Reset();
|
||||
}
|
||||
|
||||
public int EtherDisp()
|
||||
{
|
||||
//
|
||||
// Pin 139(YIODisp.1) : Hooked to "Attn," which appear to be whether any attention is needed by the receiver
|
||||
// or transmitter.
|
||||
// Pin 39(YIODisp.0) : "(schematic) Must be zero for the transmitting inner loop uCode. It is also used to
|
||||
// determine if the Option card is plugged in."
|
||||
//
|
||||
int value = 0;
|
||||
|
||||
if (_turnOff_)
|
||||
{
|
||||
//
|
||||
// Ethernet is not turned off, returned value is based on whether
|
||||
// the transmitter or reciever hardware has a status to report.
|
||||
value = _outAttn | _inAttn ? 1 : 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public ushort EStatus()
|
||||
{
|
||||
ushort value = (ushort)
|
||||
~((_turnOff_ ? 0x0001 : 0x00) |
|
||||
(_rxEvenLen ? 0x0002 : 0x00) |
|
||||
(_rxGoodCRC ? 0x0004 : 0x00) |
|
||||
(_rxOverrun_ ? 0x0008 : 0x00) |
|
||||
(_rxGoodAlign ? 0x0010 : 0x00) |
|
||||
(!_txUnderrun ? 0x0020 : 0x00) |
|
||||
(_txCollision_ ? 0x0040 : 0x00) |
|
||||
(_rxMode_ ? 0x0080 : 0x00) |
|
||||
(_enableTx ? 0x0100 : 0x00) |
|
||||
(_lastWord ? 0x0200 : 0x00) |
|
||||
(_enableRcv ? 0x0400 : 0x00) |
|
||||
(_localLoop ? 0x0800 : 0x00) |
|
||||
(_loopBack ? 0x1000 : 0x00));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public void EOCtl(ushort value)
|
||||
{
|
||||
// EOCtl: Bit(etc)
|
||||
// ----------------------------
|
||||
// EnableTrn 15
|
||||
// LastWord 14
|
||||
// Defer 13
|
||||
_enableTx = (value & 0x1) != 0;
|
||||
_lastWord = (value & 0x2) != 0;
|
||||
_defer = (value & 0x4) != 0;
|
||||
|
||||
_outAttn = false;
|
||||
_txUnderrun = false;
|
||||
_txCollision_ = true;
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl,
|
||||
"EOCtl<- 0x{0:x4}: enableTx {1} lastWord {2} defer {3}",
|
||||
value,
|
||||
_enableTx,
|
||||
_lastWord,
|
||||
_defer
|
||||
);
|
||||
|
||||
//
|
||||
// Writing EOCtl resets the defer clock
|
||||
//
|
||||
_tickElapsed = false;
|
||||
_system.Scheduler.Cancel(_deferEvent);
|
||||
|
||||
if (_defer)
|
||||
{
|
||||
//
|
||||
// Queue up an event 51.2uS in the future, this will
|
||||
// set _tickElapsed, update wakeups, and start the transmitter when it fires.
|
||||
//
|
||||
_deferEvent = _system.Scheduler.Schedule(_deferDelay, DeferCallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Start the transmitter running if need be (if it isn't already).
|
||||
//
|
||||
if (_enableTx && !_transmitterRunning && !_lastWord)
|
||||
{
|
||||
_crc32.Reset();
|
||||
StartTransmitter();
|
||||
}
|
||||
}
|
||||
|
||||
if (!_enableTx)
|
||||
{
|
||||
_fifo.Clear();
|
||||
StopTransmitter();
|
||||
}
|
||||
|
||||
UpdateWakeup();
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "EOCtl end.");
|
||||
}
|
||||
|
||||
public void EICtl(ushort value)
|
||||
{
|
||||
// EICtl: Bit(xerox order)
|
||||
// ------------------------------------
|
||||
// EnableRcv 15
|
||||
// TurnOff' 14
|
||||
// LocalLoop 13
|
||||
// LoopBack 12
|
||||
_enableRcv = (value & 0x1) != 0;
|
||||
_turnOff_ = (value & 0x2) == 0;
|
||||
_localLoop = (value & 0x4) != 0;
|
||||
_loopBack = (value & 0x8) != 0;
|
||||
|
||||
if (!_enableRcv)
|
||||
{
|
||||
// Reset receive state
|
||||
_rxMode_ = true;
|
||||
_receiverState = ReceiverState.Preamble;
|
||||
_inAttn = false;
|
||||
|
||||
_rxGoodCRC = true;
|
||||
_rxGoodAlign = true;
|
||||
_rxOverrun_ = true;
|
||||
_rxEvenLen = true;
|
||||
|
||||
if (!_loopBack)
|
||||
{
|
||||
_fifo.Clear();
|
||||
}
|
||||
|
||||
_inputPacket.Clear();
|
||||
_crc32.Reset();
|
||||
}
|
||||
|
||||
UpdateWakeup();
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "EICtl<- 0x{0:x4} enablerx {1} turnOff' {2} localLoop {3} loopBack {4}.",
|
||||
value,
|
||||
_enableRcv,
|
||||
_turnOff_,
|
||||
_localLoop,
|
||||
_loopBack);
|
||||
}
|
||||
|
||||
public void EOData(ushort value)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "EOData<- 0x{0:x4}.", value);
|
||||
|
||||
_outputData = value;
|
||||
_outputDataLatched = true;
|
||||
}
|
||||
|
||||
public void EStrobe(int cycle)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "EStrobe.");
|
||||
|
||||
if ((cycle == 1 || cycle == 3) & !_lastWord)
|
||||
{
|
||||
// Strobe output data into FIFO.
|
||||
|
||||
if (!_outputDataLatched)
|
||||
{
|
||||
// This is not actually an underrun case, it indicates a case where the microcode is doing
|
||||
// something we do not expect.
|
||||
if (Log.Enabled) Log.Write(LogType.Error, LogComponent.EthernetControl, "EStrobe: no data latched.");
|
||||
_outAttn = false;
|
||||
}
|
||||
|
||||
//
|
||||
// Move data from output data word into the FIFO.
|
||||
//
|
||||
if (_fifo.Count < 16)
|
||||
{
|
||||
_fifo.Enqueue(_outputData);
|
||||
_outputDataLatched = false;
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "EStrobe: loaded word 0x{0:x4} into FIFO. FIFO count is now {1}",
|
||||
_outputData, _fifo.Count);
|
||||
|
||||
_outAttn = false;
|
||||
|
||||
UpdateWakeup();
|
||||
}
|
||||
else
|
||||
{
|
||||
_fifo.Dequeue();
|
||||
_fifo.Enqueue(_outputData);
|
||||
// This should not happen; microcode should sleep when the FIFO is full.
|
||||
if (Log.Enabled) Log.Write(LogType.Error, LogComponent.EthernetControl, "EStrobe: FIFO full, dropping word.");
|
||||
}
|
||||
}
|
||||
else if (cycle == 2)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "EStrobe: (cycle 2) flushing received data.");
|
||||
|
||||
// Throw out input data and stop the receiver
|
||||
_fifo.Clear();
|
||||
_inAttn = false;
|
||||
_rxMode_ = true;
|
||||
StopReceiver();
|
||||
UpdateWakeup();
|
||||
}
|
||||
}
|
||||
|
||||
public ushort EIData(int cycle)
|
||||
{
|
||||
ushort value = 0;
|
||||
|
||||
//
|
||||
// Read from the input/output FIFO.
|
||||
//
|
||||
if (_fifo.Count > 0)
|
||||
{
|
||||
value = _fifo.Dequeue();
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "<-EIData: Returning FIFO word 0x{0:x4}. FIFO count is now {1}",
|
||||
value, _fifo.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogType.Error, LogComponent.EthernetControl, "<-EIData: FIFO empty.");
|
||||
|
||||
// TODO: does this cause an underrun?
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private void DeferCallback(ulong skewNsec, object context)
|
||||
{
|
||||
_tickElapsed = true;
|
||||
UpdateWakeup();
|
||||
_tickElapsed = false;
|
||||
|
||||
//
|
||||
// Start the transmitter.
|
||||
//
|
||||
if (_enableTx && !_transmitterRunning)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Defer complete, starting transmitter.");
|
||||
StartTransmitter();
|
||||
}
|
||||
}
|
||||
|
||||
private void StartTransmitter()
|
||||
{
|
||||
//
|
||||
// Start transmit clock running; this will wake up every
|
||||
// 1600ns to pick up a word (if available) from the fifo
|
||||
// and transmit it. (If Defer is active, we will do this
|
||||
// after the deferral period has elapsed.)
|
||||
//
|
||||
if (!_transmitterRunning)
|
||||
{
|
||||
//
|
||||
// First abort any transmit clock that may be running.
|
||||
//
|
||||
_system.Scheduler.Cancel(_transmitEvent);
|
||||
|
||||
//
|
||||
// Schedule the transmission callback.
|
||||
_transmitEvent = _system.Scheduler.Schedule(_ipgInterval, TransmitCallback);
|
||||
|
||||
//
|
||||
// Clear the output packet.
|
||||
//
|
||||
_outputPacket.Clear();
|
||||
|
||||
_transmitterRunning = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Transmitter already running.");
|
||||
}
|
||||
}
|
||||
|
||||
private void StopTransmitter()
|
||||
{
|
||||
_system.Scheduler.Cancel(_transmitEvent);
|
||||
_transmitterRunning = false;
|
||||
}
|
||||
|
||||
private void TransmitWord(ushort word)
|
||||
{
|
||||
if (_localLoop || _loopBack)
|
||||
{
|
||||
// Loop back to FIFO through the receiver.
|
||||
|
||||
//
|
||||
// Append this word to the input packet.
|
||||
// It will be picked up by the Receive callback and
|
||||
// put into the FIFO in due time.
|
||||
//
|
||||
_inputPacket.Enqueue(word);
|
||||
|
||||
//
|
||||
// Ensure the receiver is running.
|
||||
//
|
||||
RunReceiver();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Append to outgoing packet.
|
||||
_outputPacket.Enqueue(word);
|
||||
}
|
||||
}
|
||||
|
||||
private void CompleteTransmission()
|
||||
{
|
||||
//
|
||||
// Transmit completed packet over real ethernet.
|
||||
//
|
||||
|
||||
//
|
||||
// A properly formed packet generated by the microcode should begin with the standard ethernet
|
||||
// SFD of 3 words of 0x5555 and 1 word of 0x55d5. This must be stripped before we send it
|
||||
// to the host device.
|
||||
//
|
||||
if (_outputPacket.Count < 4)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Malformed packet: too short.");
|
||||
return;
|
||||
}
|
||||
|
||||
bool badSfd = false;
|
||||
for(int i=0;i<4;i++)
|
||||
{
|
||||
ushort sfdWord = _outputPacket.Dequeue();
|
||||
|
||||
if (i < 3)
|
||||
{
|
||||
badSfd = sfdWord != 0x5555;
|
||||
}
|
||||
else
|
||||
{
|
||||
badSfd = sfdWord != 0x55d5;
|
||||
}
|
||||
}
|
||||
|
||||
if (badSfd)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Malformed packet: Invalid SFD.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_outputPacket.Count > 0 && _hostInterface != null)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Transmitting completed packet.");
|
||||
_hostInterface.Send(_outputPacket.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private void TransmitCallback(ulong skewNsec, object context)
|
||||
{
|
||||
//
|
||||
// Pull the next word from the FIFO, if available.
|
||||
//
|
||||
if (_fifo.Count > 0)
|
||||
{
|
||||
ushort nextWord = _fifo.Dequeue();
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Transmitting word 0x{0:x4}", nextWord);
|
||||
TransmitWord(nextWord);
|
||||
}
|
||||
else if (!_lastWord)
|
||||
{
|
||||
//
|
||||
// No data available in FIFO and LastWord is not set: Underrun.
|
||||
// Raise txUnderrun to signal an error.
|
||||
//
|
||||
_txUnderrun = true;
|
||||
if (Log.Enabled) Log.Write(LogType.Error, LogComponent.EthernetControl, "Transmit underrun.");
|
||||
}
|
||||
|
||||
if (_lastWord && _fifo.Count == 0)
|
||||
{
|
||||
//
|
||||
// If LastWord is set and the FIFO is empty, that will be the last word in the packet. Shut things down.
|
||||
//
|
||||
_transmitterRunning = false;
|
||||
_outAttn = true;
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Last word. Stopping transmission.");
|
||||
|
||||
//
|
||||
// Transmit completed packet over real ethernet.
|
||||
//
|
||||
CompleteTransmission();
|
||||
}
|
||||
else if (_txUnderrun)
|
||||
{
|
||||
_transmitterRunning = false;
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Underrun. Stopping transmission.");
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Still going, schedule the next callback.
|
||||
//
|
||||
_transmitEvent = _system.Scheduler.Schedule(_transmitInterval, TransmitCallback);
|
||||
}
|
||||
|
||||
//
|
||||
// Update wakeups -- if the FIFO has space now, the microcode should be awakened, for example.
|
||||
//
|
||||
UpdateWakeup();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the host ethernet interface receives a packet destined for us.
|
||||
/// NOTE: This runs on the PCap or UDP receiver thread, not the main emulator thread.
|
||||
/// Any access to emulator structures must be properly protected.
|
||||
///
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
private void OnHostPacketReceived(MemoryStream data)
|
||||
{
|
||||
//
|
||||
// Append the new packet onto our pending packets queue.
|
||||
// This will be picked up when the receiver is ready to receive things.
|
||||
//
|
||||
_readerLock.EnterUpgradeableReadLock();
|
||||
if (!_enableRcv || !_turnOff_)
|
||||
{
|
||||
//
|
||||
// Receiver is offjust drop the packet on the floor.
|
||||
//
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Ethernet receiver is off; dropping this packet.");
|
||||
|
||||
_readerLock.EnterWriteLock();
|
||||
_pendingPackets.Clear();
|
||||
_readerLock.ExitWriteLock();
|
||||
}
|
||||
else if (_pendingPackets.Count < 32)
|
||||
{
|
||||
//
|
||||
// Place the packet into the queue; this will be picked up by the receiver poll thread
|
||||
// and passed to the receiver.
|
||||
//
|
||||
_readerLock.EnterWriteLock();
|
||||
_pendingPackets.Enqueue(data);
|
||||
_readerLock.ExitWriteLock();
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Packet (length {0}) added to pending buffer.", data.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Too many queued-up packets, drop this one.
|
||||
//
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Pending buffer full; dropping this packet.");
|
||||
}
|
||||
_readerLock.ExitUpgradeableReadLock();
|
||||
}
|
||||
|
||||
private void StopReceiver()
|
||||
{
|
||||
_system.Scheduler.Cancel(_receiveEvent);
|
||||
_receiverRunning = false;
|
||||
}
|
||||
|
||||
private void RunReceiver()
|
||||
{
|
||||
_rxMode_ = false;
|
||||
|
||||
if (!_receiverRunning && _enableRcv)
|
||||
{
|
||||
//
|
||||
// This is a hack: For loopback cases the real hardware has mysterious state machines to deal with
|
||||
// tracking the FIFO properly (since it's being used for both input and output at the same time,
|
||||
// something that only occurs during loopback testing -- the complication is how the transmit state machine knows
|
||||
// when the last word provided by the microcode has been sent, when the loopback is bringing new words into the FIFO
|
||||
// at the same time).
|
||||
// Because we live in a fantasy world of emulation, we can cheat: To keep things simple here we simply delay the
|
||||
// receive operation to ensure that there is no overlap between the transmit and receive on loopback, this avoids
|
||||
// needing extra logic for the FIFO during loopback tests.
|
||||
//
|
||||
_receiveEvent = _system.Scheduler.Schedule(
|
||||
_localLoop || _loopBack ? _receiveIntervalLoopback : _receiveInterval,
|
||||
ReceiveCallback);
|
||||
|
||||
_receiverRunning = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReceiverPollCallback(ulong skewNsec, object context)
|
||||
{
|
||||
if (!_enableRcv || !_turnOff_ || _enableTx || _transmitterRunning || _localLoop || _loopBack)
|
||||
{
|
||||
//
|
||||
// Receiver is off, we're currently transmitting, or we're in loopback mode, we do nothing.
|
||||
//
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// See if there's a packet to pick up.
|
||||
//
|
||||
MemoryStream packetStream = null;
|
||||
|
||||
_readerLock.EnterWriteLock();
|
||||
if (!_receiverRunning && _pendingPackets.Count > 0)
|
||||
{
|
||||
// We have a packet, dequeue it and dump it into the receiver input queue.
|
||||
packetStream = _pendingPackets.Dequeue();
|
||||
}
|
||||
_readerLock.ExitWriteLock();
|
||||
|
||||
if (packetStream != null)
|
||||
{
|
||||
//
|
||||
// Read the stream into the receiver input queue.
|
||||
//
|
||||
packetStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
while (packetStream.Position < packetStream.Length)
|
||||
{
|
||||
_inputPacket.Enqueue((ushort)((packetStream.ReadByte() << 8) | packetStream.ReadByte()));
|
||||
}
|
||||
|
||||
//
|
||||
// Skip the preamble state (only used in loopback)
|
||||
//
|
||||
_receiverState = ReceiverState.Data;
|
||||
|
||||
//
|
||||
// Alert the microcode to the presence of input data and start processing.
|
||||
//
|
||||
RunReceiver();
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Receive: Incoming packet queued into input buffer.");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Schedule the next poll callback.
|
||||
//
|
||||
_system.Scheduler.Schedule(_receiverPollInterval, ReceiverPollCallback);
|
||||
}
|
||||
|
||||
private void ReceiveCallback(ulong skewNsec, object context)
|
||||
{
|
||||
//
|
||||
// Pull the next word from the input packet and run the state machine.
|
||||
//
|
||||
if (_inputPacket.Count > 0)
|
||||
{
|
||||
ushort nextWord = _inputPacket.Dequeue();
|
||||
|
||||
switch (_receiverState)
|
||||
{
|
||||
case ReceiverState.Preamble:
|
||||
if (nextWord == 0x55d5) // end of preamble
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Receive: end of preamble, switching to Data state.");
|
||||
_receiverState = ReceiverState.Data;
|
||||
}
|
||||
break;
|
||||
|
||||
case ReceiverState.Data:
|
||||
//
|
||||
// Stuff into FIFO.
|
||||
//
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Receive: Enqueuing Data word 0x{0:x4} onto FIFO, {1} words left.", nextWord, _inputPacket.Count);
|
||||
_fifo.Enqueue(nextWord);
|
||||
_crc32.AddToChecksum(nextWord);
|
||||
UpdateWakeup();
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Packet CRC is now 0x{0:x8}", _crc32.Checksum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_inputPacket.Count > 0)
|
||||
{
|
||||
//
|
||||
// Post next event if there are still words left.
|
||||
//
|
||||
_receiveEvent = _system.Scheduler.Schedule(_transmitInterval, ReceiveCallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// End of packet.
|
||||
//
|
||||
_receiverRunning = false;
|
||||
|
||||
//
|
||||
// Let microcode know the packet is done.
|
||||
//
|
||||
_inAttn = true;
|
||||
|
||||
//
|
||||
// Update CRC and other flags.
|
||||
//
|
||||
_rxMode_ = false;
|
||||
|
||||
_rxGoodCRC = _loopBack || _localLoop ? _crc32.Checksum == _goodCRC : true;
|
||||
|
||||
UpdateWakeup();
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Final Packet CRC is 0x{0:x8}", _crc32.Checksum);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateWakeup()
|
||||
{
|
||||
//
|
||||
// See schematic, pg 2; ethernet requests (wakeups) generated by:
|
||||
// TxMode & BufIR & Defer' & LastWord' (i.e.transmit on, fifo buffer not full, not deferring, not the last word)
|
||||
// OR
|
||||
// Defer & TickElapsed (microcode asked for the transmission to be deferred, and that deferral time has elapsed)
|
||||
// OR
|
||||
// RcvMode & BufOR & Purge' (i.e. rcv on, fifo data ready, not purging fifo)
|
||||
// OR
|
||||
// Attn (i.e.hardware has a a status to report)
|
||||
//
|
||||
bool txWakeup = _enableTx && _fifo.Count < 16 && !_defer && !_lastWord;
|
||||
bool deferWakeup = _defer & _tickElapsed;
|
||||
bool rxWakeup = !_rxMode_ && _fifo.Count > 2 && !_purge;
|
||||
|
||||
if (txWakeup || deferWakeup || rxWakeup || _outAttn || _inAttn)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Waking Ethernet task (tx {0} defer {1} rx {2} outAttn {3} inAttn {4}", txWakeup, deferWakeup, rxWakeup, _outAttn, _inAttn);
|
||||
_system.CP.WakeTask(TaskType.Ethernet);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.EthernetControl, "Sleeping Ethernet task.");
|
||||
_system.CP.SleepTask(TaskType.Ethernet);
|
||||
}
|
||||
}
|
||||
|
||||
private DSystem _system;
|
||||
|
||||
// Output data
|
||||
private bool _outputDataLatched;
|
||||
private ushort _outputData;
|
||||
private Queue<ushort> _fifo;
|
||||
|
||||
// Input data
|
||||
private Queue<ushort> _inputPacket;
|
||||
private Queue<MemoryStream> _pendingPackets;
|
||||
|
||||
// Defer timings
|
||||
private bool _tickElapsed;
|
||||
|
||||
// Attention flags
|
||||
private bool _outAttn;
|
||||
private bool _inAttn;
|
||||
|
||||
private bool _purge;
|
||||
|
||||
// Status Bit(in Xerox order)
|
||||
// --------------------------------
|
||||
// TurnOff' : 15
|
||||
// R.EvenLen : 14
|
||||
// R.GoodCRC : 13
|
||||
// R.Overrun' : 12
|
||||
// R.GoodAlign : 11
|
||||
// T.Underrun' : 10
|
||||
// T.Collision' : 9
|
||||
// RcvMode' : 8
|
||||
// EnableTrn : 7
|
||||
// LastWord : 6
|
||||
// EnableRcv : 5
|
||||
// LocalLoop : 4
|
||||
// Loopback : 3
|
||||
|
||||
// DiagVideoData : 2
|
||||
// VideoClock : 1 // Used by LSEP
|
||||
// DiagLineSync : 0
|
||||
private bool _turnOff_;
|
||||
private bool _rxEvenLen;
|
||||
private bool _rxGoodCRC;
|
||||
private bool _rxOverrun_;
|
||||
private bool _rxGoodAlign;
|
||||
private bool _txUnderrun;
|
||||
private bool _txCollision_;
|
||||
private bool _rxMode_;
|
||||
private bool _enableTx;
|
||||
private bool _lastWord;
|
||||
private bool _enableRcv;
|
||||
private bool _localLoop;
|
||||
private bool _loopBack;
|
||||
|
||||
// EOCtl: Bit(etc)
|
||||
// ----------------------------
|
||||
// EnableTrn 15
|
||||
// LastWord 14
|
||||
// Defer 13
|
||||
private bool _defer;
|
||||
|
||||
|
||||
// EICtl: Bit(xerox order)
|
||||
// ------------------------------------
|
||||
// EnableRcv 15
|
||||
// TurnOff' 14
|
||||
// LocalLoop 13
|
||||
// LoopBack 12
|
||||
// (See above)
|
||||
|
||||
//
|
||||
// Defer event & timing -- 51.2uS
|
||||
//
|
||||
private Event _deferEvent;
|
||||
private readonly ulong _deferDelay = (ulong)(51.2 * Conversion.UsecToNsec);
|
||||
|
||||
//
|
||||
// Transmit event and timing -- 1600nS
|
||||
//
|
||||
private readonly ulong _transmitInterval = 1200;
|
||||
private readonly ulong _ipgInterval = (ulong)(9.6 * Conversion.UsecToNsec); // Inter-packet gap
|
||||
private bool _transmitterRunning;
|
||||
private Event _transmitEvent;
|
||||
|
||||
//
|
||||
// Receive event, timing, and thread safety
|
||||
//
|
||||
private readonly ulong _receiveInterval = 1200;
|
||||
private readonly ulong _receiveIntervalLoopback = 25600;
|
||||
private bool _receiverRunning;
|
||||
private ReceiverState _receiverState;
|
||||
private Event _receiveEvent;
|
||||
|
||||
private readonly ulong _receiverPollInterval = (ulong)(51.2 * Conversion.UsecToNsec);
|
||||
|
||||
271
D/Ethernet/HostEthernet.cs
Normal file
271
D/Ethernet/HostEthernet.cs
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
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 SharpPcap;
|
||||
using SharpPcap.WinPcap;
|
||||
using SharpPcap.LibPcap;
|
||||
using SharpPcap.AirPcap;
|
||||
using PacketDotNet;
|
||||
|
||||
using System;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
|
||||
using D.Logging;
|
||||
using PacketDotNet.Utils;
|
||||
using System.Text;
|
||||
|
||||
namespace D.Ethernet
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a host ethernet interface.
|
||||
/// </summary>
|
||||
public struct EthernetInterface
|
||||
{
|
||||
public EthernetInterface(string name, string description)
|
||||
{
|
||||
Name = name;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0} ({1})", Name, Description);
|
||||
}
|
||||
|
||||
public string Name;
|
||||
public string Description;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements the logic for sending and receiving emulated 10mbit ethernet packets over an actual
|
||||
/// ethernet interface controlled by the host operating system.
|
||||
///
|
||||
/// This uses SharpPcap to do the dirty work.
|
||||
/// </summary>
|
||||
public class HostEthernetEncapsulation : IPacketInterface
|
||||
{
|
||||
public HostEthernetEncapsulation(string name)
|
||||
{
|
||||
// Find the specified device by name
|
||||
foreach (ICaptureDevice device in CaptureDeviceList.Instance)
|
||||
{
|
||||
if (device is WinPcapDevice)
|
||||
{
|
||||
//
|
||||
// We use the friendly name to make it easier to specify in config files.
|
||||
//
|
||||
if (((WinPcapDevice)device).Interface.FriendlyName.ToLowerInvariant() == name.ToLowerInvariant())
|
||||
{
|
||||
AttachInterface(device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (device.Name.ToLowerInvariant() == name.ToLowerInvariant())
|
||||
{
|
||||
AttachInterface(device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_interface == null)
|
||||
{
|
||||
Log.Write(LogComponent.HostEthernet, "Specified ethernet interface does not exist or is not compatible with Darkstar.");
|
||||
throw new InvalidOperationException("Specified ethernet interface does not exist or is not compatible with Darkstar.");
|
||||
}
|
||||
|
||||
UpdateSourceAddress();
|
||||
}
|
||||
|
||||
public void RegisterReceiveCallback(ReceivePacketDelegate callback)
|
||||
{
|
||||
_callback = callback;
|
||||
|
||||
// Now that we have a callback we can start receiving stuff.
|
||||
Open(true /* promiscuous */, 0);
|
||||
BeginReceive();
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
if (_interface != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_interface.Started)
|
||||
{
|
||||
_interface.StopCapture();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Eat exceptions. The Pcap libs seem to throw on StopCapture on
|
||||
// Unix platforms, we don't really care about them (since we're shutting down anyway)
|
||||
// but this prevents debug spew from appearing on the console.
|
||||
}
|
||||
finally
|
||||
{
|
||||
_interface.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an array of words over the ethernet.
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
/// <param name="hostId"></param>
|
||||
public void Send(ushort[] packet)
|
||||
{
|
||||
byte[] packetBytes = new byte[packet.Length * 2];
|
||||
|
||||
// StringBuilder sb = new StringBuilder();
|
||||
//
|
||||
// Do this annoying dance to stuff the ushorts into bytes because this is C#.
|
||||
//
|
||||
for (int i = 0; i < packet.Length; i++)
|
||||
{
|
||||
packetBytes[i * 2] = (byte)(packet[i] >> 8);
|
||||
packetBytes[i * 2 + 1] = (byte)(packet[i]);
|
||||
|
||||
// sb.AppendFormat("{0:x2} {1:x2} ", packetBytes[i * 2], packetBytes[i * 2 + 1]);
|
||||
}
|
||||
|
||||
ByteArraySegment seg = new ByteArraySegment(packetBytes);
|
||||
|
||||
EthernetPacket p = new EthernetPacket(seg);
|
||||
|
||||
// Send it over the 'net!
|
||||
_interface.SendPacket(p);
|
||||
|
||||
Log.Write(LogComponent.HostEthernet, "Ethernet packet (length {0}) sent.", packetBytes.Length);
|
||||
// Log.Write(LogComponent.HostEthernet, "Contents: {0}", sb.ToString());
|
||||
}
|
||||
|
||||
private void ReceiveCallback(object sender, CaptureEventArgs e)
|
||||
{
|
||||
//
|
||||
// Filter out packets intended for the emulator, forward them on, drop everything else.
|
||||
//
|
||||
if (e.Packet.LinkLayerType == LinkLayers.Ethernet)
|
||||
{
|
||||
//
|
||||
// We wrap this in a try/catch; on occasion Packet.ParsePacket fails due to a bug
|
||||
// in the PacketDotNet library.
|
||||
//
|
||||
EthernetPacket packet = null;
|
||||
try
|
||||
{
|
||||
packet = (EthernetPacket)Packet.ParsePacket(LinkLayers.Ethernet, e.Packet.Data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Just eat this, log a message.
|
||||
Log.Write(LogType.Error, LogComponent.HostEthernet, "Failed to parse incoming packet. Exception {0}", ex.Message);
|
||||
packet = null;
|
||||
}
|
||||
|
||||
if (packet != null)
|
||||
{
|
||||
if (!packet.SourceHwAddress.Equals(_10mbitSourceAddress) &&
|
||||
packet.PayloadData != null) // Don't recieve packets sent by this emulator.
|
||||
{
|
||||
Log.Write(LogComponent.HostEthernet, "Received 10mbit packet.");
|
||||
_callback(new System.IO.MemoryStream(packet.PayloadData));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not for us, discard the packet.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSourceAddress()
|
||||
{
|
||||
byte[] macBytes = new byte[6];
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
macBytes[i] = (byte)((Configuration.HostID >> (i * 8)));
|
||||
}
|
||||
|
||||
_10mbitSourceAddress = new PhysicalAddress(macBytes);
|
||||
|
||||
}
|
||||
|
||||
private void AttachInterface(ICaptureDevice iface)
|
||||
{
|
||||
_interface = iface;
|
||||
|
||||
if (_interface == null)
|
||||
{
|
||||
throw new InvalidOperationException("Requested interface not found.");
|
||||
}
|
||||
|
||||
Log.Write(LogComponent.HostEthernet, "Attached to host interface {0}", iface.Name);
|
||||
}
|
||||
|
||||
private void Open(bool promiscuous, int timeout)
|
||||
{
|
||||
if (_interface is WinPcapDevice)
|
||||
{
|
||||
((WinPcapDevice)_interface).Open(promiscuous ? OpenFlags.MaxResponsiveness | OpenFlags.Promiscuous : OpenFlags.MaxResponsiveness, timeout);
|
||||
}
|
||||
else if (_interface is LibPcapLiveDevice)
|
||||
{
|
||||
((LibPcapLiveDevice)_interface).Open(promiscuous ? DeviceMode.Promiscuous : DeviceMode.Normal, timeout);
|
||||
}
|
||||
else if (_interface is AirPcapDevice)
|
||||
{
|
||||
((AirPcapDevice)_interface).Open(promiscuous ? OpenFlags.MaxResponsiveness | OpenFlags.Promiscuous : OpenFlags.MaxResponsiveness, timeout);
|
||||
}
|
||||
|
||||
Log.Write(LogComponent.HostEthernet, "Host interface opened and receiving packets.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begin receiving packets, forever.
|
||||
/// </summary>
|
||||
private void BeginReceive()
|
||||
{
|
||||
// Kick off receiver.
|
||||
_interface.OnPacketArrival += ReceiveCallback;
|
||||
_interface.StartCapture();
|
||||
}
|
||||
|
||||
private ICaptureDevice _interface;
|
||||
private ReceivePacketDelegate _callback;
|
||||
|
||||
private PhysicalAddress _10mbitSourceAddress;
|
||||
}
|
||||
}
|
||||
60
D/Ethernet/IPacketInterface.cs
Normal file
60
D/Ethernet/IPacketInterface.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
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.IO;
|
||||
|
||||
namespace D.Ethernet
|
||||
{
|
||||
public delegate void ReceivePacketDelegate(MemoryStream data);
|
||||
|
||||
/// <summary>
|
||||
/// Provides a generic interface for host network devices that can encapsulate
|
||||
/// Ethernet packets.
|
||||
/// </summary>
|
||||
public interface IPacketInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers a callback delegate to handle packets that are received.
|
||||
/// </summary>
|
||||
/// <param name="callback"></param>
|
||||
void RegisterReceiveCallback(ReceivePacketDelegate callback);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the specified word array over the device.
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
/// <param name="length"></param>
|
||||
void Send(ushort[] packet);
|
||||
|
||||
/// <summary>
|
||||
/// Shuts down the encapsulation provider.
|
||||
/// </summary>
|
||||
void Shutdown();
|
||||
}
|
||||
}
|
||||
230
D/HighResTimer.cs
Normal file
230
D/HighResTimer.cs
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
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.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace D
|
||||
{
|
||||
/// <summary>
|
||||
/// HighResTimer gives us access to NT's very-high-resolution PerformanceCounters.
|
||||
/// This gives us the precision we need to sync emulation to any speed we desire.
|
||||
/// </summary>
|
||||
public sealed class HighResTimer
|
||||
{
|
||||
[DllImport("Kernel32.dll")]
|
||||
private static extern bool QueryPerformanceCounter(
|
||||
out long lpPerformanceCount);
|
||||
|
||||
[DllImport("Kernel32.dll")]
|
||||
private static extern bool QueryPerformanceFrequency(
|
||||
out long lpFrequency);
|
||||
|
||||
public HighResTimer()
|
||||
{
|
||||
// What's the frequency, Kenneth?
|
||||
if (QueryPerformanceFrequency(out _frequency) == false)
|
||||
{
|
||||
// high-performance counter not supported
|
||||
throw new Win32Exception();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current time in seconds.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double GetCurrentTime()
|
||||
{
|
||||
long currentTime;
|
||||
QueryPerformanceCounter(out currentTime);
|
||||
|
||||
return (double)(currentTime) / (double)_frequency;
|
||||
}
|
||||
|
||||
private long _frequency;
|
||||
}
|
||||
|
||||
public sealed class FrameTimer
|
||||
{
|
||||
[DllImport("winmm.dll", EntryPoint = "timeGetDevCaps", SetLastError = true)]
|
||||
static extern UInt32 TimeGetDevCaps(ref TimeCaps timeCaps, UInt32 sizeTimeCaps);
|
||||
|
||||
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
|
||||
static extern UInt32 TimeBeginPeriod(UInt32 uPeriod);
|
||||
|
||||
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod")]
|
||||
public static extern uint TimeEndPeriod(uint uMilliseconds);
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint = "CreateTimerQueue")]
|
||||
public static extern IntPtr CreateTimerQueue();
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint = "DeleteTimerQueueEx")]
|
||||
public static extern bool DeleteTimerQueue(IntPtr hTimerQueue, IntPtr hCompletionEvent);
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint = "CreateTimerQueueTimer")]
|
||||
public static extern bool CreateTimerQueueTimer(out IntPtr phNewTimer, IntPtr hTimerQueue, IntPtr Callback, IntPtr Parameter, UInt32 DueTime, UInt32 Period, uint Flags);
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint = "ChangeTimerQueueTimer")]
|
||||
public static extern bool ChangeTimerQueueTimer(IntPtr hTimerQueue, IntPtr hTimer, UInt32 DueTime, UInt32 Period);
|
||||
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint = "DeleteTimerQueueTimer")]
|
||||
public static extern bool DeleteTimerQueueTimer(IntPtr hTimerQueue, IntPtr hTimer, IntPtr hCompletionEvent);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct TimeCaps
|
||||
{
|
||||
public UInt32 wPeriodMin;
|
||||
public UInt32 wPeriodMax;
|
||||
};
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
public delegate void UnmanagedTimerCallback(IntPtr param, bool timerOrWait);
|
||||
|
||||
/// <summary>
|
||||
/// FrameTimer provides a simple method to synchronize execution to a given framerate.
|
||||
/// Calling WaitForFrame() blocks until the start of the next frame.
|
||||
///
|
||||
/// NOTE: This code uses the Win32 TimerQueue APIs instead of the System.Threading.Timer
|
||||
/// APIs because the .NET APIs do not allow execution of the callback on the timer's thread --
|
||||
/// it queues up a new worker thread. This lowers the accuracy of the timer, and since we
|
||||
/// need all the precision we can get they're not suitable here.
|
||||
/// </summary>
|
||||
/// <param name="framesPerSecond">The frame rate to sync to.</param>
|
||||
public FrameTimer(double framesPerSecond)
|
||||
{
|
||||
//
|
||||
// Set the timer to the minimum value (1ms). This should be supported on any modern x86 system.
|
||||
// If not, too bad...
|
||||
//
|
||||
UInt32 res = TimeBeginPeriod(1);
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
throw new InvalidOperationException("Unable to set timer period.");
|
||||
}
|
||||
|
||||
//
|
||||
// Create a new timer queue
|
||||
//
|
||||
_hTimerQueue = CreateTimerQueue();
|
||||
|
||||
if (_hTimerQueue == IntPtr.Zero)
|
||||
{
|
||||
throw new InvalidOperationException("Unable to create timer queue.");
|
||||
}
|
||||
|
||||
//
|
||||
// Since we only have a resolution of 1ms, we have to do some hackery to get a slightly more accurate framerate.
|
||||
// (60 fields/sec requires 16 2/3s ms frame delay.)
|
||||
// We alternate between two rates at varying intervals and this gets us fairly close to the desired frame rate.
|
||||
//
|
||||
_callback = new UnmanagedTimerCallback(TimerCallbackFn);
|
||||
|
||||
_highPeriod = (uint)Math.Ceiling(1000.0 * (1.0 / framesPerSecond));
|
||||
_lowPeriod = (uint)Math.Floor(1000.0 * (1.0 / framesPerSecond));
|
||||
_periodTenths = _periodSwitch = (uint)((1000.0 * (1.0 / framesPerSecond) - Math.Floor(1000.0 * (1.0 / framesPerSecond))) * 10.0);
|
||||
|
||||
if (!CreateTimerQueueTimer(out _hTimer, _hTimerQueue, Marshal.GetFunctionPointerForDelegate(_callback), IntPtr.Zero, _lowPeriod, _lowPeriod, 0x00000020 /* execute in timer thread */))
|
||||
{
|
||||
throw new InvalidOperationException("Unable to create timer queue timer.");
|
||||
}
|
||||
|
||||
_event = new AutoResetEvent(false);
|
||||
|
||||
_lowTimer = 0;
|
||||
}
|
||||
|
||||
~FrameTimer()
|
||||
{
|
||||
//
|
||||
// Clean stuff up
|
||||
//
|
||||
try
|
||||
{
|
||||
DeleteTimerQueueTimer(_hTimerQueue, _hTimer, IntPtr.Zero);
|
||||
DeleteTimerQueue(_hTimerQueue, IntPtr.Zero);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Eat exceptions (for Mono)
|
||||
}
|
||||
|
||||
//
|
||||
// Fire off a final event to release any call that's waiting...
|
||||
//
|
||||
if (_event != null)
|
||||
{
|
||||
_event.Set();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Waits for the timer to fire.
|
||||
/// </summary>
|
||||
public void WaitForFrame()
|
||||
{
|
||||
_event.WaitOne();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback from timer queue. Work done here is executed on the timer's thread, so must be quick.
|
||||
/// </summary>
|
||||
/// <param name="lpParameter"></param>
|
||||
/// <param name="TimerOrWaitFired"></param>
|
||||
private void TimerCallbackFn(IntPtr lpParameter, bool TimerOrWaitFired)
|
||||
{
|
||||
_event.Set();
|
||||
_lowTimer++;
|
||||
|
||||
if (_lowTimer >= _periodSwitch)
|
||||
{
|
||||
_lowTimer = 0;
|
||||
_period = !_period;
|
||||
ChangeTimerQueueTimer(_hTimerQueue, _hTimer, _period ? _lowPeriod : _highPeriod, _period ? _lowPeriod : _highPeriod);
|
||||
|
||||
_periodSwitch = !_period ? _periodTenths : 10 - _periodTenths;
|
||||
}
|
||||
}
|
||||
|
||||
private IntPtr _hTimerQueue;
|
||||
private IntPtr _hTimer;
|
||||
private AutoResetEvent _event;
|
||||
private UnmanagedTimerCallback _callback;
|
||||
private uint _lowPeriod;
|
||||
private uint _highPeriod;
|
||||
private uint _periodSwitch;
|
||||
private uint _periodTenths;
|
||||
private int _lowTimer;
|
||||
private bool _period;
|
||||
}
|
||||
}
|
||||
402
D/IO/FloppyDisk.cs
Normal file
402
D/IO/FloppyDisk.cs
Normal file
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
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.Text;
|
||||
|
||||
namespace D.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Presents data for a floppy disk, organized by cylinder, head, and sector,
|
||||
/// and provides constructors for loading from IMD file.
|
||||
/// </summary>
|
||||
public class FloppyDisk
|
||||
{
|
||||
public FloppyDisk(string imagePath)
|
||||
{
|
||||
_imagePath = imagePath;
|
||||
_tracks = new Track[2, 77];
|
||||
_isSingleSided = true;
|
||||
|
||||
using (FileStream fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
LoadIMD(fs);
|
||||
}
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get { return _imdHeader; }
|
||||
}
|
||||
|
||||
public bool IsSingleSided
|
||||
{
|
||||
get { return _isSingleSided; }
|
||||
}
|
||||
|
||||
public string ImagePath
|
||||
{
|
||||
get { return _imagePath; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns sector data for the given address.
|
||||
/// </summary>
|
||||
/// <param name="cylinder"></param>
|
||||
/// <param name="head"></param>
|
||||
/// <param name="sector"></param>
|
||||
/// <returns></returns>
|
||||
public Sector GetSector(int cylinder, int head, int sector)
|
||||
{
|
||||
return _tracks[head, cylinder].ReadSector(sector);
|
||||
}
|
||||
|
||||
public Track GetTrack(int cylinder, int head)
|
||||
{
|
||||
return _tracks[head, cylinder];
|
||||
}
|
||||
|
||||
private void LoadIMD(Stream s)
|
||||
{
|
||||
_imdHeader = ReadIMDHeader(s);
|
||||
|
||||
//
|
||||
// Read each track in and place it in memory.
|
||||
// We assume that there will be no more than 77 cylinders
|
||||
// and no more than 2 tracks. We also do a basic sanity
|
||||
// check that no track appears more than once.
|
||||
//
|
||||
while (true)
|
||||
{
|
||||
Track t = new Track(s);
|
||||
|
||||
if (t.Cylinder < 0 || t.Cylinder > 76)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format("Invalid cylinder value {0}", t.Cylinder));
|
||||
}
|
||||
|
||||
if (t.Head < 0 || t.Head > 1)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format("Invalid head value {0}", t.Head));
|
||||
}
|
||||
|
||||
if (_tracks[t.Head, t.Cylinder] != null)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format("Duplicate head/track", t.Head, t.Cylinder));
|
||||
}
|
||||
|
||||
if (t.Head != 0)
|
||||
{
|
||||
// Got a track on side 1, this must be a double-sided disk.
|
||||
_isSingleSided = false;
|
||||
}
|
||||
|
||||
_tracks[t.Head, t.Cylinder] = t;
|
||||
|
||||
if (s.Position == s.Length)
|
||||
{
|
||||
// End of file.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string ReadIMDHeader(Stream s)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (true)
|
||||
{
|
||||
byte b = (byte)s.ReadByte();
|
||||
|
||||
if (b == 0x1a)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append((char)b);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private string _imdHeader;
|
||||
private bool _isSingleSided;
|
||||
private string _imagePath;
|
||||
|
||||
private Track[,] _tracks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single track's worth of sectors
|
||||
/// </summary>
|
||||
public class Track
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new, empty track with the specified format, sector size and sector count.
|
||||
/// </summary>
|
||||
/// <param name="format"></param>
|
||||
/// <param name="cylinder"></param>
|
||||
/// <param name="head"></param>
|
||||
/// <param name="sectorCount"></param>
|
||||
/// <param name="sectorSize"></param>
|
||||
public Track(Format format, int cylinder, int head, int sectorCount, int sectorSize)
|
||||
{
|
||||
_format = format;
|
||||
_cylinder = cylinder;
|
||||
_head = head;
|
||||
_sectorCount = sectorCount;
|
||||
_sectorSize = sectorSize;
|
||||
_sectors = new Sector[_sectorCount];
|
||||
|
||||
for (int i = 0; i < _sectorCount; i++)
|
||||
{
|
||||
_sectors[i] = new Sector(_sectorSize, _format);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new track loaded from the given stream. The stream is expected to be positioned
|
||||
/// at the beginning of an IMD sector definition.
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
public Track(Stream s)
|
||||
{
|
||||
bool bCylMap = false;
|
||||
bool bHeadMap = false;
|
||||
|
||||
_format = (Format)s.ReadByte();
|
||||
_cylinder = s.ReadByte();
|
||||
_head = s.ReadByte();
|
||||
_sectorCount = s.ReadByte();
|
||||
int sectorSizeIndex = s.ReadByte();
|
||||
|
||||
// Basic sanity check of values
|
||||
if (_format > Format.MFM250 ||
|
||||
_cylinder > 77 ||
|
||||
(_head & 0x3f) > 1 ||
|
||||
sectorSizeIndex > _sectorSizes.Length - 1)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid header data for track.");
|
||||
}
|
||||
|
||||
_sectorSize = _sectorSizes[sectorSizeIndex];
|
||||
|
||||
bCylMap = (_head & 0x80) != 0;
|
||||
bHeadMap = (_head & 0x40) != 0;
|
||||
|
||||
// Head is just the first bit.
|
||||
_head = (byte)(_head & 0x1);
|
||||
|
||||
//
|
||||
// Read sector numbering
|
||||
//
|
||||
_sectorOrdering = new List<int>(_sectorCount);
|
||||
|
||||
for (int i = 0; i < _sectorCount; i++)
|
||||
{
|
||||
_sectorOrdering.Add(s.ReadByte());
|
||||
}
|
||||
|
||||
//
|
||||
// At this time, cyl and head maps are not supported.
|
||||
// It's not expected any Star disk would use such a format.
|
||||
//
|
||||
if (bCylMap | bHeadMap)
|
||||
{
|
||||
throw new NotImplementedException("IMD Cylinder and Head maps not supported.");
|
||||
}
|
||||
|
||||
//
|
||||
// Read the sector data in.
|
||||
//
|
||||
_sectors = new Sector[_sectorCount];
|
||||
for (int i = 0; i < _sectorCount; i++)
|
||||
{
|
||||
SectorRecordType type = (SectorRecordType)s.ReadByte();
|
||||
byte compressedData;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case SectorRecordType.Unavailable:
|
||||
// Nothing, sectors left null.
|
||||
break;
|
||||
|
||||
case SectorRecordType.Normal:
|
||||
case SectorRecordType.NormalDeleted:
|
||||
case SectorRecordType.NormalError:
|
||||
case SectorRecordType.DeletedError:
|
||||
_sectors[_sectorOrdering[i] - 1] = new Sector(_sectorSize, _format, s);
|
||||
break;
|
||||
|
||||
case SectorRecordType.Compressed:
|
||||
case SectorRecordType.CompressedDeleted:
|
||||
case SectorRecordType.CompressedError:
|
||||
case SectorRecordType.CompressedDeletedError:
|
||||
compressedData = (byte)s.ReadByte();
|
||||
|
||||
// Fill sector with compressed data
|
||||
_sectors[_sectorOrdering[i] - 1] = new Sector(_sectorSize, _format, compressedData);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException(String.Format("Unexpected IMD sector data type {0}", type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Cylinder
|
||||
{
|
||||
get { return _cylinder; }
|
||||
}
|
||||
|
||||
public int Head
|
||||
{
|
||||
get { return _head; }
|
||||
}
|
||||
|
||||
public int SectorCount
|
||||
{
|
||||
get { return _sectorCount; }
|
||||
}
|
||||
|
||||
public int SectorSize
|
||||
{
|
||||
get { return _sectorSize; }
|
||||
}
|
||||
|
||||
public Format Format
|
||||
{
|
||||
get { return _format; }
|
||||
}
|
||||
|
||||
public Sector ReadSector(int sector)
|
||||
{
|
||||
return _sectors[sector];
|
||||
}
|
||||
|
||||
//
|
||||
// 00 Sector data unavailable - could not be read
|
||||
// 01 .... Normal data: (Sector Size) bytes follow
|
||||
// 02 xx Compressed: All bytes in sector have same value(xx)
|
||||
// 03 .... Normal data with "Deleted-Data address mark"
|
||||
// 04 xx Compressed with "Deleted-Data address mark"
|
||||
// 05 .... Normal data read with data error
|
||||
// 06 xx Compressed read with data error
|
||||
// 07 .... Deleted data read with data error
|
||||
// 08 xx Compressed, Deleted read with data error
|
||||
//
|
||||
private enum SectorRecordType
|
||||
{
|
||||
Unavailable = 0,
|
||||
Normal = 1,
|
||||
Compressed = 2,
|
||||
NormalDeleted = 3,
|
||||
CompressedDeleted = 4,
|
||||
NormalError = 5,
|
||||
CompressedError = 6,
|
||||
DeletedError = 7,
|
||||
CompressedDeletedError = 8,
|
||||
}
|
||||
|
||||
private Format _format;
|
||||
private int _cylinder;
|
||||
private int _head;
|
||||
private int _sectorCount;
|
||||
private int _sectorSize;
|
||||
|
||||
private List<int> _sectorOrdering;
|
||||
|
||||
private Sector[] _sectors;
|
||||
|
||||
private static int[] _sectorSizes = { 128, 256, 512, 1024, 2048, 4096, 8192 };
|
||||
}
|
||||
|
||||
public class Sector
|
||||
{
|
||||
public Sector(int sectorSize, Format format)
|
||||
{
|
||||
_data = new byte[sectorSize];
|
||||
_format = format;
|
||||
}
|
||||
|
||||
public Sector(int sectorSize, Format format, byte compressedValue)
|
||||
: this(sectorSize, format)
|
||||
{
|
||||
for (int i = 0; i < _data.Length; i++)
|
||||
{
|
||||
_data[i] = compressedValue;
|
||||
}
|
||||
}
|
||||
|
||||
public Sector(int sectorSize, Format format, Stream s)
|
||||
: this(sectorSize, format)
|
||||
{
|
||||
int read = s.Read(_data, 0, sectorSize);
|
||||
|
||||
if (read != sectorSize)
|
||||
{
|
||||
throw new InvalidOperationException("Short read in sector data.");
|
||||
}
|
||||
}
|
||||
|
||||
public Format Format
|
||||
{
|
||||
get { return _format; }
|
||||
}
|
||||
|
||||
public byte[] Data
|
||||
{
|
||||
get { return _data; }
|
||||
}
|
||||
|
||||
private Format _format;
|
||||
|
||||
private byte[] _data;
|
||||
}
|
||||
|
||||
// 00 = 500 kbps FM \ Note: kbps indicates transfer rate,
|
||||
// 01 = 300 kbps FM > not the data rate, which is
|
||||
// 02 = 250 kbps FM / 1/2 for FM encoding.
|
||||
// 03 = 500 kbps MFM
|
||||
// 04 = 300 kbps MFM
|
||||
// 05 = 250 kbps MFM
|
||||
public enum Format
|
||||
{
|
||||
FM500 = 0,
|
||||
FM300 = 1,
|
||||
FM250 = 2,
|
||||
MFM500 = 3,
|
||||
MFM300 = 4,
|
||||
MFM250 = 5,
|
||||
}
|
||||
}
|
||||
183
D/IO/FloppyDrive.cs
Normal file
183
D/IO/FloppyDrive.cs
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
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 D.IO;
|
||||
using D.Logging;
|
||||
|
||||
namespace D
|
||||
{
|
||||
public class FloppyDrive
|
||||
{
|
||||
public FloppyDrive(DSystem system)
|
||||
{
|
||||
_system = system;
|
||||
//
|
||||
// Start the Index event rolling. This will run forever.
|
||||
//
|
||||
_system.Scheduler.Schedule(_indexInterval, IndexCallback);
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public FloppyDisk Disk
|
||||
{
|
||||
get { return _disk; }
|
||||
}
|
||||
|
||||
public int Track
|
||||
{
|
||||
get { return _track; }
|
||||
}
|
||||
|
||||
public bool IsLoaded
|
||||
{
|
||||
get { return _disk != null; }
|
||||
}
|
||||
|
||||
public bool IsWriteProtected
|
||||
{
|
||||
get { return _writeProtected; }
|
||||
}
|
||||
|
||||
public bool IsSingleSided
|
||||
{
|
||||
get { return _singleSided; }
|
||||
}
|
||||
|
||||
public bool Track0
|
||||
{
|
||||
get { return _track == 0; }
|
||||
}
|
||||
|
||||
public bool Index
|
||||
{
|
||||
get { return _index; }
|
||||
}
|
||||
|
||||
public bool DiskChange
|
||||
{
|
||||
get { return _diskChange; }
|
||||
}
|
||||
|
||||
public bool DriveSelect
|
||||
{
|
||||
get { return _driveSelect; }
|
||||
set
|
||||
{
|
||||
_driveSelect = value;
|
||||
|
||||
//
|
||||
// The Disk Change signal is reset when
|
||||
// Drive Select goes low.
|
||||
//
|
||||
if (!_driveSelect)
|
||||
{
|
||||
_diskChange = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_track = 0;
|
||||
_singleSided = false;
|
||||
_writeProtected = false;
|
||||
_diskChange = false;
|
||||
_index = false;
|
||||
_driveSelect = false;
|
||||
}
|
||||
|
||||
public void LoadDisk(FloppyDisk disk)
|
||||
{
|
||||
_disk = disk;
|
||||
_singleSided = _disk.IsSingleSided;
|
||||
_diskChange = true;
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPFloppy, "Floppy disk image loaded. Description is:\n{0}", disk.Description);
|
||||
|
||||
// TODO: update WP, SS bits, etc.
|
||||
}
|
||||
|
||||
public void UnloadDisk()
|
||||
{
|
||||
// TODO: Commit disk changes
|
||||
_disk = null;
|
||||
_diskChange = true;
|
||||
}
|
||||
|
||||
public void SeekTo(int track)
|
||||
{
|
||||
// Clip into range.
|
||||
_track = Math.Max(0, track);
|
||||
_track = Math.Min(76, _track);
|
||||
}
|
||||
|
||||
private void IndexCallback(ulong skewNsec, object context)
|
||||
{
|
||||
//
|
||||
// This always runs even when a disk isn't loaded or spinning.
|
||||
// It only actually modifies _index if a disk is loaded.
|
||||
// We need to generate index pulses anyway (even if they are
|
||||
// inaccurate and unused by us given that we're not emulating
|
||||
// the disk at that low of a level) this does the job.
|
||||
//
|
||||
if (DriveSelect && IsLoaded && !_index)
|
||||
{
|
||||
// Raise the index signal, hold for a short period.
|
||||
_index = true;
|
||||
_system.Scheduler.Schedule(_indexDuration, IndexCallback);
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPFloppy, "Disk rotation complete, raising INDEX signal for 10us.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reset the index signal, wait for a long period (for the disk to go round again).
|
||||
_index = false;
|
||||
_system.Scheduler.Schedule(_indexInterval, IndexCallback);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private DSystem _system;
|
||||
|
||||
private bool _singleSided;
|
||||
private bool _writeProtected;
|
||||
private int _track;
|
||||
private bool _diskChange;
|
||||
private bool _driveSelect;
|
||||
private FloppyDisk _disk;
|
||||
|
||||
// Index signal and timing
|
||||
private bool _index;
|
||||
private ulong _indexInterval = 200 * Conversion.MsecToNsec; // 1/5 second at 300rpm
|
||||
private ulong _indexDuration = 10 * Conversion.UsecToNsec; // 10uSec duration for index signal.
|
||||
}
|
||||
}
|
||||
477
D/IO/SA1000.cs
Normal file
477
D/IO/SA1000.cs
Normal file
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
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.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace D.IO
|
||||
{
|
||||
public enum DriveType
|
||||
{
|
||||
Invalid = 0,
|
||||
SA1004 = 1, // 10MB
|
||||
Q2040 = 2, // Quantum 40MB
|
||||
Q2080 = 3, // Quantum 80MB
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Geometry for an SA1000-style drive
|
||||
/// </summary>
|
||||
public struct Geometry
|
||||
{
|
||||
public Geometry(int cylinders, int heads)
|
||||
{
|
||||
Cylinders = cylinders;
|
||||
Heads = heads;
|
||||
}
|
||||
|
||||
public int Cylinders;
|
||||
public int Heads;
|
||||
|
||||
public static Geometry SA1004 = new Geometry(256, 4);
|
||||
public static Geometry Q2040 = new Geometry(512, 8);
|
||||
public static Geometry Q2080 = new Geometry(1172, 7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encapsulates the state, disk data and low-level behavior of Shugart SA1000-style drives.
|
||||
/// </summary>
|
||||
public class SA1000Drive
|
||||
{
|
||||
public SA1000Drive(DSystem system)
|
||||
{
|
||||
_type = DriveType.Invalid;
|
||||
NewDisk(_type, String.Empty);
|
||||
|
||||
_system = system;
|
||||
|
||||
// Queue up the event that rotates our virtual disk. This runs continuously.
|
||||
_system.Scheduler.Schedule(_diskWordDelay, DiskWordCallback);
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_cylinder = 0;
|
||||
_head = 0;
|
||||
_wordIndex = 0;
|
||||
_index = false;
|
||||
_seekComplete = true;
|
||||
_lastStep = false;
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_diskImagePath))
|
||||
{
|
||||
Save(_diskImagePath);
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(string path)
|
||||
{
|
||||
using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
//
|
||||
// Format is:
|
||||
// 1st Byte: Drive type (see DriveType enumeration)
|
||||
// Bytes 2-N: Tracks of data (5325 words each) for all cylinders on the disk
|
||||
// Each word in a track is encapsulated in a 24-bit integer:
|
||||
// Metadata (address mark, CRC indicators) in upper 8 bits, data in low 16 bits.
|
||||
//
|
||||
fs.WriteByte((byte)_type);
|
||||
|
||||
for (int cyl = 0; cyl < _geometry.Cylinders; cyl++)
|
||||
{
|
||||
for (int head = 0; head < _geometry.Heads; head++)
|
||||
{
|
||||
for (int word = 0; word < _wordsPerTrack; word++)
|
||||
{
|
||||
fs.Write(BitConverter.GetBytes(_tracks[cyl, head, word]), 0, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_diskImagePath = path;
|
||||
}
|
||||
}
|
||||
|
||||
public void Load(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
byte type = (byte)fs.ReadByte();
|
||||
if (type < (int)DriveType.SA1004 || type > (int)DriveType.Q2080)
|
||||
{
|
||||
throw new InvalidOperationException("Unsupported drive type.");
|
||||
}
|
||||
|
||||
_type = (DriveType)type;
|
||||
|
||||
NewDisk(_type, path);
|
||||
|
||||
byte[] buffer = new byte[4];
|
||||
for (int cyl = 0; cyl < _geometry.Cylinders; cyl++)
|
||||
{
|
||||
for (int head = 0; head < _geometry.Heads; head++)
|
||||
{
|
||||
for (int word = 0; word < _wordsPerTrack; word++)
|
||||
{
|
||||
int read = fs.Read(buffer, 0, 3);
|
||||
|
||||
if (read < 3)
|
||||
{
|
||||
throw new InvalidOperationException("Short read on disk image load.");
|
||||
}
|
||||
|
||||
_tracks[cyl, head, word] = BitConverter.ToUInt32(buffer, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
//
|
||||
// Hit an exception while loading, ensure that we don't
|
||||
// have a partial image loaded.
|
||||
//
|
||||
_type = DriveType.Invalid;
|
||||
NewDisk(_type, String.Empty);
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public void NewDisk(DriveType type, string path)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DriveType.Invalid:
|
||||
//
|
||||
// For Invalid (i.e. unloaded or unspecified disks)
|
||||
// we assume an SA1004 geometry, but will always
|
||||
// return Not Ready.
|
||||
//
|
||||
case DriveType.SA1004:
|
||||
_geometry = Geometry.SA1004;
|
||||
break;
|
||||
|
||||
case DriveType.Q2040:
|
||||
_geometry = Geometry.Q2040;
|
||||
break;
|
||||
|
||||
case DriveType.Q2080:
|
||||
_geometry = Geometry.Q2080;
|
||||
break;
|
||||
}
|
||||
|
||||
_tracks = new uint[_geometry.Cylinders, _geometry.Heads, _wordsPerTrack];
|
||||
_type = type;
|
||||
_diskImagePath = path;
|
||||
}
|
||||
|
||||
public string ImagePath
|
||||
{
|
||||
get { return _diskImagePath; }
|
||||
}
|
||||
|
||||
public DriveType Type
|
||||
{
|
||||
get { return _type; }
|
||||
}
|
||||
|
||||
public Geometry Geometry
|
||||
{
|
||||
get { return _geometry; }
|
||||
}
|
||||
|
||||
public int WordsPerTrack
|
||||
{
|
||||
get { return _wordsPerTrack; }
|
||||
}
|
||||
|
||||
public int Cylinder
|
||||
{
|
||||
get { return _cylinder; }
|
||||
}
|
||||
|
||||
public int Head
|
||||
{
|
||||
get { return _head; }
|
||||
}
|
||||
|
||||
public bool Track0
|
||||
{
|
||||
get { return _cylinder == 0; }
|
||||
}
|
||||
|
||||
public bool Index
|
||||
{
|
||||
get { return _index; }
|
||||
}
|
||||
|
||||
public bool IsReady
|
||||
{
|
||||
//
|
||||
// We're always spun up and ready as
|
||||
// long as a valid disk is loaded.
|
||||
//
|
||||
get { return _type != DriveType.Invalid; }
|
||||
}
|
||||
|
||||
public bool SeekComplete
|
||||
{
|
||||
get { return _seekComplete; }
|
||||
}
|
||||
|
||||
public int WordIndex
|
||||
{
|
||||
get { return _wordIndex; }
|
||||
}
|
||||
|
||||
public void SetHead(int head)
|
||||
{
|
||||
_head = head % _geometry.Heads;
|
||||
}
|
||||
|
||||
public void Step(bool directionIn, bool stepSignal)
|
||||
{
|
||||
if (stepSignal && !_lastStep)
|
||||
{
|
||||
if (_stepCount == 0)
|
||||
{
|
||||
_directionIn = directionIn;
|
||||
}
|
||||
|
||||
// We queue up the step operation
|
||||
_timeSinceLastStep = 0;
|
||||
_stepCount++;
|
||||
|
||||
_seekComplete = false;
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "Buffering step.");
|
||||
}
|
||||
|
||||
_lastStep = stepSignal;
|
||||
}
|
||||
|
||||
public uint ReadData()
|
||||
{
|
||||
return _currentWord;
|
||||
}
|
||||
|
||||
public void WriteData(ushort data)
|
||||
{
|
||||
_tracks[_cylinder, _head, _wordIndex] = data;
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "Wrote 0x{0:x4} to c/h/w {1}/{2}/{3}", data, _cylinder, _head, _wordIndex);
|
||||
}
|
||||
|
||||
public void WriteAddressMark(ushort data)
|
||||
{
|
||||
_tracks[_cylinder, _head, _wordIndex] = (uint)(data | 0x10000); // Set AM bit
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "Wrote Address Mark 0x{0:x4} to c/h/w {1}/{2}/{3}", data, _cylinder, _head, _wordIndex);
|
||||
}
|
||||
|
||||
public void WriteCRC(ushort data)
|
||||
{
|
||||
_tracks[_cylinder, _head, _wordIndex] = (uint)(data | 0x20000); // Set CRC bit
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "Wrote CRC 0x{0:x4} to c/h/w {1}/{2}/{3}", data, _cylinder, _head, _wordIndex);
|
||||
}
|
||||
|
||||
public uint DebugRead(int cylinder, int head, int word)
|
||||
{
|
||||
return _tracks[cylinder, head, word];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This gets called back every 4.32uS at which point we move a new word under the head of the disk,
|
||||
/// wake up the disk task as appropriate, and deal with buffered seeks if any are in progress.
|
||||
/// </summary>
|
||||
/// <param name="skewNsec"></param>
|
||||
/// <param name="context"></param>
|
||||
private void DiskWordCallback(ulong skewNsec, object context)
|
||||
{
|
||||
//
|
||||
// Rotate the disk one word. If a wakeup is requested then take care of that.
|
||||
//
|
||||
SpinDisk();
|
||||
|
||||
//
|
||||
// Let the controller know a new word is ready.
|
||||
//
|
||||
_system.ShugartController.SignalDiskWordReady();
|
||||
|
||||
//
|
||||
// Deal with buffered seeks: if more than 350uS has elapsed since the last step
|
||||
// pulse from the microcode, we will do the seek now.
|
||||
// Technically this logic belongs in the drive itself but since we already have this
|
||||
// convenient event running here we do it now.
|
||||
//
|
||||
_timeSinceLastStep += 370;
|
||||
|
||||
if (_timeSinceLastStep > 35000 && _stepCount > 0)
|
||||
{
|
||||
Seek(_stepCount, _directionIn);
|
||||
_stepCount = 0;
|
||||
}
|
||||
|
||||
// Queue this event up again.
|
||||
_system.Scheduler.Schedule(_diskWordDelay - skewNsec, DiskWordCallback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a "buffered seek" by the requested amount
|
||||
/// in the specified direction.
|
||||
/// </summary>
|
||||
/// <param name="count"></param>
|
||||
/// <param name="directionIn"></param>
|
||||
private void Seek(int count, bool directionIn)
|
||||
{
|
||||
_destinationCylinder = _cylinder + count * (directionIn ? 1 : -1);
|
||||
|
||||
// Clip into range
|
||||
_destinationCylinder = Math.Max(0, _destinationCylinder);
|
||||
_destinationCylinder = Math.Min(_geometry.Cylinders - 1, _destinationCylinder);
|
||||
|
||||
//
|
||||
// Schedule a seek for about 50ms in the future.
|
||||
// This is approximate, but we don't need exact timing here.
|
||||
//
|
||||
_system.Scheduler.Schedule(_seekDuration, SeekCompleteCallback);
|
||||
}
|
||||
|
||||
private void SeekCompleteCallback(ulong skewNsec, object context)
|
||||
{
|
||||
//
|
||||
// Move to the specified destination.
|
||||
//
|
||||
_cylinder = _destinationCylinder;
|
||||
_seekComplete = true;
|
||||
|
||||
_system.ShugartController.SignalSeekComplete();
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "Seek to {0} complete.", _cylinder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates the rotation of the disc under the drive's heads; each call
|
||||
/// puts a new word of data under the "head" (which is returned by ReadData). At the end
|
||||
/// of the track the Index signal is raised.
|
||||
/// </summary>
|
||||
/// <param name="skewNsec"></param>
|
||||
/// <param name="context"></param>
|
||||
private void SpinDisk()
|
||||
{
|
||||
_currentWord = _tracks[_cylinder, _head, _wordIndex];
|
||||
|
||||
_wordIndex++;
|
||||
|
||||
if (_wordIndex == _wordsPerTrack)
|
||||
{
|
||||
_wordIndex = 0;
|
||||
_index = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_index = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Per the SA1000 spec, each track has a capacity of 10.4kbytes -- roughly 5325 words.
|
||||
//
|
||||
// We store disk data words in 32-bit words; the low 16 bits are the data, the upper 16 bits being non-zero
|
||||
// indicates that the word is an Address Mark or a CRC word.
|
||||
//
|
||||
// The 10mb SA1004 has 256 tracks and 4 heads.
|
||||
private Geometry _geometry;
|
||||
private DriveType _type;
|
||||
private const int _wordsPerTrack = 5325;
|
||||
private uint[,,] _tracks;
|
||||
|
||||
private int _wordIndex;
|
||||
private uint _currentWord;
|
||||
|
||||
//
|
||||
// Disk addressing
|
||||
//
|
||||
private int _cylinder;
|
||||
private int _head;
|
||||
|
||||
//
|
||||
// Status bits
|
||||
private bool _index;
|
||||
|
||||
//
|
||||
// Seek timing and data
|
||||
//
|
||||
private ulong _seekDuration = (ulong)(25.0 * Conversion.MsecToNsec);
|
||||
private int _destinationCylinder;
|
||||
private bool _seekComplete;
|
||||
|
||||
//
|
||||
// Seek status
|
||||
//
|
||||
private bool _lastStep;
|
||||
private int _stepCount;
|
||||
private int _timeSinceLastStep;
|
||||
private bool _directionIn;
|
||||
|
||||
//
|
||||
// Disk word timing.
|
||||
//
|
||||
// Time for a single word to move under the heads: ~3.6uS.
|
||||
// (Disk spins at 3125rpm, meaning 0.0192 seconds/revolution. There are
|
||||
// 5325 words per track -- 0.0192 / 5325 = 3.60e-6 seconds, or 3.6uS.
|
||||
// To make this line up nicely with the Star microcode clock (just to make things
|
||||
// more deterministic) we make the delay 27 microinstruction cycles long --
|
||||
// 3699nS.
|
||||
private readonly ulong _diskWordDelay = 3699;
|
||||
|
||||
//
|
||||
// Image file data
|
||||
//
|
||||
private string _diskImagePath;
|
||||
|
||||
//
|
||||
// System
|
||||
//
|
||||
private DSystem _system;
|
||||
}
|
||||
|
||||
}
|
||||
848
D/IO/ShugartController.cs
Normal file
848
D/IO/ShugartController.cs
Normal file
@@ -0,0 +1,848 @@
|
||||
/*
|
||||
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.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace D.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements the hardware end of the Shugart disk controller, currently only supplying the logic
|
||||
/// for an SA1000-style drive.
|
||||
/// </summary>
|
||||
public class ShugartController
|
||||
{
|
||||
public ShugartController(DSystem system, SA1000Drive drive)
|
||||
{
|
||||
_system = system;
|
||||
_drive = drive;
|
||||
|
||||
_writePipeline = new Queue<ushort>();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_writeEnable = false;
|
||||
_wakeupControl = 0;
|
||||
_writeCRC = false;
|
||||
_transferEnable = false;
|
||||
_firmwareEnable = false;
|
||||
_directionIn = false;
|
||||
_step = false;
|
||||
_reduceIW = false;
|
||||
_faultClear = false;
|
||||
_driveSelect = false;
|
||||
_headSelect = 0;
|
||||
_wakeupRequest = ServiceRequest.NoWakeup0;
|
||||
|
||||
_verifyError = false;
|
||||
_crcError = false;
|
||||
_overrun = false;
|
||||
_writeFault = false;
|
||||
_sa1000 = true;
|
||||
_sectorFound = false;
|
||||
_indexFound = false;
|
||||
_readWordReady = false;
|
||||
|
||||
_writePipeline.Clear();
|
||||
|
||||
ResetTransfer();
|
||||
}
|
||||
|
||||
public void SetKCtl(ushort value)
|
||||
{
|
||||
_writeEnable = (value & 0x0001) != 0;
|
||||
_wakeupControl = (value & 0x0006) >> 1;
|
||||
_writeCRC = (value & 0x0008) != 0;
|
||||
_transferEnable = (value & 0x0010) != 0;
|
||||
_firmwareEnable = (value & 0x0020) != 0;
|
||||
_directionIn = (value & 0x0040) != 0;
|
||||
_step = (value & 0x0080) != 0;
|
||||
_reduceIW = (value & 0x0100) != 0;
|
||||
_faultClear = (value & 0x0200) != 0;
|
||||
_driveSelect = (value & 0x0400) != 0;
|
||||
_headSelect = (value & 0xf800) >> 11;
|
||||
|
||||
_wakeupRequest = (ServiceRequest)(_wakeupControl | (_transferEnable ? 0x4 : 0x0));
|
||||
|
||||
//
|
||||
// "The SA1000's WriteFault is cleared by de-selecting the drive for at least 500ns."
|
||||
// We're not that picky.
|
||||
//
|
||||
if (!_driveSelect)
|
||||
{
|
||||
_writeFault = false;
|
||||
}
|
||||
|
||||
//
|
||||
// Step the drive
|
||||
//
|
||||
_drive.Step(_directionIn, _step);
|
||||
|
||||
// Select the head
|
||||
//
|
||||
_drive.SetHead(_headSelect);
|
||||
|
||||
//
|
||||
// Handle wakeup requests that might be pending based on the control value.
|
||||
//
|
||||
bool wake = false;
|
||||
switch (_wakeupRequest)
|
||||
{
|
||||
case ServiceRequest.FirmwareEnable:
|
||||
wake = _firmwareEnable;
|
||||
break;
|
||||
|
||||
case ServiceRequest.SeekComplete:
|
||||
wake = SeekComplete();
|
||||
break;
|
||||
|
||||
case ServiceRequest.IndexFound:
|
||||
wake = _indexFound;
|
||||
break;
|
||||
|
||||
case ServiceRequest.SectorFound:
|
||||
wake = _sectorFound;
|
||||
break;
|
||||
|
||||
default:
|
||||
wake = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_transferEnable)
|
||||
{
|
||||
if (_writeEnable && _wakeupRequest == ServiceRequest.WriteWordNeeded)
|
||||
{
|
||||
_transfer = TransferType.Write;
|
||||
}
|
||||
else if (!_writeEnable && _wakeupRequest == ServiceRequest.WriteWordNeeded)
|
||||
{
|
||||
_transfer = TransferType.Verify;
|
||||
}
|
||||
else if (!_writeEnable && _transferEnable && _wakeupRequest == ServiceRequest.ReadWordReady)
|
||||
{
|
||||
_transfer = TransferType.Read;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Unexpected combination of service request and write enable flags");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Reset transfer state machine if _transferEnable is low.
|
||||
//
|
||||
ResetTransfer();
|
||||
}
|
||||
|
||||
if (wake)
|
||||
{
|
||||
_system.CP.WakeTask(TaskType.Disk);
|
||||
}
|
||||
else
|
||||
{
|
||||
_system.CP.SleepTask(TaskType.Disk);
|
||||
}
|
||||
|
||||
/*
|
||||
if (Log.Enabled) Log.Write(
|
||||
LogType.Verbose,
|
||||
LogComponent.ShugartControl,
|
||||
"KCtl<-0x{0:x4} : we {1} wc {2} wcrc {3} te {4} fe {5} di {6} st {7} ri {8} fc {9} ds {10} hs {11} wq {12}",
|
||||
value,
|
||||
_writeEnable,
|
||||
_wakeupControl,
|
||||
_writeCRC,
|
||||
_transferEnable,
|
||||
_firmwareEnable,
|
||||
_directionIn,
|
||||
_step,
|
||||
_reduceIW,
|
||||
_faultClear,
|
||||
_driveSelect,
|
||||
_headSelect,
|
||||
_wakeupRequest); */
|
||||
}
|
||||
|
||||
public void SetKCmd(ushort value)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.ShugartControl, "KCmd<-0x{0:x4} unimplemented.", value);
|
||||
}
|
||||
|
||||
public void ClrKFlags()
|
||||
{
|
||||
// This depends on the kind of service request currently set.
|
||||
// TODO: figure out exactly what this works out to...
|
||||
if (_wakeupRequest != ServiceRequest.FirmwareEnable && _wakeupRequest != ServiceRequest.SeekComplete)
|
||||
{
|
||||
_system.CP.SleepTask(TaskType.Disk);
|
||||
}
|
||||
|
||||
_verifyError = false;
|
||||
_crcError = false;
|
||||
_overrun = false;
|
||||
_indexFound = false;
|
||||
_sectorFound = false;
|
||||
|
||||
if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.ShugartControl, "ClrKFlags");
|
||||
}
|
||||
|
||||
public void KStrobe()
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogType.Warning, LogComponent.ShugartControl, "KStrobe unimplemented");
|
||||
}
|
||||
|
||||
public ushort ReadKStatus()
|
||||
{
|
||||
// if (Log.Enabled) Log.Write(LogType.Warning, LogComponent.ShugartControl, "<-KStatus read");
|
||||
|
||||
// "All status bits are inverted on the X bus because use of the comparable non-inverting drivers
|
||||
// was forbidden when the board was designed."
|
||||
ushort value = (ushort)~(
|
||||
(_verifyError ? 0x0001 : 0x0000) |
|
||||
(_crcError ? 0x0002 : 0x0000) |
|
||||
(_overrun ? 0x0004 : 0x0000) |
|
||||
(_writeFault ? 0x0008 : 0x0000) |
|
||||
(!_drive.IsReady ? 0x0010 : 0x0000) |
|
||||
(_sa1000 ? 0x0020 : 0x0000) |
|
||||
(!_sectorFound ? 0x0040 : 0x0000) |
|
||||
(_indexFound ? 0x0080 : 0x0000) |
|
||||
(_firmwareEnable ? 0x0100 : 0x0000) |
|
||||
(_drive.Track0 ? 0x0200 : 0x0000) |
|
||||
(SeekComplete() ? 0x0400 : 0x0000) |
|
||||
((~_headSelect & 0x1f) << 11)
|
||||
);
|
||||
|
||||
/*
|
||||
if (Log.Enabled) Log.Write(
|
||||
LogType.Verbose,
|
||||
LogComponent.ShugartControl,
|
||||
"0x{0:x4}<-KStatus",
|
||||
value); */
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public ushort ReadKTest()
|
||||
{
|
||||
//
|
||||
// This is only partially implemented, enough to indicate to the microcode what kind of drive is
|
||||
// attached.
|
||||
//
|
||||
// Drive type is exposed via KTest[9] (Sector').
|
||||
// For an SA1000 this is always 0.
|
||||
// For a Quantum Q2040, this is always 1.
|
||||
// For a Quantum Q2080, this is the inverse of the MSB of the head select (KCtl[0]).
|
||||
//
|
||||
|
||||
int value = 0;
|
||||
|
||||
switch (_drive.Type)
|
||||
{
|
||||
case DriveType.SA1004:
|
||||
value = 0;
|
||||
break;
|
||||
|
||||
case DriveType.Q2040:
|
||||
value = 0x40;
|
||||
break;
|
||||
|
||||
case DriveType.Q2080:
|
||||
value = ((~_headSelect) & 0x10) == 0 ? 0x40 : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return (ushort)value;
|
||||
}
|
||||
|
||||
public void SetKOData(ushort value)
|
||||
{
|
||||
if (_writePipeline.Count > 1)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogType.Error,
|
||||
LogComponent.ShugartControl,
|
||||
"KOData<- : Not ready for write! (c/h/s/f {0}/{1}/{2}/{3})",
|
||||
_drive.Cylinder,
|
||||
_drive.Head,
|
||||
_debugSector,
|
||||
_debugField);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_writePipeline.Enqueue(value);
|
||||
if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "KOData<- : 0x{0:x4} latched", value);
|
||||
}
|
||||
|
||||
if (_wakeupRequest == ServiceRequest.WriteWordNeeded)
|
||||
{
|
||||
_system.CP.SleepTask(TaskType.Disk);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ushort ReadKIData()
|
||||
{
|
||||
if (!_readWordReady)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogType.Error,
|
||||
LogComponent.ShugartControl,
|
||||
"<-KIData : Not ready for read! (c/h/s/f {0}/{1}/{2}/{3})",
|
||||
_drive.Cylinder,
|
||||
_drive.Head,
|
||||
_debugSector,
|
||||
_debugField);
|
||||
_overrun = true;
|
||||
}
|
||||
|
||||
//
|
||||
// Put the microcode back to sleep now that we've read the next word.
|
||||
//
|
||||
if (_wakeupRequest == ServiceRequest.ReadWordReady)
|
||||
{
|
||||
_system.CP.SleepTask(TaskType.Disk);
|
||||
}
|
||||
|
||||
_readWordReady = false;
|
||||
|
||||
// if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "<-KIData Read 0x{0:x4} from c/h/w {1}/{2}/{3} (sector {4} field {5})", _readData, _drive.Cylinder, _drive.Head, _drive.WordIndex, _debugSector, _debugField);
|
||||
|
||||
return (ushort)_readData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the drive to let the controller know that a new word is ready to be read or written.
|
||||
/// </summary>
|
||||
public void SignalDiskWordReady()
|
||||
{
|
||||
if (_drive.Index)
|
||||
{
|
||||
_indexFound = true;
|
||||
|
||||
// Wake up if we're waiting for the Index
|
||||
if (_wakeupRequest == ServiceRequest.IndexFound)
|
||||
{
|
||||
_system.CP.WakeTask(TaskType.Disk);
|
||||
}
|
||||
|
||||
//
|
||||
// Reset debug counters
|
||||
//
|
||||
_debugSector = -1;
|
||||
_debugField = -1;
|
||||
}
|
||||
|
||||
// Check for overrun on reads
|
||||
//
|
||||
if (_readWordReady &&
|
||||
_transferEnable &&
|
||||
_transfer == TransferType.Read &&
|
||||
_readState == ReadState.Data)
|
||||
{
|
||||
// No data available from microcode.
|
||||
if (Log.Enabled) Log.Write(LogType.Error, LogComponent.ShugartControl, "Read data: overrun.");
|
||||
_overrun = true;
|
||||
}
|
||||
|
||||
_readWordReady = true;
|
||||
_readData = _drive.ReadData();
|
||||
|
||||
//
|
||||
// Check for Header Address Mark and set SectorFound bit if present.
|
||||
if (_readData == _headerAddressMark)
|
||||
{
|
||||
_sectorFound = true;
|
||||
|
||||
if (_debugSector != -1 && _debugField != 2)
|
||||
{
|
||||
//Console.WriteLine("Only found {0} fields on the last sector.", _debugField);
|
||||
}
|
||||
|
||||
_debugSector++; // next sector
|
||||
_debugField = 0; // header field
|
||||
}
|
||||
|
||||
if (_readData == _labelDataAddressMark)
|
||||
{
|
||||
_debugField++; // next field
|
||||
}
|
||||
|
||||
//
|
||||
// Run the transfer state machine
|
||||
//
|
||||
if (_transferEnable)
|
||||
{
|
||||
bool wake = false;
|
||||
switch (_transfer)
|
||||
{
|
||||
case TransferType.Write:
|
||||
switch (_writeState)
|
||||
{
|
||||
case WriteState.AutoPreamble:
|
||||
// One word of preamble is written by the hardware itself.
|
||||
_drive.WriteData(0);
|
||||
|
||||
_transferCount++;
|
||||
if (_transferCount > 1)
|
||||
{
|
||||
_transferCount = 0;
|
||||
_writeState = WriteState.Preamble;
|
||||
|
||||
// Wake the microcode task for the first preamble word
|
||||
wake = _wakeupRequest == ServiceRequest.WriteWordNeeded;
|
||||
if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "Preamble word needed.");
|
||||
}
|
||||
break;
|
||||
|
||||
case WriteState.Preamble:
|
||||
// Four words of preamble are to be written by the microcode.
|
||||
if (_writePipeline.Count > 0)
|
||||
{
|
||||
_drive.WriteData(_writePipeline.Dequeue());
|
||||
}
|
||||
else
|
||||
{
|
||||
// No data available from microcode.
|
||||
if (Log.Enabled) Log.Write(LogType.Error, LogComponent.ShugartControl, "Write preamble: overrun.");
|
||||
_overrun = true;
|
||||
}
|
||||
|
||||
// Wake the microcode task
|
||||
wake = _wakeupRequest == ServiceRequest.WriteWordNeeded;
|
||||
|
||||
_transferCount++;
|
||||
if (_transferCount > 4)
|
||||
{
|
||||
_transferCount = 0;
|
||||
_writeState = WriteState.AddressMark;
|
||||
if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "AM word needed.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "Preamble word needed.");
|
||||
}
|
||||
break;
|
||||
|
||||
case WriteState.AddressMark:
|
||||
//
|
||||
// One word of address mark, written by the microcode.
|
||||
//
|
||||
ushort amWord = 0;
|
||||
|
||||
if (_writePipeline.Count > 0)
|
||||
{
|
||||
amWord = _writePipeline.Dequeue();
|
||||
}
|
||||
else
|
||||
{
|
||||
// No data available from microcode.
|
||||
if (Log.Enabled) Log.Write(LogType.Error, LogComponent.ShugartControl, "Write am data: overrun.");
|
||||
_overrun = true;
|
||||
}
|
||||
|
||||
_drive.WriteAddressMark(amWord);
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "KOData<- : Address mark is 0x{0:x4}", amWord);
|
||||
|
||||
wake = _wakeupRequest == ServiceRequest.WriteWordNeeded;
|
||||
_writeState = WriteState.Data;
|
||||
break;
|
||||
|
||||
case WriteState.Data:
|
||||
//
|
||||
// N words of data, written by the microcode. This state is left only when KCtl<- is set to enable
|
||||
// writing the CRC.
|
||||
//
|
||||
if (_writeCRC)
|
||||
{
|
||||
wake = _wakeupRequest == ServiceRequest.WriteWordNeeded;
|
||||
_writeState = WriteState.CRC;
|
||||
_transferCount = 0;
|
||||
|
||||
// Write the first word of the CRC.
|
||||
_drive.WriteCRC(0xbeef);
|
||||
}
|
||||
else
|
||||
{
|
||||
wake = _wakeupRequest == ServiceRequest.WriteWordNeeded;
|
||||
|
||||
_transferCount++;
|
||||
|
||||
if (_writePipeline.Count > 0)
|
||||
{
|
||||
_drive.WriteData(_writePipeline.Dequeue());
|
||||
}
|
||||
else
|
||||
{
|
||||
// No data available from microcode.
|
||||
if (Log.Enabled) Log.Write(LogType.Error, LogComponent.ShugartControl, "Write data: overrun.");
|
||||
_overrun = true;
|
||||
}
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "Data word needed.");
|
||||
}
|
||||
break;
|
||||
|
||||
case WriteState.CRC:
|
||||
//
|
||||
// One word of CRC, written by the hardware. This takes three word times, but
|
||||
// only one word is written.
|
||||
// We don't actually calculate the CRC (it cannot be read by microcode and
|
||||
// we aren't simulating corrupted disks), but we write a known
|
||||
// value for basic sanity checking on reads.
|
||||
//
|
||||
|
||||
//
|
||||
// The actual CRC was written when we made the state transition.
|
||||
// We write these other marker words to clobber anything that might
|
||||
// be underneath them.
|
||||
//
|
||||
_drive.WriteCRC(0xdead);
|
||||
|
||||
_transferCount++;
|
||||
|
||||
// We still keep the microcode alive -- it may write words; we will ignore them.
|
||||
wake = _wakeupRequest == ServiceRequest.WriteWordNeeded;
|
||||
|
||||
if (_transferCount > 1)
|
||||
{
|
||||
_writeState = WriteState.Complete;
|
||||
}
|
||||
break;
|
||||
|
||||
case WriteState.Complete:
|
||||
// Nothing.
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case TransferType.Verify:
|
||||
switch (_verifyState)
|
||||
{
|
||||
case VerifyState.WaitForAddressMark:
|
||||
// Check the current data under the read heads, if it's an address mark,
|
||||
// wake the Disk task up and move to the Data state.
|
||||
if (_readData == _headerAddressMark ||
|
||||
_readData == _labelDataAddressMark)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "Address Mark 0x{0:x4} found at word 0x{1:x4}, waking microcode.",
|
||||
_readData,
|
||||
_drive.WordIndex);
|
||||
wake = true;
|
||||
_verifyState = VerifyState.Data;
|
||||
|
||||
//
|
||||
// Set the CRC error flag:
|
||||
// This is presumed true until all words of the field
|
||||
// are read and can be compared with the CRC word at the
|
||||
// end.
|
||||
//
|
||||
_crcError = true;
|
||||
|
||||
if (_writePipeline.Count == 0)
|
||||
{
|
||||
//
|
||||
// Hack: boot microcode does not "prime" the write pipeline --
|
||||
// relying on the hardware behavior of clearing the writeData buffer
|
||||
// automatically; if the microcode hasn't written a word by this point
|
||||
// enqueue a zero.
|
||||
//
|
||||
_writePipeline.Enqueue(0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case VerifyState.Data:
|
||||
//
|
||||
// If this is a CRC, we check for our canard value and move to the CRC state,
|
||||
// otherwise compare data.
|
||||
//
|
||||
ushort writeData = 0;
|
||||
if (_writePipeline.Count > 0)
|
||||
{
|
||||
writeData = _writePipeline.Dequeue();
|
||||
}
|
||||
|
||||
if ((_readData & 0x20000) != 0)
|
||||
{
|
||||
if (_readData != _fakeCRCValue)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogType.Error, LogComponent.ShugartControl, "Verify CRC: 0x{0:x4} != 0x{1:x4}", _fakeCRCValue, _readData);
|
||||
_crcError = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// All good.
|
||||
//
|
||||
_crcError = false;
|
||||
}
|
||||
|
||||
_verifyState = VerifyState.CRC;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (writeData != _readData)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "Verify data: 0x{0:x4} != 0x{1:x4}", writeData, _readData);
|
||||
_verifyError = true;
|
||||
}
|
||||
}
|
||||
wake = true;
|
||||
break;
|
||||
|
||||
case VerifyState.CRC:
|
||||
//
|
||||
// We sit here forever. Microcode may send two extra words which we will ignore,
|
||||
// after which it will disable the controller.
|
||||
//
|
||||
if (_writePipeline.Count > 0)
|
||||
{
|
||||
_writePipeline.Dequeue();
|
||||
}
|
||||
wake = true;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TransferType.Read:
|
||||
switch (_readState)
|
||||
{
|
||||
case ReadState.WaitForAddressMark:
|
||||
// Check the current data under the read heads, if it's an address mark,
|
||||
// wake the Disk task up and move to the Data state.
|
||||
if (_readData == _headerAddressMark ||
|
||||
_readData == _labelDataAddressMark)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.ShugartControl, "Address Mark 0x{0:x4} found at word 0x{1:x4}, waking microcode.",
|
||||
_drive.ReadData(),
|
||||
_drive.WordIndex);
|
||||
wake = true;
|
||||
_readState = ReadState.Data;
|
||||
}
|
||||
break;
|
||||
|
||||
case ReadState.Data:
|
||||
//
|
||||
// If this is a CRC, we check for our canard value and move to the CRC state,
|
||||
// otherwise the microcode will read the next word via <-KIData
|
||||
//
|
||||
if ((_readData & 0x20000) != 0)
|
||||
{
|
||||
if (_readData != _fakeCRCValue)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogType.Error, LogComponent.ShugartControl, "Read CRC: 0x{0:x4} != 0x{1:x4}", _fakeCRCValue, _readData);
|
||||
_crcError = true;
|
||||
}
|
||||
|
||||
_readState = ReadState.CRC;
|
||||
|
||||
}
|
||||
wake = true;
|
||||
break;
|
||||
|
||||
case ReadState.CRC:
|
||||
//
|
||||
// We sit here forever. Microcode may send two extra words which we will ignore,
|
||||
// after which it will disable the controller.
|
||||
//
|
||||
if (_writePipeline.Count > 0)
|
||||
{
|
||||
_writePipeline.Dequeue();
|
||||
}
|
||||
wake = true;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Wake up the disk task if we need the microcode to read or write a word.
|
||||
//
|
||||
if (wake)
|
||||
{
|
||||
_system.CP.WakeTask(TaskType.Disk);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void SignalSeekComplete()
|
||||
{
|
||||
if (_wakeupRequest == ServiceRequest.SeekComplete && SeekComplete())
|
||||
{
|
||||
_system.CP.WakeTask(TaskType.Disk);
|
||||
}
|
||||
}
|
||||
|
||||
private bool SeekComplete()
|
||||
{
|
||||
//
|
||||
// "[SeekComplete] is set when the drive is ready, it is selected, and the heads are not in motion."
|
||||
//
|
||||
return (_drive.IsReady && _driveSelect && _drive.SeekComplete);
|
||||
}
|
||||
|
||||
private void ResetTransfer()
|
||||
{
|
||||
_transfer = TransferType.None;
|
||||
_writeState = WriteState.AutoPreamble;
|
||||
_verifyState = VerifyState.WaitForAddressMark;
|
||||
_readState = ReadState.WaitForAddressMark;
|
||||
_transferCount = 0;
|
||||
_writePipeline.Clear();
|
||||
}
|
||||
|
||||
private DSystem _system;
|
||||
|
||||
//
|
||||
// The drive the controller is connected to.
|
||||
//
|
||||
private SA1000Drive _drive;
|
||||
|
||||
//
|
||||
// KCtl bits
|
||||
//
|
||||
private bool _writeEnable;
|
||||
private int _wakeupControl;
|
||||
private bool _writeCRC;
|
||||
private bool _transferEnable;
|
||||
private bool _firmwareEnable;
|
||||
private bool _directionIn;
|
||||
private bool _step;
|
||||
private bool _reduceIW;
|
||||
private bool _faultClear;
|
||||
private bool _driveSelect;
|
||||
private int _headSelect;
|
||||
|
||||
private ServiceRequest _wakeupRequest;
|
||||
|
||||
//
|
||||
// KStatus bits
|
||||
//
|
||||
private bool _verifyError;
|
||||
private bool _crcError;
|
||||
private bool _overrun;
|
||||
private bool _writeFault;
|
||||
private bool _sa1000;
|
||||
private bool _sectorFound;
|
||||
private bool _indexFound;
|
||||
|
||||
|
||||
//
|
||||
// Read/Write state machine
|
||||
//
|
||||
private int _transferCount;
|
||||
private uint _readData;
|
||||
private bool _readWordReady;
|
||||
|
||||
//
|
||||
// Write pipeline (word being actively written to disk, word loaded by KOData<-.
|
||||
// Kind of overkill to use a Queue object here.
|
||||
//
|
||||
private Queue<ushort> _writePipeline = new Queue<ushort>();
|
||||
|
||||
private WriteState _writeState;
|
||||
private VerifyState _verifyState;
|
||||
private ReadState _readState;
|
||||
private TransferType _transfer;
|
||||
|
||||
//
|
||||
// Address marks
|
||||
//
|
||||
private const int _headerAddressMark = 0x1a141;
|
||||
private const int _labelDataAddressMark = 0x1a143;
|
||||
|
||||
//
|
||||
// CRC (not actually CRC) value
|
||||
//
|
||||
private const int _fakeCRCValue = 0x2beef;
|
||||
|
||||
//
|
||||
// Debug metadata. Keep track of sector and field information.
|
||||
//
|
||||
private int _debugSector;
|
||||
private int _debugField;
|
||||
|
||||
private enum TransferType
|
||||
{
|
||||
None,
|
||||
Read,
|
||||
Write,
|
||||
Verify
|
||||
}
|
||||
|
||||
private enum ServiceRequest
|
||||
{
|
||||
FirmwareEnable = 0,
|
||||
SeekComplete = 1,
|
||||
IndexFound = 2, // NB: HWRef has IndexFound and SectorFound values reversed.
|
||||
SectorFound = 3,
|
||||
ReadWordReady = 4,
|
||||
WriteWordNeeded = 5,
|
||||
NoWakeup0 = 6,
|
||||
NoWakeup1 = 7,
|
||||
}
|
||||
|
||||
private enum WriteState
|
||||
{
|
||||
Invalid = 0,
|
||||
AutoPreamble, // 2 words of zeros written by the hardware
|
||||
Preamble, // 4 words of zeros written by the microcode
|
||||
AddressMark, // 1 word of address mark written by the microcode
|
||||
Data, // 256 words actual sector data written by the microcode
|
||||
CRC, // 1 word of CRC, written by the hardware
|
||||
Complete, // write done
|
||||
}
|
||||
|
||||
private enum VerifyState
|
||||
{
|
||||
Invalid = 0,
|
||||
WaitForAddressMark, // Waiting for the next Address Mark to come around
|
||||
Data, // Data is being read and compared with data from the microcode, by the hardware
|
||||
CRC, // CRC is being checked by the hardware
|
||||
}
|
||||
|
||||
private enum ReadState
|
||||
{
|
||||
Invalid = 0,
|
||||
WaitForAddressMark, // Waiting for the next Address Mark to come around
|
||||
Data, // Data is being read
|
||||
CRC, // CRC is being checked by the hardware
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
452
D/IOP/DMAController.cs
Normal file
452
D/IOP/DMAController.cs
Normal file
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
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.Logging;
|
||||
using System;
|
||||
|
||||
namespace D.IOP
|
||||
{
|
||||
public class DMAChannel
|
||||
{
|
||||
public DMAChannel()
|
||||
{
|
||||
Reset();
|
||||
Device = null;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Enabled = false;
|
||||
Completed = false;
|
||||
ChAddr = 0;
|
||||
ChCount = -1;
|
||||
Type = DMAType.Invalid;
|
||||
}
|
||||
|
||||
public bool Enabled;
|
||||
|
||||
public bool Completed;
|
||||
|
||||
// Channel address
|
||||
public ushort ChAddr;
|
||||
|
||||
// Channel data count
|
||||
public int ChCount;
|
||||
|
||||
// Channel DMA type
|
||||
public DMAType Type;
|
||||
|
||||
// DMA device
|
||||
public IDMAInterface Device;
|
||||
}
|
||||
|
||||
public enum DMAType
|
||||
{
|
||||
Verify = 0,
|
||||
Write = 1,
|
||||
Read = 2,
|
||||
Invalid = 3,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines an interface for DMA exchanges between devices and the DMA controller.
|
||||
/// </summary>
|
||||
public interface IDMAInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// DMA Request: device request to obtain a DMA cycle from the DMA controller
|
||||
/// </summary>
|
||||
bool DRQ { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Writes a single byte to the device from the DMA controller
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
void DMAWrite(byte value);
|
||||
|
||||
/// <summary>
|
||||
/// Reads a single byte from the device to the DMA controller
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
byte DMARead();
|
||||
|
||||
/// <summary>
|
||||
/// Indicates to a DMA device that a DMA transfer has completed.
|
||||
/// </summary>
|
||||
void DMAComplete();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This implements the general behavior of the Intel 8257 as used in the Star.
|
||||
/// It is far from a generic 8257 simulation, it could be made more general-purpose...
|
||||
/// </summary>
|
||||
public class DMAController : IIOPDevice
|
||||
{
|
||||
public DMAController(IOProcessor iop)
|
||||
{
|
||||
_iop = iop;
|
||||
|
||||
for (int i = 0; i < _channels.Length; i++)
|
||||
{
|
||||
_channels[i] = new DMAChannel();
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterDevice(IDMAInterface device, int channel)
|
||||
{
|
||||
_channels[channel].Device = device;
|
||||
}
|
||||
|
||||
public DMAChannel GetChannel(int i)
|
||||
{
|
||||
return _channels[i];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hold request. Goes high when the DMA controller is taking control of the
|
||||
/// bus (so the CPU should take a nap.)
|
||||
/// </summary>
|
||||
public bool HRQ
|
||||
{
|
||||
get { return _hrq; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Terminal Count: TC is activated when the 14-bit value in the [last] selected channel's
|
||||
/// terminal count register equals zero.
|
||||
/// </summary>
|
||||
public bool TC
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_lastSelectedChannel != -1)
|
||||
{
|
||||
return _channels[_lastSelectedChannel].ChCount == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int[] ReadPorts
|
||||
{
|
||||
get { return _readPorts; }
|
||||
}
|
||||
|
||||
public int[] WritePorts
|
||||
{
|
||||
get { return _writePorts; }
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_first = true;
|
||||
|
||||
_rotatingPriority = false;
|
||||
_extendedWrite = false;
|
||||
_tcStop = false;
|
||||
_autoLoad = false;
|
||||
|
||||
_lastSelectedChannel = 0;
|
||||
_nextToService = 0;
|
||||
|
||||
for (int i = 0; i < _channels.Length; i++)
|
||||
{
|
||||
_channels[i].Reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes a single DMA transfer (if there are
|
||||
/// any transfers pending). This takes 4 clock
|
||||
/// cycles.
|
||||
/// </summary>
|
||||
public void Execute()
|
||||
{
|
||||
//
|
||||
// See if there's anything to do.
|
||||
//
|
||||
int nextChannel = SelectNextChannel();
|
||||
|
||||
//
|
||||
// Raise HRQ if so.
|
||||
//
|
||||
_hrq = nextChannel != -1;
|
||||
|
||||
if (_hrq)
|
||||
{
|
||||
DMAChannel c = _channels[nextChannel];
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPDMA, "Channel {0} selected. {1} bytes to {2}, addr 0x{3:x4}.",
|
||||
nextChannel, c.ChCount, c.Type, c.ChAddr);
|
||||
|
||||
switch (c.Type)
|
||||
{
|
||||
case DMAType.Verify:
|
||||
throw new NotImplementedException("DMA Verify not implemented.");
|
||||
|
||||
case DMAType.Read:
|
||||
// Read byte from memory and transfer to device
|
||||
byte dmaWrite = _iop.Memory.ReadByte(c.ChAddr);
|
||||
c.Device.DMAWrite(dmaWrite);
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPDMA, "DMA read transfer of byte 0x{0:x2} from address 0x{1:x4}", dmaWrite, c.ChAddr);
|
||||
break;
|
||||
|
||||
case DMAType.Write:
|
||||
// Read byte from device and transfer to memory.
|
||||
byte dmaRead = c.Device.DMARead();
|
||||
_iop.Memory.WriteByte(c.ChAddr, dmaRead);
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPDMA, "DMA write transfer of byte 0x{0:x2} to address 0x{1:x4}", dmaRead, c.ChAddr);
|
||||
break;
|
||||
}
|
||||
|
||||
// Increment address, decrement counter.
|
||||
c.ChAddr++;
|
||||
c.ChCount--;
|
||||
|
||||
// If the counter runs out, stop the channel if so enabled.
|
||||
if (c.ChCount == 0)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPDMA, "Channel {0} completed.", nextChannel);
|
||||
// Stop this crazy thing.
|
||||
if (_tcStop)
|
||||
{
|
||||
c.Enabled = false;
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPDMA, "Channel {0} disabled.", nextChannel);
|
||||
}
|
||||
|
||||
c.Completed = true;
|
||||
c.Device.DMAComplete();
|
||||
}
|
||||
|
||||
_lastSelectedChannel = nextChannel;
|
||||
}
|
||||
}
|
||||
|
||||
public void WritePort(int port, byte value)
|
||||
{
|
||||
switch ((DMAPorts)port)
|
||||
{
|
||||
case DMAPorts.DmaMode:
|
||||
_first = true;
|
||||
|
||||
_channels[0].Enabled = (value & 0x01) != 0;
|
||||
_channels[1].Enabled = (value & 0x02) != 0;
|
||||
_channels[2].Enabled = (value & 0x04) != 0;
|
||||
_channels[3].Enabled = (value & 0x08) != 0;
|
||||
|
||||
_rotatingPriority = (value & 0x10) != 0;
|
||||
_extendedWrite = (value & 0x20) != 0;
|
||||
_tcStop = (value & 0x40) != 0;
|
||||
_autoLoad = (value & 0x80) != 0;
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPDMA, "DMAMode: en: {0},{1},{2},{3} rp {4} ew {5} tc {6} al {7}",
|
||||
_channels[0].Enabled, _channels[1].Enabled, _channels[2].Enabled, _channels[3].Enabled,
|
||||
_rotatingPriority, _extendedWrite, _tcStop, _autoLoad);
|
||||
|
||||
if (_autoLoad)
|
||||
{
|
||||
throw new NotImplementedException("AutoLoad not yet implemented.");
|
||||
}
|
||||
break;
|
||||
|
||||
case DMAPorts.DmaCh0Addr:
|
||||
case DMAPorts.DmaCh1Addr:
|
||||
case DMAPorts.DmaCh2Addr:
|
||||
case DMAPorts.DmaCh3Addr:
|
||||
{
|
||||
int ch = (port - 0xa0) / 2;
|
||||
if (_first)
|
||||
{
|
||||
_channels[ch].ChAddr = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_channels[ch].ChAddr = (ushort)(_channels[ch].ChAddr | (value << 8));
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPDMA, "Channel {0} address set to 0x{1:x4}", ch, _channels[ch].ChAddr);
|
||||
}
|
||||
_first = !_first;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMAPorts.DmaCh0Count:
|
||||
case DMAPorts.DmaCh1Count:
|
||||
case DMAPorts.DmaCh2Count:
|
||||
case DMAPorts.DmaCh3Count:
|
||||
{
|
||||
int ch = (port - 0xa1) / 2;
|
||||
if (_first)
|
||||
{
|
||||
_channels[ch].ChCount = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// + 1 because the value loaded is the number of bytes-1.
|
||||
_channels[ch].ChCount = (ushort)(_channels[ch].ChCount | ((value & 0x3f) << 8)) + 1;
|
||||
_channels[ch].Type = (DMAType)(value >> 6);
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPDMA, "Channel {0} count set to 0x{1:x4}", ch, _channels[ch].ChCount);
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPDMA, "Channel {0} type set to {1}", ch, _channels[ch].Type);
|
||||
}
|
||||
_first = !_first;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException(String.Format("Unexpected write to port {0:x2}", port));
|
||||
}
|
||||
}
|
||||
|
||||
public byte ReadPort(int port)
|
||||
{
|
||||
byte value = 0;
|
||||
|
||||
switch ((DMAPorts)port)
|
||||
{
|
||||
case DMAPorts.DmaStatus:
|
||||
// "The low 4 bits of this register indicate what channels have completed."
|
||||
value = (byte)((_channels[0].Completed ? 0x01 : 0x00) |
|
||||
(_channels[1].Completed ? 0x02 : 0x00) |
|
||||
(_channels[2].Completed ? 0x04 : 0x00) |
|
||||
(_channels[3].Completed ? 0x08 : 0x00));
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPDMA, "DMAStatus read {0}", value);
|
||||
|
||||
// TC Status bits are cleared after the status register is read.
|
||||
_channels[0].Completed = false;
|
||||
_channels[1].Completed = false;
|
||||
_channels[2].Completed = false;
|
||||
_channels[3].Completed = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException(String.Format("Unexpected read from port {0:x2}", port));
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
private int SelectNextChannel()
|
||||
{
|
||||
int nextChannel = -1;
|
||||
|
||||
if (!_rotatingPriority)
|
||||
{
|
||||
//
|
||||
// Select the highest priority channel that has something to do.
|
||||
// Channel 0 has the highest priority.
|
||||
//
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (_channels[i].Enabled && _channels[i].Device != null &&_channels[i].Device.DRQ)
|
||||
{
|
||||
nextChannel = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Select the next channel in the cycle, if it has something to do.
|
||||
//
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int j = (i + _nextToService) % 4;
|
||||
if (_channels[j].Enabled && _channels[j].Device != null && _channels[j].Device.DRQ)
|
||||
{
|
||||
nextChannel = j;
|
||||
_nextToService = j + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nextChannel;
|
||||
}
|
||||
|
||||
private readonly int[] _readPorts = new int[]
|
||||
{
|
||||
(int)DMAPorts.DmaStatus,
|
||||
};
|
||||
|
||||
private readonly int[] _writePorts = new int[]
|
||||
{
|
||||
(int)DMAPorts.DmaCh0Addr,
|
||||
(int)DMAPorts.DmaCh0Count,
|
||||
(int)DMAPorts.DmaCh1Addr,
|
||||
(int)DMAPorts.DmaCh1Count,
|
||||
(int)DMAPorts.DmaCh2Addr,
|
||||
(int)DMAPorts.DmaCh2Count,
|
||||
(int)DMAPorts.DmaCh3Addr,
|
||||
(int)DMAPorts.DmaCh3Count,
|
||||
(int)DMAPorts.DmaMode,
|
||||
};
|
||||
|
||||
// Which address byte to store when loading registers.
|
||||
private bool _first;
|
||||
|
||||
private DMAChannel[] _channels = new DMAChannel[4];
|
||||
|
||||
// DMA Mode Flags
|
||||
private bool _rotatingPriority;
|
||||
private bool _extendedWrite;
|
||||
private bool _tcStop;
|
||||
private bool _autoLoad;
|
||||
|
||||
// Scheduling
|
||||
private int _nextToService;
|
||||
private int _lastSelectedChannel;
|
||||
|
||||
private IOProcessor _iop;
|
||||
|
||||
private enum DMAPorts
|
||||
{
|
||||
DmaCh0Addr = 0xa0,
|
||||
DmaCh0Count = 0xa1,
|
||||
DmaCh1Addr = 0xa2,
|
||||
DmaCh1Count = 0xa3,
|
||||
DmaCh2Addr = 0xa4,
|
||||
DmaCh2Count = 0xa5,
|
||||
DmaCh3Addr = 0xa6,
|
||||
DmaCh3Count = 0xa7,
|
||||
DmaMode = 0xa8, // Write
|
||||
DmaStatus = 0xa8, // Read
|
||||
}
|
||||
|
||||
private bool _hrq;
|
||||
}
|
||||
}
|
||||
1039
D/IOP/FloppyController.cs
Normal file
1039
D/IOP/FloppyController.cs
Normal file
File diff suppressed because it is too large
Load Diff
37
D/IOP/I8085IOBus.cs
Normal file
37
D/IOP/I8085IOBus.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
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.IOP
|
||||
{
|
||||
public interface I8085IOBus
|
||||
{
|
||||
void Out(byte port, byte o);
|
||||
|
||||
byte In(byte port);
|
||||
}
|
||||
}
|
||||
42
D/IOP/I8085MemoryBus.cs
Normal file
42
D/IOP/I8085MemoryBus.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
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.IOP
|
||||
{
|
||||
public interface I8085MemoryBus
|
||||
{
|
||||
byte ReadByte(ushort address);
|
||||
|
||||
void WriteByte(ushort address, byte b);
|
||||
|
||||
ushort ReadWord(ushort address);
|
||||
|
||||
void WriteWord(ushort address, ushort w);
|
||||
}
|
||||
}
|
||||
41
D/IOP/IIOPDevice.cs
Normal file
41
D/IOP/IIOPDevice.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
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.IOP
|
||||
{
|
||||
public interface IIOPDevice
|
||||
{
|
||||
int[] ReadPorts { get; }
|
||||
int[] WritePorts { get; }
|
||||
|
||||
void WritePort(int port, byte value);
|
||||
|
||||
byte ReadPort(int port);
|
||||
}
|
||||
}
|
||||
95
D/IOP/IOPIOBus.cs
Normal file
95
D/IOP/IOPIOBus.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
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.Logging;
|
||||
using System;
|
||||
|
||||
namespace D.IOP
|
||||
{
|
||||
public class IOPIOBus : I8085IOBus
|
||||
{
|
||||
public IOPIOBus()
|
||||
{
|
||||
_writeDispatch = new IIOPDevice[256];
|
||||
_readDispatch = new IIOPDevice[256];
|
||||
}
|
||||
|
||||
public void RegisterDevice(IIOPDevice device)
|
||||
{
|
||||
foreach(byte port in device.ReadPorts)
|
||||
{
|
||||
if (_readDispatch[port] != null)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format("Read port collision {0:x2} when adding device {1}", port, device));
|
||||
}
|
||||
|
||||
_readDispatch[port] = device;
|
||||
}
|
||||
|
||||
foreach (byte port in device.WritePorts)
|
||||
{
|
||||
if (_writeDispatch[port] != null)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format("Write port collision {0:x2} when adding device {1}", port, device));
|
||||
}
|
||||
|
||||
_writeDispatch[port] = device;
|
||||
}
|
||||
}
|
||||
|
||||
public void Out(byte port, byte val)
|
||||
{
|
||||
if (_writeDispatch[port] != null)
|
||||
{
|
||||
_writeDispatch[port].WritePort(port, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPIO, "Unhandled write to IO port ${0:x2}, ${1:x2}", port, val);
|
||||
}
|
||||
}
|
||||
|
||||
public byte In(byte port)
|
||||
{
|
||||
if (_readDispatch[port] != null)
|
||||
{
|
||||
return _readDispatch[port].ReadPort(port);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPIO, "Unhandled read from IO port ${0:x2}", port);
|
||||
return 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private IIOPDevice[] _writeDispatch;
|
||||
private IIOPDevice[] _readDispatch;
|
||||
}
|
||||
}
|
||||
224
D/IOP/IOPMemoryBus.cs
Normal file
224
D/IOP/IOPMemoryBus.cs
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
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.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace D.IOP
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements the IOP's memory bus. Memory map looks like
|
||||
/// (see SysDefs.asm):
|
||||
///
|
||||
/// $0000 - $1FFF : PROM (8K)
|
||||
/// $2000 - $5FFF : RAM (16K)
|
||||
/// $80B0 - $80BF : Host Addr PROM (16 bytes)
|
||||
///
|
||||
/// </summary>
|
||||
public class IOPMemoryBus : I8085MemoryBus
|
||||
{
|
||||
public IOPMemoryBus(I8085IOBus ioBus)
|
||||
{
|
||||
// 8K ROM
|
||||
_rom = new byte[0x2000];
|
||||
|
||||
// 16K RAM. We actually allocate 24K
|
||||
// to make addressing simpler.
|
||||
_ram = new byte[0x6000];
|
||||
|
||||
// The 8085's IO ports are also memory-mapped at
|
||||
// $8000 + port.
|
||||
_io = ioBus;
|
||||
|
||||
LoadPROMs();
|
||||
|
||||
LoadHostIDProm();
|
||||
}
|
||||
|
||||
public byte ReadByte(ushort address)
|
||||
{
|
||||
if (address < 0x2000)
|
||||
{
|
||||
return _rom[address];
|
||||
}
|
||||
else if(address < 0x6000)
|
||||
{
|
||||
return _ram[address];
|
||||
}
|
||||
else if(address > 0x80af && address < 0x80c0)
|
||||
{
|
||||
//
|
||||
// Host Address PROM. This contains 12 nybbles of data containing the 48-bit
|
||||
// Ethernet host address and a checksum.
|
||||
// The PROM itself is 16 bytes in size.
|
||||
//
|
||||
return _hostIdProm[address - 0x80b0];
|
||||
}
|
||||
else if(address > 0x8000 && address < 0x8100)
|
||||
{
|
||||
// Memory-mapped I/O ports
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPMemory, "Memory-mapped I/O read from {0:x4}", address);
|
||||
return _io.In((byte)address);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing mapped here.
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPMemory, "Read from nonexistent memory at {0:x4}", address);
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteByte(ushort address, byte b)
|
||||
{
|
||||
if (address < 0x2000)
|
||||
{
|
||||
// ROM, not writeable.
|
||||
}
|
||||
else if (address < 0x6000)
|
||||
{
|
||||
_ram[address] = b;
|
||||
}
|
||||
else if (address > 0x8000 && address < 0x8100)
|
||||
{
|
||||
// Memory-mapped I/O ports
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPMemory, "Memory-mapped I/O write at {0:x4}", address);
|
||||
_io.Out((byte)address, b);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing mapped here.
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPMemory, "Write to nonexistent memory at {0:x4}", address);
|
||||
}
|
||||
}
|
||||
|
||||
public ushort ReadWord(ushort address)
|
||||
{
|
||||
return (ushort)(ReadByte(address) | (ReadByte((ushort)(address + 1)) << 8));
|
||||
}
|
||||
|
||||
public void WriteWord(ushort address, ushort u)
|
||||
{
|
||||
WriteByte(address++, (byte)u);
|
||||
WriteByte(address, (byte)(u >> 8));
|
||||
}
|
||||
|
||||
public void UpdateHostIDProm()
|
||||
{
|
||||
LoadHostIDProm();
|
||||
}
|
||||
|
||||
private void LoadPROMs()
|
||||
{
|
||||
// Loads PROMs into ROM space. The files for rev 3.1 are:
|
||||
// U129 - 537P03029 - $0000
|
||||
// U130 - 537P03030 - $0800
|
||||
// U131 - 537P03700 - $1000
|
||||
// U132 - 537P03032 - $1800
|
||||
|
||||
LoadPROM("537P03029.bin", 0x0000);
|
||||
LoadPROM("537P03030.bin", 0x0800);
|
||||
LoadPROM("537P03700.bin", 0x1000);
|
||||
LoadPROM("537P03032.bin", 0x1800);
|
||||
}
|
||||
|
||||
private void LoadPROM(string promName, ushort address)
|
||||
{
|
||||
string promPath = Path.Combine("IOP", "PROM", promName);
|
||||
|
||||
using (FileStream promStream = new FileStream(promPath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
if (promStream.Length != 0x800)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
String.Format("PROM file {0} has unexpected size 0x{1:x}", promName, promStream.Length));
|
||||
}
|
||||
|
||||
promStream.Read(_rom, address, 0x800);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadHostIDProm()
|
||||
{
|
||||
//
|
||||
// Copy data from the current emulator config into the HostID prom array.
|
||||
//
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
byte val = (byte)(Configuration.HostID >> (5 - i) * 8);
|
||||
SetIDPromByte(i, val);
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the checksum of the PROM. Looking at the PROM as
|
||||
// 8 bytes (big-endian) rather than 16 nibbles, this is a cyclic XOR of:
|
||||
// Bytes 0 & 1 - XOR'd together
|
||||
// Bytes 2-5
|
||||
// Checksum is stored in Byte 6, complemented checksum is in Byte 7.
|
||||
// Byte 8 appears to be unused.
|
||||
//
|
||||
byte checksum = RotateLeft((byte)(GetIDPromByte(0) ^ GetIDPromByte(1)));
|
||||
|
||||
for (int i = 2; i < 6; i++)
|
||||
{
|
||||
checksum ^= GetIDPromByte(i);
|
||||
checksum = RotateLeft(checksum);
|
||||
}
|
||||
|
||||
SetIDPromByte(6, checksum);
|
||||
SetIDPromByte(7, (byte)(~checksum));
|
||||
}
|
||||
|
||||
private byte GetIDPromByte(int byteNumber)
|
||||
{
|
||||
return (byte)((_hostIdProm[byteNumber * 2] & 0xf) | (_hostIdProm[byteNumber * 2 + 1] << 4));
|
||||
}
|
||||
|
||||
private void SetIDPromByte(int byteNumber, byte value)
|
||||
{
|
||||
_hostIdProm[byteNumber * 2] = (byte)(value & 0xf);
|
||||
_hostIdProm[byteNumber * 2 + 1] = (byte)(value >> 4);
|
||||
}
|
||||
|
||||
private byte RotateLeft(byte value)
|
||||
{
|
||||
return (byte)((value << 1) | ((value & 0x80) != 0 ? 1 : 0));
|
||||
}
|
||||
|
||||
private byte[] _rom;
|
||||
private byte[] _ram;
|
||||
|
||||
//
|
||||
// Host ID Prom: contains the host's Ethernet MAC + checksum.
|
||||
// 16 nybbles long.
|
||||
private byte[] _hostIdProm = new byte[16];
|
||||
|
||||
private I8085IOBus _io;
|
||||
}
|
||||
}
|
||||
165
D/IOP/IOProcessor.cs
Normal file
165
D/IOP/IOProcessor.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
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.IOP
|
||||
{
|
||||
/// <summary>
|
||||
/// Encapsulates the entirety of the IOP hardware.
|
||||
/// </summary>
|
||||
public class IOProcessor
|
||||
{
|
||||
public IOProcessor(DSystem system)
|
||||
{
|
||||
_system = system;
|
||||
_io = new IOPIOBus();
|
||||
_mem = new IOPMemoryBus(_io);
|
||||
_cpu = new i8085(_mem, _io);
|
||||
_keyboard = new Keyboard();
|
||||
_mouse = new Mouse();
|
||||
|
||||
//
|
||||
// 8" floppy drive used by the IOP
|
||||
//
|
||||
_floppyDrive = new FloppyDrive(_system);
|
||||
|
||||
//
|
||||
// Add devices to the IO bus
|
||||
//
|
||||
_miscIO = new MiscIO(this);
|
||||
_floppyController = new FloppyController(_floppyDrive, _system);
|
||||
_dma = new DMAController(this);
|
||||
_tty = new Printer();
|
||||
|
||||
//
|
||||
// Register DMA devices with controller
|
||||
//
|
||||
_dma.RegisterDevice(_floppyController, 0); // Floppy, DMA Channel 0
|
||||
_dma.RegisterDevice(_system.CP, 1); // CP, DMA Channel 1
|
||||
|
||||
_io.RegisterDevice(_miscIO);
|
||||
_io.RegisterDevice(_floppyController);
|
||||
_io.RegisterDevice(_dma);
|
||||
_io.RegisterDevice(_system.CP);
|
||||
//_io.RegisterDevice(_tty);
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_cpu.Reset();
|
||||
_miscIO.Reset();
|
||||
_dma.Reset();
|
||||
_floppyController.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes a single 8085 instruction or runs the DMA controller if DMA is in progress,
|
||||
/// and returns the number of 3Mhz clock cycles consumed.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int Execute()
|
||||
{
|
||||
//
|
||||
// Run the DMA controller, see if it has anything to do this cycle.
|
||||
//
|
||||
_dma.Execute();
|
||||
|
||||
if (_dma.HRQ)
|
||||
{
|
||||
// Yes, it executed a DMA transfer which means the CPU doesn't get to run.
|
||||
return 4; // A DMA cycle takes 4 clocks.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Run the CPU for one instruction.
|
||||
return _cpu.Execute();
|
||||
}
|
||||
}
|
||||
|
||||
public i8085 CPU
|
||||
{
|
||||
get { return _cpu; }
|
||||
}
|
||||
|
||||
public I8085MemoryBus Memory
|
||||
{
|
||||
get { return _mem; }
|
||||
}
|
||||
|
||||
public MiscIO MiscIO
|
||||
{
|
||||
get { return _miscIO; }
|
||||
}
|
||||
|
||||
public FloppyController FloppyController
|
||||
{
|
||||
get { return _floppyController; }
|
||||
}
|
||||
|
||||
public DMAController DMAController
|
||||
{
|
||||
get { return _dma; }
|
||||
}
|
||||
|
||||
public Keyboard Keyboard
|
||||
{
|
||||
get { return _keyboard; }
|
||||
}
|
||||
|
||||
public Mouse Mouse
|
||||
{
|
||||
get { return _mouse; }
|
||||
}
|
||||
|
||||
public Printer Printer
|
||||
{
|
||||
get { return _tty; }
|
||||
}
|
||||
|
||||
private i8085 _cpu;
|
||||
private IOPIOBus _io;
|
||||
private I8085MemoryBus _mem;
|
||||
|
||||
//
|
||||
// Devices on the IOP
|
||||
//
|
||||
private MiscIO _miscIO;
|
||||
private FloppyController _floppyController;
|
||||
private DMAController _dma;
|
||||
private Keyboard _keyboard;
|
||||
private Mouse _mouse;
|
||||
private Printer _tty;
|
||||
private DSystem _system;
|
||||
|
||||
//
|
||||
// Devices used by the IOP
|
||||
//
|
||||
private FloppyDrive _floppyDrive;
|
||||
}
|
||||
}
|
||||
237
D/IOP/Keyboard.cs
Normal file
237
D/IOP/Keyboard.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
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.Logging;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace D.IOP
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the scancodes understood by the IOP.
|
||||
/// The below is currently derived from work undertaken by Al Kossow
|
||||
/// (many thanks.)
|
||||
/// This table corresponds to the standard US keyboard layout for the
|
||||
/// Star/1108. TODO: How to deal with international arrangements?
|
||||
/// </summary>
|
||||
public enum KeyCode
|
||||
{
|
||||
Invalid = 0x00,
|
||||
|
||||
D1 = 0x10,
|
||||
T10 = 0x11,
|
||||
Defaults = 0x12, // T9
|
||||
LargerSmaller = 0x13, // T8
|
||||
Subscript = 0x14, // T7
|
||||
Undo = 0x15, // R6
|
||||
Superscript = 0x16, // T6
|
||||
Properties = 0x17, // L12 (Also Ctrl)
|
||||
Move = 0x18, // L9
|
||||
Copy = 0x19, // L6
|
||||
Underline = 0x1a, // T5
|
||||
Italics = 0x1b, // T4
|
||||
Bold = 0x1c, // T3
|
||||
Center = 0x1d, // T2
|
||||
T1 = 0x1e,
|
||||
|
||||
R4 = 0x20,
|
||||
SkipNext = 0x22, // R1
|
||||
Help = 0x23, // R2
|
||||
Margins = 0x24, // R5
|
||||
R3 = 0x25,
|
||||
L10 = 0x27,
|
||||
Same = 0x28, // L7
|
||||
L4 = 0x29,
|
||||
L1 = 0x2a,
|
||||
A9 = 0x2d,
|
||||
|
||||
DefnExpand = 0x30, // R7 (Also Esc)
|
||||
R10 = 0x31,
|
||||
Keyboard = 0x32, // R11 (^X)
|
||||
Font = 0x33, // R8 (\,|)
|
||||
R9 = 0x34,
|
||||
Stop = 0x35, // R12
|
||||
Space = 0x36,
|
||||
Open = 0x37, // L11 (Also Meta)
|
||||
L8 = 0x38,
|
||||
Find = 0x39, // L5
|
||||
Again = 0x3a, // L2
|
||||
Delete = 0x3b, // L3
|
||||
A8 = 0x3c,
|
||||
A11 = 0x3d,
|
||||
|
||||
A12 = 0x41, // Shift ?
|
||||
RightShift = 0x42, // A6
|
||||
FSlash = 0x43,
|
||||
Period = 0x44,
|
||||
Comma = 0x45,
|
||||
M = 0x46,
|
||||
N = 0x47,
|
||||
B = 0x48,
|
||||
V = 0x49,
|
||||
C = 0x4a,
|
||||
X = 0x4b,
|
||||
Z = 0x4c,
|
||||
K47 = 0x4e,
|
||||
|
||||
Return = 0x50, // A4
|
||||
BackQuote = 0x51, // K46
|
||||
Quote = 0x52, // K43
|
||||
Colon = 0x53,
|
||||
L = 0x54,
|
||||
K = 0x55,
|
||||
J = 0x56,
|
||||
H = 0x57,
|
||||
G = 0x58,
|
||||
F = 0x59,
|
||||
D = 0x5a,
|
||||
S = 0x5b,
|
||||
A = 0x5c,
|
||||
Lock = 0x5e, // A3
|
||||
LeftShift = 0x5f, // A5
|
||||
|
||||
A10 = 0x60,
|
||||
RBracket = 0x61, // K45
|
||||
LBracket = 0x62, // K42
|
||||
P = 0x63,
|
||||
O = 0x64,
|
||||
I = 0x65,
|
||||
U = 0x66,
|
||||
Y = 0x67,
|
||||
T = 0x68,
|
||||
R = 0x69,
|
||||
E = 0x6a,
|
||||
W = 0x6b,
|
||||
Q = 0x6c,
|
||||
Tab = 0x6d, // A1
|
||||
D2 = 0x6f,
|
||||
|
||||
Backspace = 0x70, // A2
|
||||
Equals = 0x71,
|
||||
Minus = 0x72,
|
||||
N0 = 0x73,
|
||||
N9 = 0x74,
|
||||
N8 = 0x75,
|
||||
N7 = 0x76,
|
||||
N6 = 0x77,
|
||||
N5 = 0x78,
|
||||
N4 = 0x79,
|
||||
N3 = 0x7a,
|
||||
N2 = 0x7b,
|
||||
N1 = 0x7c,
|
||||
FArrow = 0x7d, // K48
|
||||
|
||||
}
|
||||
|
||||
public class Keyboard
|
||||
{
|
||||
public Keyboard()
|
||||
{
|
||||
_keyboardQueue = new Queue<KeyCode>();
|
||||
|
||||
_lock = new ReaderWriterLockSlim();
|
||||
}
|
||||
|
||||
public byte ReadData()
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPKeyboard, "Key data {0} (0x{1:x2}) read.", _keyData, (int)_keyData);
|
||||
return (byte)_keyData;
|
||||
}
|
||||
|
||||
public void NextData()
|
||||
{
|
||||
_lock.EnterUpgradeableReadLock();
|
||||
if (_keyboardQueue.Count > 0)
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
_keyData = _keyboardQueue.Dequeue();
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPKeyboard, "Key data {0} (0x{1:x2}) dequeued.", _keyData, (int)_keyData);
|
||||
_lock.ExitWriteLock();
|
||||
}
|
||||
else
|
||||
{
|
||||
// No data available.
|
||||
_keyData = KeyCode.Invalid;
|
||||
}
|
||||
_lock.ExitUpgradeableReadLock();
|
||||
}
|
||||
|
||||
public bool DataReady()
|
||||
{
|
||||
_lock.EnterReadLock();
|
||||
bool ready = _keyboardQueue.Count > 0;
|
||||
_lock.ExitReadLock();
|
||||
return ready;
|
||||
}
|
||||
|
||||
public void EnableDiagnosticMode()
|
||||
{
|
||||
//
|
||||
// Per MoonIOPCSTest.asm:
|
||||
// "Return sequence of events should be all characters held down followed by D2, D1."
|
||||
// Right now, just enqueue d2, d1
|
||||
|
||||
_lock.EnterWriteLock();
|
||||
|
||||
_keyboardQueue.Enqueue(KeyCode.D2);
|
||||
_keyboardQueue.Enqueue(KeyCode.D1);
|
||||
|
||||
_lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
public void DisableDiagnosticMode()
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
_keyboardQueue.Clear();
|
||||
_lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
public void KeyDown(KeyCode keycode)
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
// Bit 0 = 0 indicates the key being pressed
|
||||
_keyboardQueue.Enqueue((KeyCode)((int)keycode & 0x7f));
|
||||
_lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
public void KeyUp(KeyCode keycode)
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
// Bit 0 = 1 indicates the key being released
|
||||
_keyboardQueue.Enqueue((KeyCode)((int)keycode | 0x80));
|
||||
_lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
private KeyCode _keyData;
|
||||
private Queue<KeyCode> _keyboardQueue;
|
||||
|
||||
private ReaderWriterLockSlim _lock;
|
||||
|
||||
}
|
||||
}
|
||||
453
D/IOP/MiscIO.cs
Normal file
453
D/IOP/MiscIO.cs
Normal file
@@ -0,0 +1,453 @@
|
||||
/*
|
||||
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.Logging;
|
||||
using System;
|
||||
|
||||
namespace D.IOP
|
||||
{
|
||||
public enum AltBootValues
|
||||
{
|
||||
None = -1,
|
||||
DiagnosticRigid = 0,
|
||||
Rigid,
|
||||
Floppy,
|
||||
Ethernet,
|
||||
DiagnosticEthernet,
|
||||
DiagnosticFloppy,
|
||||
AlternateEthernet,
|
||||
DiagnosticTrident1,
|
||||
DiagnosticTrident2,
|
||||
DiagnosticTrident3,
|
||||
HeadCleaning
|
||||
}
|
||||
|
||||
public class MiscIO : IIOPDevice
|
||||
{
|
||||
public MiscIO(IOProcessor iop)
|
||||
{
|
||||
//
|
||||
// Keep a reference to the IOP we belong to
|
||||
// so we can poll the interrupt status of various
|
||||
// devices.
|
||||
//
|
||||
_iop = iop;
|
||||
|
||||
_todClock = new TODClock();
|
||||
|
||||
// Default to no alt boot
|
||||
_altBoot = AltBootValues.None;
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public int[] ReadPorts
|
||||
{
|
||||
get { return _readPorts; }
|
||||
}
|
||||
|
||||
public int[] WritePorts
|
||||
{
|
||||
get { return _writePorts; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows UI to be alerted when the MP value changes.
|
||||
/// </summary>
|
||||
public delegate void MPChangedEventHandler();
|
||||
|
||||
public MPChangedEventHandler MPChanged;
|
||||
|
||||
|
||||
public AltBootValues AltBoot
|
||||
{
|
||||
get
|
||||
{
|
||||
return _altBoot;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_altBoot = value;
|
||||
_altBootCounter = (int)value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_mPanelValue = 0;
|
||||
_mPanelBlank = true;
|
||||
|
||||
_lastClockFlags = 0;
|
||||
_dmaTestValue = 0;
|
||||
|
||||
_altBootCounter = (int)_altBoot;
|
||||
|
||||
_todClock.Reset();
|
||||
}
|
||||
|
||||
public void WritePort(int port, byte value)
|
||||
{
|
||||
switch (port)
|
||||
{
|
||||
case 0xd0:
|
||||
//
|
||||
// DMA Test Register
|
||||
// At this point, it appears all this does is store the value written,
|
||||
// and return it when read.
|
||||
//
|
||||
_dmaTestValue = value;
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPMisc, "Misc IO port DMATest write {0:x2}", value);
|
||||
break;
|
||||
|
||||
case 0xe9: // KB, MP, TOD clocks
|
||||
DoMiscClock(value);
|
||||
break;
|
||||
|
||||
case 0xea: // Clear TOD interrupt
|
||||
_todClock.ClearInterrupt();
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPMisc, "Misc IO TOD interrupt clear.");
|
||||
break;
|
||||
|
||||
case 0xed: // Clear Mouse X,Y counters
|
||||
_iop.Mouse.Clear();
|
||||
break;
|
||||
|
||||
case 0xef: // KB, MP, TOD control
|
||||
//
|
||||
// Control bits:
|
||||
// 0x40 - pReadKBData - read KB data
|
||||
// 0x20 - KBTone - KB speaker bit
|
||||
// 0x10 - KBDiag - Set KB Diag mode
|
||||
// 0x08 - BlankMPanel - Blank MPanel bit
|
||||
// 0x04 - ReadTimeMode - Read TOD mode bit
|
||||
// 0x02 - ClearTimeMode - Clear TOD mode bit
|
||||
// 0x01 - SetTimeMode - Set TOD mode bit
|
||||
//
|
||||
_mPanelBlank = (value & 0x08) != 0;
|
||||
MPChanged();
|
||||
|
||||
if ((value & 0x40) != 0)
|
||||
{
|
||||
// Prime the next byte of keyboard data.
|
||||
_iop.Keyboard.NextData();
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPMisc, "Misc IO Keyboard data clock.");
|
||||
}
|
||||
|
||||
if ((value & 0x10) != 0)
|
||||
{
|
||||
_iop.Keyboard.EnableDiagnosticMode();
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPMisc, "Misc IO Keyboard diagnostic mode entered.");
|
||||
}
|
||||
|
||||
if ((value & 0x04) != 0)
|
||||
{
|
||||
_todClock.SetMode(TODAccessMode.Read);
|
||||
}
|
||||
|
||||
if ((value & 0x02) != 0)
|
||||
{
|
||||
_todClock.SetMode(TODAccessMode.Clear);
|
||||
}
|
||||
|
||||
if ((value & 0x01) != 0)
|
||||
{
|
||||
_todClock.SetMode(TODAccessMode.Set);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException(String.Format("Unexpected write to port {0:x2}", port));
|
||||
}
|
||||
}
|
||||
|
||||
public byte ReadPort(int port)
|
||||
{
|
||||
byte value;
|
||||
switch(port)
|
||||
{
|
||||
case 0xd0:
|
||||
//
|
||||
// DMA Test Register:
|
||||
// Just return whatever value was written.
|
||||
//
|
||||
value = _dmaTestValue;
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPMisc, "Misc IO port DMATest read {0:x2}", value);
|
||||
break;
|
||||
|
||||
case 0xef:
|
||||
//
|
||||
// MiscInput1: AltBoot,TimeData,PowerFailed,TODInt,CSParError,MouseSw1,Sw2,Sw3
|
||||
//
|
||||
// Provide the AltBoot switch so we can allow floppy booting:
|
||||
// The way the boot prom selects a boot device is to:
|
||||
// 1) check for the AltBoot bit (meaning the alternate boot switch is held down)
|
||||
// 2) if so, increment MP, wait 1 second.
|
||||
// 3) repeat 1 + 2 until AltBoot is no longer set.
|
||||
// 4) the final value is the device to be booted from.
|
||||
//
|
||||
// We decrement our boot device counter on every read until we hit zero at which point
|
||||
// we "release" the button.
|
||||
//
|
||||
if (_altBootCounter > 0)
|
||||
{
|
||||
value = (int)MiscInput1Flags.AltBoot;
|
||||
_altBootCounter--;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// OR in other bits
|
||||
//
|
||||
value = (byte)(value |
|
||||
_todClock.ReadClockBit() |
|
||||
(_todClock.PowerLoss ? 0x20 : 0x0) |
|
||||
(_todClock.Interrupt ? 0x10 : 0x0) |
|
||||
(int)(_iop.Mouse.Buttons) |
|
||||
(int)MiscInput1Flags.CSParity /* active low, we don't want parity errors */);
|
||||
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPMisc, "Misc IO port MiscInput1 read {0:x2}", value);
|
||||
break;
|
||||
|
||||
case 0xe9:
|
||||
//
|
||||
// Interrupt status register.
|
||||
// Most of these aren't real interrupts (they don't trigger an 8085 interrupt) but are simply
|
||||
// status flags raised by various bits of hardware that get polled by the main IOP code loop.
|
||||
// This register is not a latch, it merely buffers these signals which are generated by their
|
||||
// respective devices.
|
||||
// We combine those bits here from their various sources. All of these signals are active low.
|
||||
//
|
||||
// Add more as more things get implemented...
|
||||
//
|
||||
value = (byte)~(
|
||||
(_iop.FloppyController.Interrupt ? 0x80 : 0x00) |
|
||||
(_iop.Keyboard.DataReady() ? 0x40 : 0x00));
|
||||
/* TODO: disabled until it can be completed
|
||||
(_iop.Printer.TxRequest ? 0x20 : 0x00) |
|
||||
(_iop.Printer.RxRequest ? 0x10 : 0x00)); */
|
||||
|
||||
// if (Log.Enabled) Log.Write(LogComponent.IOPMisc, "Misc IO port Interrupt Status read {0:x2}", value);
|
||||
break;
|
||||
|
||||
case 0xea:
|
||||
//
|
||||
// Keyboard data latch. Data is inverted, and bit 0 (msb) indicates keystroke up or down (1 = down).
|
||||
//
|
||||
value = (byte)(~_iop.Keyboard.ReadData());
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPMisc, "Misc IO port Keyboard Data read {0:x2}", value);
|
||||
break;
|
||||
|
||||
case 0xed:
|
||||
//
|
||||
// Mouse X counter
|
||||
//
|
||||
value = (byte)_iop.Mouse.MouseX;
|
||||
break;
|
||||
|
||||
case 0xee:
|
||||
//
|
||||
// Mouse Y counter
|
||||
//
|
||||
value = (byte)_iop.Mouse.MouseY;
|
||||
break;
|
||||
|
||||
default:
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The value of the MP display (displayed in red LEDs on the front of the Star)
|
||||
/// </summary>
|
||||
public int MPanelValue
|
||||
{
|
||||
get { return _mPanelValue; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the MP display is currently turned on
|
||||
/// </summary>
|
||||
public bool MPanelBlank
|
||||
{
|
||||
get { return _mPanelBlank; }
|
||||
}
|
||||
|
||||
public TODClock TODClock
|
||||
{
|
||||
get { return _todClock; }
|
||||
}
|
||||
|
||||
private void DoMiscClock(byte clockFlags)
|
||||
{
|
||||
//
|
||||
// From code in BootSubs.asm (not coincidentally labeled DoMiscClock):
|
||||
// The various clocks are clocked manually by the 8085 by writing a zero
|
||||
// to the appropriate clock bit followed by a 1 to the clock bit, on a 0->1 transition
|
||||
// data is clocked into the appropriate register, or cleared/incremented for the MPanel display.
|
||||
//
|
||||
|
||||
//
|
||||
// on a 1->0 transition for a clock bit we will take the appropriate action.
|
||||
//
|
||||
for (int clockFlag = 0x1; clockFlag < 0x100; clockFlag = clockFlag << 1)
|
||||
{
|
||||
if ((clockFlags & clockFlag) == 0 &&
|
||||
(_lastClockFlags & clockFlag) != 0)
|
||||
{
|
||||
switch((ClockFlags)clockFlag)
|
||||
{
|
||||
case ClockFlags.ClrMPanel:
|
||||
_mPanelValue = 0;
|
||||
MPChanged();
|
||||
break;
|
||||
|
||||
case ClockFlags.IncMPanel:
|
||||
_mPanelValue = (_mPanelValue + 1) % 10000;
|
||||
MPChanged();
|
||||
break;
|
||||
|
||||
case ClockFlags.TODRead:
|
||||
_todClock.ClockBit(TODClockType.Read);
|
||||
break;
|
||||
|
||||
case ClockFlags.TODSetA:
|
||||
_todClock.ClockBit(TODClockType.SetA);
|
||||
break;
|
||||
|
||||
case ClockFlags.TODSetB:
|
||||
_todClock.ClockBit(TODClockType.SetB);
|
||||
break;
|
||||
|
||||
case ClockFlags.TODSetC:
|
||||
_todClock.ClockBit(TODClockType.SetC);
|
||||
break;
|
||||
|
||||
case ClockFlags.TODSetD:
|
||||
_todClock.ClockBit(TODClockType.SetD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_lastClockFlags = clockFlags;
|
||||
}
|
||||
|
||||
// MP data
|
||||
private bool _mPanelBlank;
|
||||
private int _mPanelValue;
|
||||
|
||||
// Alt boot counter -- decremented on access to MiscInput1, used to simulate
|
||||
// holding down of AltBoot button for N seconds to select boot device.
|
||||
private int _altBootCounter;
|
||||
|
||||
// The value to set the AltBoot counter to at reset.
|
||||
private AltBootValues _altBoot;
|
||||
|
||||
// Clock register data
|
||||
private int _lastClockFlags;
|
||||
|
||||
// DMA Test Register data
|
||||
private byte _dmaTestValue;
|
||||
|
||||
// TOD Clock
|
||||
private TODClock _todClock;
|
||||
|
||||
// Reference to the IOP we belong to.
|
||||
private IOProcessor _iop;
|
||||
|
||||
private readonly int[] _readPorts = new int[]
|
||||
{
|
||||
0xd0, // DMA Test Register
|
||||
0xe9, // Interrupt request bits (read)
|
||||
0xea, // Keyboard data latch
|
||||
0xed, // Mouse X counter
|
||||
0xee, // Mouse Y counter
|
||||
0xef // Miscellaneous input
|
||||
};
|
||||
|
||||
private readonly int[] _writePorts = new int[]
|
||||
{
|
||||
0xd0, // DMA Test Register
|
||||
0xe9, // KB, MP, TOD clocks (write)
|
||||
0xea, // Clear TOD interrupt (write)
|
||||
0xed, // Clear Mouse X,Y counters
|
||||
0xef // KB, MP, TOD control (write)
|
||||
};
|
||||
|
||||
//
|
||||
// Misc clocks flags
|
||||
//
|
||||
[Flags]
|
||||
private enum ClockFlags
|
||||
{
|
||||
ClrMPanel = 0x40,
|
||||
IncMPanel = 0x20,
|
||||
TODRead = 0x10,
|
||||
TODSetA = 0x08,
|
||||
TODSetB = 0x04,
|
||||
TODSetC = 0x02,
|
||||
TODSetD = 0x01,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum MiscInput1Flags
|
||||
{
|
||||
AltBoot = 0x80,
|
||||
TODData = 0x40,
|
||||
PowerFailed = 0x20,
|
||||
TODInt = 0x10,
|
||||
CSParity = 0x08,
|
||||
MouseSw3 = 0x4,
|
||||
MouseSw2 = 0x2,
|
||||
MouseSw1 = 0x1,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum InterruptRequestFlags
|
||||
{
|
||||
Floppy = 0x80,
|
||||
Keyboard = 0x40,
|
||||
PrinterTx = 0x20,
|
||||
PrinterRx = 0x10,
|
||||
Misc = 0x08,
|
||||
RS232 = 0x04,
|
||||
LSEPTx = 0x02,
|
||||
LSEPRx = 0x01,
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
103
D/IOP/Mouse.cs
Normal file
103
D/IOP/Mouse.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
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.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace D.IOP
|
||||
{
|
||||
[Flags]
|
||||
public enum StarMouseButton
|
||||
{
|
||||
None = 0,
|
||||
Left = 0x4,
|
||||
Right = 0x2,
|
||||
Middle = 0x1,
|
||||
}
|
||||
|
||||
public class Mouse
|
||||
{
|
||||
public Mouse()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public int MouseX
|
||||
{
|
||||
get { return _mouseX; }
|
||||
}
|
||||
|
||||
public int MouseY
|
||||
{
|
||||
get { return _mouseY; }
|
||||
}
|
||||
|
||||
public StarMouseButton Buttons
|
||||
{
|
||||
get { return _buttons; }
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_mouseX = 0;
|
||||
_mouseY = 0;
|
||||
}
|
||||
|
||||
public void MouseDown(StarMouseButton button)
|
||||
{
|
||||
_buttons |= button;
|
||||
}
|
||||
|
||||
public void MouseUp(StarMouseButton button)
|
||||
{
|
||||
_buttons &= (~button);
|
||||
}
|
||||
|
||||
public void MouseMove(int dx, int dy)
|
||||
{
|
||||
_mouseX += dx;
|
||||
_mouseY += dy;
|
||||
|
||||
// Clip into range (-128 to 127)
|
||||
_mouseX = Math.Max(-128, _mouseX);
|
||||
_mouseX = Math.Min(127, _mouseX);
|
||||
|
||||
_mouseY = Math.Max(-128, _mouseY);
|
||||
_mouseY = Math.Min(127, _mouseY);
|
||||
}
|
||||
|
||||
private int _mouseX;
|
||||
private int _mouseY;
|
||||
|
||||
private StarMouseButton _buttons;
|
||||
}
|
||||
}
|
||||
BIN
D/IOP/PROM/537P03029.bin
Normal file
BIN
D/IOP/PROM/537P03029.bin
Normal file
Binary file not shown.
BIN
D/IOP/PROM/537P03030.bin
Normal file
BIN
D/IOP/PROM/537P03030.bin
Normal file
Binary file not shown.
BIN
D/IOP/PROM/537P03032.bin
Normal file
BIN
D/IOP/PROM/537P03032.bin
Normal file
Binary file not shown.
BIN
D/IOP/PROM/537P03700.bin
Normal file
BIN
D/IOP/PROM/537P03700.bin
Normal file
Binary file not shown.
123
D/IOP/Printer.cs
Normal file
123
D/IOP/Printer.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
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.Logging;
|
||||
|
||||
namespace D.IOP
|
||||
{
|
||||
/// <summary>
|
||||
/// Stub implementation of the Printer port. This is just
|
||||
/// enough to get the rigid diagnostic set to pass.
|
||||
/// </summary>
|
||||
public class Printer : IIOPDevice
|
||||
{
|
||||
public Printer()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_rxRequest = true; // active low
|
||||
_txRequest = true; // always ready to transmit, makes the diags happy.
|
||||
}
|
||||
|
||||
public bool RxRequest
|
||||
{
|
||||
get { return _rxRequest; }
|
||||
}
|
||||
|
||||
public bool TxRequest
|
||||
{
|
||||
get { return _txRequest; }
|
||||
}
|
||||
|
||||
public int[] ReadPorts
|
||||
{
|
||||
get { return _readPorts; }
|
||||
}
|
||||
|
||||
public int[] WritePorts
|
||||
{
|
||||
get { return _writePorts; }
|
||||
}
|
||||
|
||||
public byte ReadPort(int port)
|
||||
{
|
||||
byte value = 0;
|
||||
switch(port)
|
||||
{
|
||||
case 0x88:
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPPrinter, "Stub: Printer data port read.");
|
||||
value = _txData; // just loopback data to make diags happy.
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPPrinter, "Stub: Printer status port read. Returning DTR");
|
||||
value = 0x00;
|
||||
_rxRequest = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public void WritePort(int port, byte data)
|
||||
{
|
||||
switch(port)
|
||||
{
|
||||
case 0x88:
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPPrinter, "Stub: Printer data port write 0x{0:x2}.", data);
|
||||
_txData = data;
|
||||
_rxRequest = false; // "TTY request is active low."
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
if (Log.Enabled) Log.Write(LogComponent.IOPPrinter, "Stub: Printer control port write 0x{0:x2}.", data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _rxRequest;
|
||||
private bool _txRequest;
|
||||
|
||||
private byte _txData;
|
||||
|
||||
private readonly int[] _readPorts = new int[]
|
||||
{
|
||||
0x88, // data
|
||||
0x89, // status
|
||||
};
|
||||
|
||||
private readonly int[] _writePorts = new int[]
|
||||
{
|
||||
0x88, // data
|
||||
0x89, // commands
|
||||
};
|
||||
}
|
||||
}
|
||||
2532
D/IOP/Source/SourceMap.txt
Normal file
2532
D/IOP/Source/SourceMap.txt
Normal file
File diff suppressed because it is too large
Load Diff
311
D/IOP/TODClock.cs
Normal file
311
D/IOP/TODClock.cs
Normal file
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
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.Threading;
|
||||
|
||||
namespace D.IOP
|
||||
{
|
||||
public enum TODPowerUpSetMode
|
||||
{
|
||||
HostTimeY2K = 0,
|
||||
HostTime,
|
||||
SpecificDateAndTime,
|
||||
SpecificDate,
|
||||
NoChange,
|
||||
}
|
||||
|
||||
public enum TODAccessMode
|
||||
{
|
||||
Read = 0x4,
|
||||
Clear = 0x2,
|
||||
Set = 0x1,
|
||||
None = 0,
|
||||
}
|
||||
|
||||
public enum TODClockType
|
||||
{
|
||||
Read = 0,
|
||||
SetA,
|
||||
SetB,
|
||||
SetC,
|
||||
SetD,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements the Star's TOD clock and timing logic.
|
||||
/// The Star does not use an off-the-shelf RTC chip, just a series of
|
||||
/// 74LS393 dual 4-bit counters and 74LS165 shift registers
|
||||
/// clocked off of a 1Hz clock -- these form a single 32-bit register
|
||||
/// that counts seconds. It can be read and written by the IOP.
|
||||
///
|
||||
/// This uses a Timer to provide decent real-time clock interrupts
|
||||
/// independent of the speed of the running emulation.
|
||||
/// </summary>
|
||||
public class TODClock
|
||||
{
|
||||
public TODClock()
|
||||
{
|
||||
_lock = new ReaderWriterLockSlim();
|
||||
|
||||
// Get the timer rolling, it will tick once a second forever.
|
||||
// TODO: this is not particularly accurate, timekeeping-wise.
|
||||
_timer = new Timer(TimerTick, null, 1000, 1000);
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
_interrupt = false;
|
||||
_lock.ExitWriteLock();
|
||||
|
||||
_todReadBit = 0;
|
||||
_mode = TODAccessMode.None;
|
||||
_powerLoss = false;
|
||||
|
||||
PowerUpSetMode = Configuration.TODSetMode;
|
||||
PowerUpSetTime = (PowerUpSetMode == TODPowerUpSetMode.SpecificDate) ?
|
||||
Configuration.TODDate : Configuration.TODDateTime;
|
||||
|
||||
SetTODClockInternal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the clock to the current value specified by the
|
||||
/// system configuration.
|
||||
/// </summary>
|
||||
public void ResetTODClockTime()
|
||||
{
|
||||
SetTODClockInternal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// How to set the TOD clock when the system is started.
|
||||
/// </summary>
|
||||
public TODPowerUpSetMode PowerUpSetMode;
|
||||
|
||||
/// <summary>
|
||||
/// A specific time to set the TOD clock to
|
||||
/// </summary>
|
||||
public DateTime PowerUpSetTime;
|
||||
|
||||
/// <summary>
|
||||
/// The Interrupt flag indicates that a (soft) TOD interrupt
|
||||
/// has occurred -- this is raised every time the clock ticks.
|
||||
/// </summary>
|
||||
public bool Interrupt
|
||||
{
|
||||
get
|
||||
{
|
||||
bool value;
|
||||
|
||||
_lock.EnterReadLock();
|
||||
value = _interrupt;
|
||||
_lock.ExitReadLock();
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool PowerLoss
|
||||
{
|
||||
get
|
||||
{
|
||||
return _powerLoss;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearInterrupt()
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
_interrupt = false;
|
||||
_lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
public void SetMode(TODAccessMode mode)
|
||||
{
|
||||
_mode = mode;
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case TODAccessMode.Read:
|
||||
_todReadBit = 0;
|
||||
break;
|
||||
|
||||
case TODAccessMode.Set:
|
||||
// TODO: anything need to be done here?
|
||||
break;
|
||||
|
||||
case TODAccessMode.Clear:
|
||||
_todValue = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public int ReadClockBit()
|
||||
{
|
||||
_lock.EnterReadLock();
|
||||
// From BookKeepingTask.asm: "Bits from clock come in true, and most significant bit first."
|
||||
int value = (_todValue & (0x80000000 >> (_todReadBit & 0x1f))) != 0 ? 0x40 : 0;
|
||||
_lock.ExitReadLock();
|
||||
return value;
|
||||
}
|
||||
|
||||
public void ClockBit(TODClockType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case TODClockType.Read:
|
||||
_todReadBit++;
|
||||
break;
|
||||
|
||||
//
|
||||
// A clock to A,B,C or D causes the value
|
||||
// in the corresponding byte of the tod counter to be incremented.
|
||||
// A is the least-significant byte, D is the most-significant.
|
||||
//
|
||||
case TODClockType.SetA:
|
||||
_lock.EnterWriteLock();
|
||||
_todValue = ((_todValue & 0xffffff00) | ((_todValue + 1) & 0xff));
|
||||
_powerLoss = false;
|
||||
_lock.ExitWriteLock();
|
||||
break;
|
||||
|
||||
case TODClockType.SetB:
|
||||
_lock.EnterWriteLock();
|
||||
_todValue = ((_todValue & 0xffff00ff) | ((_todValue + 0x100) & 0xff00));
|
||||
_powerLoss = false;
|
||||
_lock.ExitWriteLock();
|
||||
break;
|
||||
|
||||
case TODClockType.SetC:
|
||||
_lock.EnterWriteLock();
|
||||
_todValue = ((_todValue & 0xff00ffff) | ((_todValue + 0x10000) & 0xff0000));
|
||||
_powerLoss = false;
|
||||
_lock.ExitWriteLock();
|
||||
break;
|
||||
|
||||
case TODClockType.SetD:
|
||||
_lock.EnterWriteLock();
|
||||
_todValue = ((_todValue & 0x00ffffff) | ((_todValue + 0x1000000) & 0xff000000));
|
||||
_powerLoss = false;
|
||||
_lock.ExitWriteLock();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException("Clock bit not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
private void SetTODClockInternal()
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
switch (PowerUpSetMode)
|
||||
{
|
||||
case TODPowerUpSetMode.HostTimeY2K:
|
||||
//
|
||||
// Get current time, and move date back 28 years since most Star software isn't happy with Y2K.
|
||||
// This keeps the calendar in sync at least.
|
||||
//
|
||||
_todValue = GetXeroxTime(DateTime.Now.ToLocalTime().AddYears(-28));
|
||||
break;
|
||||
|
||||
case TODPowerUpSetMode.HostTime:
|
||||
//
|
||||
// Set TOD clock to the current wall-clock time.
|
||||
//
|
||||
_todValue = GetXeroxTime(DateTime.Now.ToLocalTime());
|
||||
break;
|
||||
|
||||
case TODPowerUpSetMode.SpecificDateAndTime:
|
||||
//
|
||||
// Set TOD clock to the specified date and time.
|
||||
//
|
||||
_todValue = GetXeroxTime(PowerUpSetTime);
|
||||
break;
|
||||
|
||||
case TODPowerUpSetMode.SpecificDate:
|
||||
//
|
||||
// Set TOD clock to the specified date, with the current time.
|
||||
//
|
||||
_todValue = GetXeroxTime(PowerUpSetTime.Add(DateTime.Now.TimeOfDay));
|
||||
break;
|
||||
|
||||
case TODPowerUpSetMode.NoChange:
|
||||
//
|
||||
// Do nothing.
|
||||
//
|
||||
break;
|
||||
}
|
||||
_lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
private uint GetXeroxTime(DateTime time)
|
||||
{
|
||||
//
|
||||
// The Star's epoch is 1/1/1901.
|
||||
//
|
||||
long dateTicks = time.Ticks;
|
||||
long epochTicks = new DateTime(1901, 1, 1, 0, 0, 0).ToLocalTime().Ticks;
|
||||
|
||||
long adjustedTicks = dateTicks - epochTicks;
|
||||
|
||||
// Ticks are 100nS.
|
||||
uint seconds = (uint)(adjustedTicks / 10000000);
|
||||
|
||||
return seconds;
|
||||
}
|
||||
|
||||
private void TimerTick(object context)
|
||||
{
|
||||
//
|
||||
// One real second has elapsed.
|
||||
// We raise the interrupt flag and increment
|
||||
// the clock value.
|
||||
//
|
||||
_lock.EnterWriteLock();
|
||||
_interrupt = true;
|
||||
_todValue++;
|
||||
_lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
private bool _interrupt;
|
||||
private bool _powerLoss;
|
||||
private UInt32 _todValue;
|
||||
private int _todReadBit;
|
||||
|
||||
private TODAccessMode _mode;
|
||||
|
||||
// Timer for real-time clocking and a lock to make things
|
||||
// thread-safe. The lock is probably overkill but let's do this right.
|
||||
private Timer _timer;
|
||||
private ReaderWriterLockSlim _lock;
|
||||
}
|
||||
}
|
||||
2085
D/IOP/i8085.cs
Normal file
2085
D/IOP/i8085.cs
Normal file
File diff suppressed because it is too large
Load Diff
164
D/Logging/Log.cs
Normal file
164
D/Logging/Log.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
#define LOGGING_ENABLED
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace D.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies a component to specify logging for
|
||||
/// </summary>
|
||||
[Flags, ]
|
||||
public enum LogComponent
|
||||
{
|
||||
None = 0,
|
||||
|
||||
// IOP
|
||||
IOP = 0x1,
|
||||
IOPMemory = 0x2,
|
||||
IOPIO = 0x4,
|
||||
IOPFloppy = 0x8,
|
||||
IOPMisc = 0x10,
|
||||
IOPDMA = 0x20,
|
||||
IOPKeyboard = 0x40,
|
||||
IOPPrinter = 0x80,
|
||||
|
||||
// CP
|
||||
CPControl = 0x100,
|
||||
CPExecution = 0x200,
|
||||
CPMicrocodeLoad = 0x400,
|
||||
CPTPCLoad = 0x800,
|
||||
CPTask = 0x1000,
|
||||
CPMap = 0x2000,
|
||||
CPError = 0x4000,
|
||||
CPIB = 0x8000,
|
||||
CPStack = 0x10000,
|
||||
CPInst = 0x20000,
|
||||
|
||||
// Memory
|
||||
MemoryControl = 0x100000,
|
||||
MemoryAccess = 0x200000,
|
||||
|
||||
// Display
|
||||
DisplayControl = 0x400000,
|
||||
|
||||
// Shugart controller
|
||||
ShugartControl = 0x800000,
|
||||
|
||||
// Ethernet
|
||||
EthernetControl = 0x1000000,
|
||||
HostEthernet = 0x2000000,
|
||||
|
||||
// Configuration
|
||||
Configuration = 0x4000000,
|
||||
|
||||
All = 0x7fffffff
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the type (or severity) of a given log message
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum LogType
|
||||
{
|
||||
None = 0,
|
||||
Normal = 0x1,
|
||||
Warning = 0x2,
|
||||
Error = 0x4,
|
||||
Verbose = 0x8,
|
||||
All = 0x7fffffff
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides basic functionality for logging messages of all types.
|
||||
/// </summary>
|
||||
public static class Log
|
||||
{
|
||||
static Log()
|
||||
{
|
||||
Enabled = false;
|
||||
_components = LogComponent.None;
|
||||
_type = LogType.None;
|
||||
_logIndex = 0;
|
||||
}
|
||||
|
||||
public static LogComponent LogComponents
|
||||
{
|
||||
get { return _components; }
|
||||
set { _components = value; }
|
||||
}
|
||||
|
||||
public static readonly bool Enabled;
|
||||
|
||||
#if LOGGING_ENABLED
|
||||
/// <summary>
|
||||
/// Logs a message without specifying type/severity for terseness;
|
||||
/// will not log if Type has been set to None.
|
||||
/// </summary>
|
||||
/// <param name="level"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="args"></param>
|
||||
public static void Write(LogComponent component, string message, params object[] args)
|
||||
{
|
||||
Write(LogType.Normal, component, message, args);
|
||||
}
|
||||
|
||||
public static void Write(LogType type, LogComponent component, string message, params object[] args)
|
||||
{
|
||||
if ((_type & type) != 0 &&
|
||||
(_components & component) != 0)
|
||||
{
|
||||
//
|
||||
// My log has something to tell you...
|
||||
// TODO: color based on type, etc.
|
||||
Console.WriteLine(_logIndex.ToString() + ": " + component.ToString() + ": " + message, args);
|
||||
_logIndex++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
public static void Write(LogComponent component, string message, params object[] args)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static void Write(LogType type, LogComponent component, string message, params object[] args)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private static LogComponent _components;
|
||||
private static LogType _type;
|
||||
private static long _logIndex;
|
||||
}
|
||||
}
|
||||
121
D/Memory/Memory.cs
Normal file
121
D/Memory/Memory.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
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.Logging;
|
||||
using System;
|
||||
|
||||
namespace D.Memory
|
||||
{
|
||||
/// <summary>
|
||||
/// Encapsulates the physical memory, with enough of an ECC implementation
|
||||
/// to allow diagnostics to pass.
|
||||
/// </summary>
|
||||
public class Memory
|
||||
{
|
||||
public Memory()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
if (_memory == null || _memory.Length != Configuration.MemorySize * 1024)
|
||||
{
|
||||
_memory = new ushort[Configuration.MemorySize * 1024];
|
||||
_ecc = new byte[_memory.Length];
|
||||
}
|
||||
else if (_memory != null)
|
||||
{
|
||||
Array.Clear(_memory, 0, _memory.Length);
|
||||
Array.Clear(_ecc, 0, _ecc.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public int Size
|
||||
{
|
||||
get { return _memory.Length; }
|
||||
}
|
||||
|
||||
public ushort ReadWord(int address, out bool valid)
|
||||
{
|
||||
if (address < _memory.Length)
|
||||
{
|
||||
ushort memWord = _memory[address];
|
||||
valid = _ecc[address] == CalculateECCSyndrome(memWord);
|
||||
return memWord;
|
||||
}
|
||||
else
|
||||
{
|
||||
valid = false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteWord(int address, ushort value)
|
||||
{
|
||||
if (address < _memory.Length)
|
||||
{
|
||||
WriteECC(address, value);
|
||||
_memory[address] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.MemoryAccess, "Write to nonexistent memory address 0x{0:x}", address);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCheckBits(int invertBits)
|
||||
{
|
||||
_mctlInvert = invertBits;
|
||||
}
|
||||
|
||||
private byte CalculateECCSyndrome(ushort word)
|
||||
{
|
||||
//
|
||||
// Not actually calculating an ECC syndrome here, as at the moment there are no
|
||||
// plans to emulate faulty memory, or the hardware to correct it.
|
||||
//
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void WriteECC(int address, ushort value)
|
||||
{
|
||||
//
|
||||
// Write the calculated ECC syndrome value with the bits specified by MCtl<-
|
||||
// inverted.
|
||||
//
|
||||
_ecc[address] = (byte)(CalculateECCSyndrome(value) ^ _mctlInvert);
|
||||
}
|
||||
|
||||
private ushort[] _memory;
|
||||
private byte[] _ecc;
|
||||
|
||||
private int _mctlInvert;
|
||||
}
|
||||
}
|
||||
156
D/Memory/MemoryController.cs
Normal file
156
D/Memory/MemoryController.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
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.Logging;
|
||||
|
||||
namespace D.Memory
|
||||
{
|
||||
public class MemoryController
|
||||
{
|
||||
public MemoryController()
|
||||
{
|
||||
_mem = new Memory();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_mStatus = 0;
|
||||
_mar = 0;
|
||||
_md = 0;
|
||||
_mdValid = true;
|
||||
|
||||
_mem.Reset();
|
||||
}
|
||||
|
||||
public ushort MStatus
|
||||
{
|
||||
get { return _mStatus; }
|
||||
}
|
||||
|
||||
public int MAR
|
||||
{
|
||||
get { return _mar; }
|
||||
}
|
||||
|
||||
// Exposing memory for debugging purposes.
|
||||
public Memory DebugMemory
|
||||
{
|
||||
get { return _mem; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used for debugging.
|
||||
/// </summary>
|
||||
public ushort MD
|
||||
{
|
||||
get { return _md; }
|
||||
}
|
||||
|
||||
public void SetMCtl(ushort value)
|
||||
{
|
||||
//
|
||||
// See HWRef, figure 18 (pg 55).
|
||||
// This is used to test syndrome bits or clear error logs.
|
||||
//
|
||||
if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.MemoryControl, "MCtl<-0x{0:x}", value);
|
||||
|
||||
_mem.SetCheckBits((value & 0xff) >> 2);
|
||||
|
||||
if ((value & 0x800) != 0)
|
||||
{
|
||||
// Clear error log for the task specified by bits [5..7].
|
||||
int task = (value & 0x700) >> 8;
|
||||
_mStatus &= (ushort)(~(0x80 >> task));
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadMAR(int address)
|
||||
{
|
||||
_mar = address;
|
||||
|
||||
//
|
||||
// Pre-load the memory requested, so we can return
|
||||
// the original data in cases where MDR is written and MD is read in the same click.
|
||||
//
|
||||
_md = _mem.ReadWord(_mar, out _mdValid);
|
||||
|
||||
if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.MemoryAccess, "MAR<-0x{0:x5}", address);
|
||||
}
|
||||
|
||||
public void LoadMDR(ushort value)
|
||||
{
|
||||
//
|
||||
// Write the word to memory
|
||||
//
|
||||
_mem.WriteWord(_mar, value);
|
||||
|
||||
if (Log.Enabled)
|
||||
{
|
||||
Log.Write(LogType.Verbose, LogComponent.MemoryAccess, "MDR<-0x{0:x4}", value);
|
||||
if (_mar >= 0x10000 && _mar < 0x20000)
|
||||
{
|
||||
Log.Write(LogType.Verbose, LogComponent.CPMap, "MAP 0x{0:x5} = {1:x4}", _mar, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ushort ReadMD(TaskType task, out bool valid)
|
||||
{
|
||||
//
|
||||
// Return the data read in LoadMAR.
|
||||
//
|
||||
if (Log.Enabled) Log.Write(LogType.Verbose, LogComponent.MemoryAccess, "<-MD (0x{0:x4}) valid {1}", _md, _mdValid);
|
||||
|
||||
valid = _mdValid;
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
if (Log.Enabled) Log.Write(LogComponent.MemoryAccess, "Read from nonexistent memory address 0x{0:x}", _mar);
|
||||
_mStatus |= (ushort)((0x80 >> (int)task)); // Set error bit for task
|
||||
_mStatus |= 0x100; // double-bit error.
|
||||
|
||||
// TODO: set syndrome bits
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear single/double-bit errors (bits 6..7)
|
||||
_mStatus &= 0xfcff;
|
||||
}
|
||||
return _md;
|
||||
}
|
||||
|
||||
private int _mar;
|
||||
private ushort _md;
|
||||
private bool _mdValid;
|
||||
private ushort _mStatus;
|
||||
|
||||
private Memory _mem;
|
||||
}
|
||||
}
|
||||
15
D/Notes/8085 code annotation.txt
Normal file
15
D/Notes/8085 code annotation.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
Need to build a symbol table of sorts for 8085 code to allow mapping of ROM addresses
|
||||
to source lines & symbol names in source code.
|
||||
|
||||
Current thoughts:
|
||||
Text file consisting of lines in the format:
|
||||
|
||||
$<ROM Address>-[length]: <source file name>, <line number>
|
||||
|
||||
to describe instruction mapping or label/constant value definition -> source line.
|
||||
Duplicate <ROM Address> fields may be present to describe symbols pointing to same address
|
||||
|
||||
Start with ROM addresses that correspond directly to labels, see how interpolation (based on
|
||||
assembly of source, perhaps?) can deal with the intermediary addresses.
|
||||
|
||||
|
||||
1
D/Notes/Ethernet.txt
Normal file
1
D/Notes/Ethernet.txt
Normal file
File diff suppressed because one or more lines are too long
214
D/Notes/IOP.txt
Normal file
214
D/Notes/IOP.txt
Normal file
@@ -0,0 +1,214 @@
|
||||
IOP notes. These are gleaned from various bits of documentation and source code.
|
||||
There is no official IOP documentation available.
|
||||
|
||||
Hardware:
|
||||
- CPU: 8085
|
||||
- FDC: WD FD1797
|
||||
- i8253 programmable interval timer
|
||||
- i8251 UART
|
||||
- i8257 dma controller
|
||||
- Z80-SIO for RS232C/RS366 (?? not present on PCB...)
|
||||
|
||||
Memory Map (see SysDefs.asm):
|
||||
|
||||
$0000-$1FFF : PROM (8K)
|
||||
$2000-$5FFF : RAM (16K)
|
||||
|
||||
$8000-$800F : Host Addr PROM
|
||||
$8010-$FFFF : Memory Mapped-I/O
|
||||
|
||||
Map of PROM ICs to ROM Locations:
|
||||
|
||||
3.1 :
|
||||
|
||||
U129 - 537P03029 - $0000
|
||||
U130 - 537P03030 - $0800
|
||||
U131 - 537P03700 - $1000
|
||||
U132 - 537P03032 - $1800
|
||||
|
||||
|
||||
I/O addresses:
|
||||
|
||||
$80-$83 - Alto PPI
|
||||
|
||||
$84 - FDC Command (write)
|
||||
$84 - FDC Status (read)
|
||||
$85 - FDC Track register (write)
|
||||
$86 - FDC Sector register (write)
|
||||
$87 - FDC Data register (write, read?)
|
||||
|
||||
$88 - Printer Data (read/write)
|
||||
$89 - Printer Commands (write)
|
||||
$89 - Printer Status (read)
|
||||
|
||||
$8C - Timer Counter 0 (read/write)
|
||||
$8D - Timer Counter 1 (read/write)
|
||||
$8E - Timer Counter 2 (read/write)
|
||||
$8F - Timer Mode (commands) (write)
|
||||
|
||||
$90 - LSEP Uart Data
|
||||
$91 - LSEP Uart Command
|
||||
$92 - LSEP Uart Status
|
||||
$94 - LSEP Timer Counter 0
|
||||
|
||||
$95 - Counter for SIO
|
||||
$96 - Counter for Time Counter
|
||||
|
||||
$97 - LSEP Timer Mode / Baud Rate Gen. Control Register (?)
|
||||
|
||||
$98 - SIO Channel A Data Register
|
||||
$99 - " B "
|
||||
$9A - SIO Channel A Control Register
|
||||
$9B - " B "
|
||||
|
||||
$9C - RS366 register
|
||||
|
||||
$A0 - $A8 - DMA Controller
|
||||
|
||||
$B0 - $BF - Host PROM data (read)
|
||||
|
||||
|
||||
$E0 - Keyset (read?)
|
||||
|
||||
$E8 - FDC External State
|
||||
$E9 - KB, MP, TOD clocks (write)
|
||||
$E9 - Interrupt request bits (read)
|
||||
$EA - clear TOD interrupt (write)
|
||||
$EA - Keyboard data latch (read)
|
||||
|
||||
$EB - CP data in (read)
|
||||
$EB - CP data out (write)
|
||||
$EC - CP (central processor) control register (write)
|
||||
$EC - CP status (read)
|
||||
|
||||
$ED - Mouse X counter (read)
|
||||
$ED - Clear mouse X, Y counters (write)
|
||||
$EE - Mouse Y counter (read)
|
||||
$EE - Clear CP DMA Complete (write)
|
||||
|
||||
$EF - Misc I/O devices (keyboard, clocks, etc.) input
|
||||
$EF - Misc control (write)
|
||||
|
||||
$F8-$FF - Control Store read/write:
|
||||
|
||||
; Format of TPCHigh (write): TPCAddr[0:2],,TPCData[0:4]'
|
||||
; Format of TPCLow (write): don't care,,TPCData[5:11]'
|
||||
$FE - TPC High (inverted)
|
||||
$FF - TPC Low (inverted)
|
||||
$F8-$FD - 48 bits of control store, MSB -> LSB, bits inverted.
|
||||
|
||||
|
||||
|
||||
|
||||
Memory-Mapped IO:
|
||||
-----------------
|
||||
|
||||
$80ec - CPControl - CP control register : IOPWait',,SwTAddr',,IOPAttn,,CPDmaMode,,CPDmaIn (write)
|
||||
$80ec - CPStatus (read)
|
||||
$80eb - CP data in (read)
|
||||
$80eb - CP data out (write)
|
||||
|
||||
|
||||
|
||||
CP <-> IOP comms
|
||||
----------------
|
||||
|
||||
In WriteCPbyte (BootSubs.asm), addr $71b:
|
||||
|
||||
WaitCPOutAck expects CPStatus to have the interrupt mask bit set after data is written, loops until this is so.
|
||||
|
||||
|
||||
CP interrupts from IOP:
|
||||
|
||||
from Kernel.mc:
|
||||
|
||||
"The Kernel can be entered by one of two ways: Either via a breakpoint or the IOP asynchronously interrupting the CP
|
||||
via the IOPWait line. If entry is via a breakpoint, the kernel can be entered in any cycle (and inter-cycle state
|
||||
information must be preserved). IOPWait caused entry always occurs between clicks (so all state information is already
|
||||
saved by the CP and there is no memory state across clicks which can be lost, saved or restored).
|
||||
|
||||
Upon entering the kernel, it interrupts the IOP and waits for a command byte. There are 3 possible commands that the
|
||||
IOP can specify: Refresh, ExitKernel, and ExecuteBufffer. Refresh is used by the IOP when it is writing the CS,
|
||||
ExitKernel causes the CP to leave the kernel task, and ExecuteBuffer causes the instructions which the IOP wrote in
|
||||
the buffer area to be executed.
|
||||
|
||||
When the kernel is entered via a breakpoint, an R register (rK) must be used to hold memory data or a breakpoint ID
|
||||
(or an RH reg for ID), and a Link register to hold condition bits (or a breakpoint ID).
|
||||
|
||||
When being entered via an IOPWait, no R register state need be lost (currently rK is lost) (i.e. rK and RHrK can first
|
||||
be saved away, then later restored. There should also be a second kind of ExitKernel command which doesn't write Mem[0]).
|
||||
|
||||
Currently, the kernel is written assuming it can always use rK, so this register is lost in the IOPWait caused entry
|
||||
also. (rK is used in the wait loop and in the overlay code which Burdock uses to read and write some registers.) "
|
||||
|
||||
|
||||
Status / Control registers:
|
||||
|
||||
IOP Ports:
|
||||
CPControl: IOP -> CP (IOP write) ($EC)
|
||||
- IOP uses this to control the CP; IOPAttn is set if the IOP needs attention from the CP?
|
||||
- Bits are: (from IOP schematic, p 15):
|
||||
- CPDmaIn - 0x8
|
||||
- CPDmaMode - 0x10
|
||||
- IOPAttn - 0x20
|
||||
- SwTAddr' - 0x40
|
||||
- IOPWait' - 0x80
|
||||
|
||||
CPStatus: CP -> IOP (IOP read) ($EC)
|
||||
- CP reports its status to the IOP, also includes IOP status
|
||||
- Bits are: (from IOP schematic, p 17):
|
||||
- CPDmaComplete' - 0x1
|
||||
- CPOutIntReq' - 0x2
|
||||
- CPInIntReq' - 0x4
|
||||
- CPDmaIn' - 0x8 - From CPControl
|
||||
- CPDmaMode' - 0x10 - "
|
||||
- IOPAttn' - 0x20 - "
|
||||
- EmuWake - 0x40 - From IOPCtl<-
|
||||
- CPAttn - 0x80 - "
|
||||
|
||||
|
||||
CP Ports:
|
||||
IOPCtl<-: CP-> IOP (CP write)
|
||||
- CP sets up communication between the IOP and the CP:
|
||||
- Bits are:
|
||||
- WakeMode.1 - 0x1
|
||||
- WakeMode.0 - 0x2
|
||||
- CPAttn - 0x4
|
||||
- EmuWake - 0x8 (is this actually used?)
|
||||
|
||||
Per uCode and Schematic (IOP, p 15), the WakeMode bits are:
|
||||
- 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
|
||||
|
||||
<-IOPStatus: IOP -> CP (CP read)
|
||||
- CP gets the IOP's status
|
||||
- Bits are (from IOP schematic, p 15):
|
||||
- IOPReq - 0x1 - set when data available from IOP?
|
||||
- WakeMode.1' - 0x2
|
||||
- WakeMode.0' - 0x4
|
||||
- CPAttn' - 0x8
|
||||
- EmuWake' = 0x10
|
||||
- IOPAttn - 0x20
|
||||
- Bits 0x40, 0x80 are always set low
|
||||
|
||||
|
||||
Communication register:
|
||||
- Appears to be a data register (8 bits + flow control) between the IOP and the CP; IOP gets status (interrupt?) when CP has written data to be read,
|
||||
CP can get woken up when the IOP has written data (see below).
|
||||
|
||||
CP Wakeups for IOP:
|
||||
- If IOPInMode is set, the CP's IOP task will wake up if input is available from the IOP (in the data register)
|
||||
- If IOPOutMode is set, wakeups will occur if the output data register is empty (i.e. the IOP is ready to receive a word.)
|
||||
- If IOPAWmode is set (In and Out bits set) the IOP will always wake up regardless
|
||||
|
||||
|
||||
Interrupts:
|
||||
----------
|
||||
Three interrupt lines on the CPU are used as following:
|
||||
|
||||
RST5.5 - CP Interrupt caused by CPAttn going high (also Burdock, the Alto debugging iface)
|
||||
RST6.5 - RS232 interrupt
|
||||
RST7.5 - Floppy Interrupt
|
||||
|
||||
76
D/Program.cs
Normal file
76
D/Program.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
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.Windows.Forms;
|
||||
using D.UI;
|
||||
|
||||
namespace D
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main(string[] args)
|
||||
{
|
||||
PrintHerald();
|
||||
|
||||
// Cons up a system to run stuff on.
|
||||
DSystem system = new DSystem();
|
||||
system.Reset();
|
||||
|
||||
//
|
||||
// Start the UI, this will not return from ShowDialog
|
||||
// until the window is closed.
|
||||
//
|
||||
DWindow mainWindow = new DWindow(system);
|
||||
system.AttachDisplay(mainWindow);
|
||||
DialogResult res = mainWindow.ShowDialog();
|
||||
|
||||
//
|
||||
// Main window is now closed: shut down the system.
|
||||
// Ensure the system is stopped.
|
||||
//
|
||||
system.StopExecution();
|
||||
|
||||
//
|
||||
// Commit disks on normal exit
|
||||
//
|
||||
system.Shutdown(res == DialogResult.OK);
|
||||
|
||||
Console.WriteLine("Goodbye...");
|
||||
}
|
||||
|
||||
private static void PrintHerald()
|
||||
{
|
||||
Console.WriteLine("Darkstar v{0}", typeof(Program).Assembly.GetName().Version);
|
||||
Console.WriteLine("(c) 2017, 2018 Living Computers: Museum+Labs");
|
||||
Console.WriteLine("Bug reports to joshd@livingcomputers.org");
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
65
D/Properties/AssemblyInfo.cs
Normal file
65
D/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
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.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Darkstar")]
|
||||
[assembly: AssemblyDescription("A Xerox Star/1108 Emulator")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Living Computers: Museum+Labs")]
|
||||
[assembly: AssemblyProduct("Darkstar")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017, 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("0590465e-1d91-4591-946e-ee3f7d82834b")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
158
D/Properties/Settings.Designer.cs
generated
Normal file
158
D/Properties/Settings.Designer.cs
generated
Normal file
@@ -0,0 +1,158 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace D.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string HardDriveImage {
|
||||
get {
|
||||
return ((string)(this["HardDriveImage"]));
|
||||
}
|
||||
set {
|
||||
this["HardDriveImage"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string FloppyDriveImage {
|
||||
get {
|
||||
return ((string)(this["FloppyDriveImage"]));
|
||||
}
|
||||
set {
|
||||
this["FloppyDriveImage"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool ThrottleSpeed {
|
||||
get {
|
||||
return ((bool)(this["ThrottleSpeed"]));
|
||||
}
|
||||
set {
|
||||
this["ThrottleSpeed"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("1")]
|
||||
public uint DisplayScale {
|
||||
get {
|
||||
return ((uint)(this["DisplayScale"]));
|
||||
}
|
||||
set {
|
||||
this["DisplayScale"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("2852201285")]
|
||||
public ulong HostAddress {
|
||||
get {
|
||||
return ((ulong)(this["HostAddress"]));
|
||||
}
|
||||
set {
|
||||
this["HostAddress"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string HostPacketInterfaceName {
|
||||
get {
|
||||
return ((string)(this["HostPacketInterfaceName"]));
|
||||
}
|
||||
set {
|
||||
this["HostPacketInterfaceName"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("1024")]
|
||||
public uint MemorySize {
|
||||
get {
|
||||
return ((uint)(this["MemorySize"]));
|
||||
}
|
||||
set {
|
||||
this["MemorySize"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool SlowPhosphor {
|
||||
get {
|
||||
return ((bool)(this["SlowPhosphor"]));
|
||||
}
|
||||
set {
|
||||
this["SlowPhosphor"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("1979-12-10")]
|
||||
public global::System.DateTime TODDateTime {
|
||||
get {
|
||||
return ((global::System.DateTime)(this["TODDateTime"]));
|
||||
}
|
||||
set {
|
||||
this["TODDateTime"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("0")]
|
||||
public int TODSetMode {
|
||||
get {
|
||||
return ((int)(this["TODSetMode"]));
|
||||
}
|
||||
set {
|
||||
this["TODSetMode"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("1955-11-05")]
|
||||
public global::System.DateTime TODDate {
|
||||
get {
|
||||
return ((global::System.DateTime)(this["TODDate"]));
|
||||
}
|
||||
set {
|
||||
this["TODDate"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
39
D/Properties/Settings.settings
Normal file
39
D/Properties/Settings.settings
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="D.Properties" GeneratedClassName="Settings">
|
||||
<Profiles />
|
||||
<Settings>
|
||||
<Setting Name="HardDriveImage" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="FloppyDriveImage" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="ThrottleSpeed" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="DisplayScale" Type="System.UInt32" Scope="User">
|
||||
<Value Profile="(Default)">1</Value>
|
||||
</Setting>
|
||||
<Setting Name="HostAddress" Type="System.UInt64" Scope="User">
|
||||
<Value Profile="(Default)">2852201285</Value>
|
||||
</Setting>
|
||||
<Setting Name="HostPacketInterfaceName" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="MemorySize" Type="System.UInt32" Scope="User">
|
||||
<Value Profile="(Default)">1024</Value>
|
||||
</Setting>
|
||||
<Setting Name="SlowPhosphor" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="TODDateTime" Type="System.DateTime" Scope="User">
|
||||
<Value Profile="(Default)">1979-12-10</Value>
|
||||
</Setting>
|
||||
<Setting Name="TODSetMode" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
<Setting Name="TODDate" Type="System.DateTime" Scope="User">
|
||||
<Value Profile="(Default)">1955-11-05</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
||||
BIN
D/SDL2.dll
Normal file
BIN
D/SDL2.dll
Normal file
Binary file not shown.
252
D/Scheduler.cs
Normal file
252
D/Scheduler.cs
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
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.Collections.Generic;
|
||||
|
||||
namespace D
|
||||
{
|
||||
/// <summary>
|
||||
/// The SchedulerEventCallback describes a delegate that is invoked whenever a scheduled event has
|
||||
/// reached its due-date and is fired.
|
||||
/// </summary>
|
||||
/// <param name="skew">The delta between the requested exec time and the actual exec time (in nsec)</param>
|
||||
/// <param name="context">An object containing context useful to the scheduler of the event</param>
|
||||
public delegate void SchedulerEventCallback(ulong skewNsec, object context);
|
||||
|
||||
/// <summary>
|
||||
/// An Event encapsulates a callback and associated context that is scheduled for a future timestamp.
|
||||
/// </summary>
|
||||
public class Event
|
||||
{
|
||||
public Event(ulong timestampNsec, object context, SchedulerEventCallback callback)
|
||||
{
|
||||
_timestampNsec = timestampNsec;
|
||||
_context = context;
|
||||
_callback = callback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The absolute time (in nsec) to raise the event.
|
||||
/// </summary>
|
||||
public ulong TimestampNsec
|
||||
{
|
||||
get { return _timestampNsec; }
|
||||
set { _timestampNsec = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An object containing context to be passed to the
|
||||
/// event callback.
|
||||
/// </summary>
|
||||
public object Context
|
||||
{
|
||||
get { return _context; }
|
||||
set { _context = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A delegate to be executed when the callback fires.
|
||||
/// </summary>
|
||||
public SchedulerEventCallback EventCallback
|
||||
{
|
||||
get { return _callback; }
|
||||
}
|
||||
|
||||
private ulong _timestampNsec;
|
||||
private object _context;
|
||||
private SchedulerEventCallback _callback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Scheduler class provides infrastructure for scheduling time-based hardware events
|
||||
/// (for example, sector marks, or video task wakeups).
|
||||
///
|
||||
/// Note that the Scheduler is not thread-safe and must only be used from the emulation thread,
|
||||
/// or else things will break. This is not optimal -- having a thread-safe scheduler would make
|
||||
/// it easier/cleaner to deal with asynchronous things like ethernet packets and scripting events
|
||||
/// but doing so incurs about a 10% performance penalty so it's been avoided.
|
||||
/// </summary>
|
||||
public class Scheduler
|
||||
{
|
||||
public Scheduler()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
public ulong CurrentTimeNsec
|
||||
{
|
||||
get { return _currentTimeNsec; }
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_schedule = new SchedulerQueue();
|
||||
_currentTimeNsec = 0;
|
||||
}
|
||||
|
||||
public void Clock()
|
||||
{
|
||||
//
|
||||
// Move one system clock forward in time.
|
||||
//
|
||||
_currentTimeNsec += _timeStepNsec;
|
||||
|
||||
//
|
||||
// See if we have any events waiting to fire at this timestep.
|
||||
//
|
||||
while (_schedule.Top != null && _currentTimeNsec >= _schedule.Top.TimestampNsec)
|
||||
{
|
||||
// Pop the top event and fire the callback.
|
||||
Event e = _schedule.Pop();
|
||||
e.EventCallback(_currentTimeNsec - e.TimestampNsec, e.Context);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a new event to the schedule.
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
public Event Schedule(ulong timestampNsec, object context, SchedulerEventCallback callback)
|
||||
{
|
||||
|
||||
Event e = new Event(timestampNsec + _currentTimeNsec, context, callback);
|
||||
_schedule.Push(e);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
public Event Schedule(ulong timestampNsec, SchedulerEventCallback callback)
|
||||
{
|
||||
Event e = new Event(timestampNsec + _currentTimeNsec, null, callback);
|
||||
_schedule.Push(e);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
public void Cancel(Event e)
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
_schedule.Remove(e);
|
||||
}
|
||||
}
|
||||
|
||||
private ulong _currentTimeNsec;
|
||||
|
||||
private SchedulerQueue _schedule;
|
||||
|
||||
// 137nsec is approximately one central processor system clock cycle and is the time-base for
|
||||
// the scheduler.
|
||||
private const ulong _timeStepNsec = 137;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides an "ordered" queue based on timestamp -- the top of the queue is always the
|
||||
/// next event to be fired; a "push" places a new event in order on the current queue.
|
||||
/// </summary>
|
||||
public class SchedulerQueue
|
||||
{
|
||||
public SchedulerQueue()
|
||||
{
|
||||
_queue = new LinkedList<Event>();
|
||||
}
|
||||
|
||||
public Event Top
|
||||
{
|
||||
get
|
||||
{
|
||||
return _top;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(Event e)
|
||||
{
|
||||
return _queue.Contains(e);
|
||||
}
|
||||
|
||||
public void Push(Event e)
|
||||
{
|
||||
// Degenerate case: list is empty or new entry is earlier than the head of the list.
|
||||
if (_queue.Count == 0 || _top.TimestampNsec >= e.TimestampNsec)
|
||||
{
|
||||
_queue.AddFirst(e);
|
||||
_top = e;
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Do a linear search to find the place to put this in.
|
||||
// Since we maintain a sorted list with every insertion we only need to find the first entry
|
||||
// that the new entry is earlier (or equal) to.
|
||||
// This will likely be adequate as the queue should never get incredibly deep; a binary
|
||||
// search may be more performant if this is not the case.
|
||||
//
|
||||
LinkedListNode<Event> current = _queue.First;
|
||||
while (current != null)
|
||||
{
|
||||
if (current.Value.TimestampNsec >= e.TimestampNsec)
|
||||
{
|
||||
_queue.AddBefore(current, e);
|
||||
return;
|
||||
}
|
||||
|
||||
current = current.Next;
|
||||
}
|
||||
|
||||
// Add at end
|
||||
_queue.AddLast(e);
|
||||
}
|
||||
|
||||
public Event Pop()
|
||||
{
|
||||
Event e = _top;
|
||||
_queue.RemoveFirst();
|
||||
|
||||
_top = _queue.First != null ? _queue.First.Value : null;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
public void Remove(Event e)
|
||||
{
|
||||
if (_queue.Contains(e))
|
||||
{
|
||||
_queue.Remove(e);
|
||||
_top = _queue.First.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private LinkedList<Event> _queue;
|
||||
|
||||
/// <summary>
|
||||
/// The Top of the queue (null if queue is empty).
|
||||
/// </summary>
|
||||
private Event _top;
|
||||
}
|
||||
}
|
||||
410
D/System.cs
Normal file
410
D/System.cs
Normal file
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
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.Display;
|
||||
using D.Ethernet;
|
||||
using D.IO;
|
||||
using D.IOP;
|
||||
using D.Memory;
|
||||
using D.UI;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace D
|
||||
{
|
||||
|
||||
public delegate bool StepCallbackDelegate();
|
||||
|
||||
public delegate void ErrorCallbackDelegate(Exception e);
|
||||
|
||||
/// <summary>
|
||||
/// Defines the context for the current execution
|
||||
/// (debug hooks, etc)
|
||||
/// </summary>
|
||||
public class SystemExecutionContext
|
||||
{
|
||||
public SystemExecutionContext(StepCallbackDelegate step8085, StepCallbackDelegate stepCP, StepCallbackDelegate stepMesa, ErrorCallbackDelegate error)
|
||||
{
|
||||
StepCallback8085 = step8085;
|
||||
StepCallbackCP = stepCP;
|
||||
StepCallbackMesa = stepMesa;
|
||||
ErrorCallback = error;
|
||||
}
|
||||
|
||||
public readonly StepCallbackDelegate StepCallback8085;
|
||||
public readonly StepCallbackDelegate StepCallbackCP;
|
||||
public readonly StepCallbackDelegate StepCallbackMesa;
|
||||
public readonly ErrorCallbackDelegate ErrorCallback;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Encompasses the Star's hardware and provides functionality to run and debug the system.
|
||||
/// </summary>
|
||||
public class DSystem
|
||||
{
|
||||
public DSystem()
|
||||
{
|
||||
_scheduler = new Scheduler();
|
||||
|
||||
_cp = new CentralProcessor(this);
|
||||
_iop = new IOProcessor(this);
|
||||
_memoryController = new MemoryController();
|
||||
_displayController = new DisplayController(this);
|
||||
_hardDrive = new SA1000Drive(this);
|
||||
_shugartController = new ShugartController(this, _hardDrive);
|
||||
_ethernetController = new EthernetController(this);
|
||||
|
||||
try
|
||||
{
|
||||
_frameTimer = new FrameTimer(38.7);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Not supported on this platform.
|
||||
_frameTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
bool wasExecuting = IsExecuting;
|
||||
|
||||
// Save context and stop executing if the system is currently running.
|
||||
SystemExecutionContext context = null;
|
||||
if (wasExecuting)
|
||||
{
|
||||
context = _currentExecutionContext;
|
||||
StopExecution();
|
||||
}
|
||||
|
||||
// Now do the actual reset.
|
||||
_cp.Reset();
|
||||
_iop.Reset();
|
||||
_displayController.Reset();
|
||||
_ethernetController.Reset();
|
||||
_hardDrive.Reset();
|
||||
_shugartController.Reset();
|
||||
// _scheduler.Reset();
|
||||
|
||||
_cpCycles = 0;
|
||||
_elapsedCycles = 0;
|
||||
|
||||
// Restart execution if we were running before the reset.
|
||||
if (wasExecuting)
|
||||
{
|
||||
StartExecution(context);
|
||||
}
|
||||
}
|
||||
|
||||
public void Shutdown(bool commitDisks)
|
||||
{
|
||||
_hardDrive.Save();
|
||||
}
|
||||
|
||||
public bool IsExecuting
|
||||
{
|
||||
get { return _executionThread != null && _executionThread.IsAlive; }
|
||||
}
|
||||
|
||||
public SystemExecutionContext ExecutionContext
|
||||
{
|
||||
get { return _currentExecutionContext; }
|
||||
}
|
||||
|
||||
|
||||
public Scheduler Scheduler
|
||||
{
|
||||
get { return _scheduler; }
|
||||
}
|
||||
|
||||
public IOProcessor IOP
|
||||
{
|
||||
get { return _iop; }
|
||||
}
|
||||
|
||||
public CentralProcessor CP
|
||||
{
|
||||
get { return _cp; }
|
||||
}
|
||||
|
||||
public MemoryController MemoryController
|
||||
{
|
||||
get { return _memoryController; }
|
||||
}
|
||||
|
||||
public DisplayController DisplayController
|
||||
{
|
||||
get { return _displayController; }
|
||||
}
|
||||
|
||||
public ShugartController ShugartController
|
||||
{
|
||||
get { return _shugartController; }
|
||||
}
|
||||
|
||||
public SA1000Drive HardDrive
|
||||
{
|
||||
get { return _hardDrive; }
|
||||
}
|
||||
|
||||
public EthernetController EthernetController
|
||||
{
|
||||
get { return _ethernetController; }
|
||||
}
|
||||
|
||||
public DWindow Display
|
||||
{
|
||||
get { return _display; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows UI to be alerted when execution state changes
|
||||
/// </summary>
|
||||
public delegate void ExecutionStateChangedDelegate();
|
||||
|
||||
public ExecutionStateChangedDelegate ExecutionStateChanged;
|
||||
|
||||
public void AttachDisplay(DWindow display)
|
||||
{
|
||||
_display = display;
|
||||
}
|
||||
|
||||
public void StartExecution(SystemExecutionContext context)
|
||||
{
|
||||
StopExecution();
|
||||
|
||||
if (_executionThread == null || !_executionThread.IsAlive)
|
||||
{
|
||||
if (context.StepCallback8085 != null &&
|
||||
context.StepCallbackCP != null &&
|
||||
context.StepCallbackMesa != null)
|
||||
{
|
||||
_executionThread = new Thread(new ParameterizedThreadStart(DebugExecutionWorker));
|
||||
}
|
||||
else
|
||||
{
|
||||
_executionThread = new Thread(new ParameterizedThreadStart(ExecutionWorker));
|
||||
}
|
||||
_executionThread.Start(context);
|
||||
|
||||
ExecutionStateChanged();
|
||||
|
||||
_currentExecutionContext = context;
|
||||
}
|
||||
}
|
||||
|
||||
public void StopExecution()
|
||||
{
|
||||
if (_executionThread != null && _executionThread.IsAlive)
|
||||
{
|
||||
_abortExecution = true;
|
||||
_executionThread.Join();
|
||||
|
||||
_executionThread = null;
|
||||
_currentExecutionContext = null;
|
||||
|
||||
ExecutionStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void DebugExecutionWorker(object obj)
|
||||
{
|
||||
SystemExecutionContext context = (SystemExecutionContext)obj;
|
||||
|
||||
_abortExecution = false;
|
||||
bool iopAbort = false;
|
||||
|
||||
while (!_abortExecution)
|
||||
{
|
||||
try
|
||||
{
|
||||
//
|
||||
// We clock the IOP first and let it run an instruction.
|
||||
// This returns the number of clock cycles consumed --
|
||||
// on the 8085's 3Mhz timebase.
|
||||
//
|
||||
// We then execute the corresponding number of CP cycles
|
||||
// (based on a 137ns clock period, or about 7.3Mhz) that would
|
||||
// occur during that period.
|
||||
//
|
||||
if (_cpCycles == 0)
|
||||
{
|
||||
if (iopAbort)
|
||||
{
|
||||
//
|
||||
// Out of cycles after an IOP abort, now we actually abort.
|
||||
//
|
||||
_abortExecution = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i8085Cycles = _iop.Execute();
|
||||
|
||||
// This is inexact and that's probably good enough on average.
|
||||
_cpCycles = (int)_cpCyclesPer8085Cycle * i8085Cycles;
|
||||
|
||||
if (context.StepCallback8085())
|
||||
{
|
||||
//
|
||||
// Set our local iopAbort flag, we still want to continue
|
||||
// to execute the CP and scheduler for as many microcycles as correspond to the
|
||||
// above 8085 instruction's execution time to keep things in sync.
|
||||
//
|
||||
iopAbort = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_cp.ExecuteInstruction(1);
|
||||
_cpCycles--;
|
||||
_elapsedCycles++;
|
||||
|
||||
if (context.StepCallbackCP())
|
||||
{
|
||||
//
|
||||
// Break on microinstruction step
|
||||
//
|
||||
_abortExecution = true;
|
||||
}
|
||||
|
||||
if (_cp.IBDispatch &&
|
||||
context.StepCallbackMesa())
|
||||
{
|
||||
//
|
||||
// Break on macroinstruction step
|
||||
//
|
||||
_abortExecution = true;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
context.ErrorCallback(e);
|
||||
_abortExecution = true;
|
||||
}
|
||||
}
|
||||
|
||||
_cpCycles = 0;
|
||||
|
||||
ExecutionStateChanged();
|
||||
}
|
||||
|
||||
private void ExecutionWorker(object obj)
|
||||
{
|
||||
SystemExecutionContext context = (SystemExecutionContext)obj;
|
||||
|
||||
_abortExecution = false;
|
||||
|
||||
while (!_abortExecution)
|
||||
{
|
||||
try
|
||||
{
|
||||
//
|
||||
// We clock the IOP first and let it run an instruction.
|
||||
// This returns the number of clock cycles consumed --
|
||||
// on the 8085's 3Mhz timebase.
|
||||
//
|
||||
// We then execute the corresponding number of CP cycles
|
||||
// (based on a 137ns clock period, or about 7.3Mhz) that would
|
||||
// occur during that period.
|
||||
//
|
||||
int i8085Cycles = _iop.Execute();
|
||||
|
||||
// This is inexact and that's probably good enough on average.
|
||||
_cpCycles = (int)_cpCyclesPer8085Cycle * i8085Cycles;
|
||||
|
||||
_cp.ExecuteInstruction(_cpCycles);
|
||||
|
||||
if (Configuration.ThrottleSpeed)
|
||||
{
|
||||
_elapsedCycles += _cpCycles;
|
||||
|
||||
if (_elapsedCycles > _cpCyclesPerField)
|
||||
{
|
||||
_elapsedCycles -= _cpCyclesPerField;
|
||||
|
||||
if (_frameTimer != null)
|
||||
{
|
||||
_frameTimer.WaitForFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
context.ErrorCallback(e);
|
||||
_abortExecution = true;
|
||||
}
|
||||
}
|
||||
|
||||
ExecutionStateChanged();
|
||||
}
|
||||
|
||||
//
|
||||
// Devices belonging to this system
|
||||
//
|
||||
private IOProcessor _iop;
|
||||
private CentralProcessor _cp;
|
||||
private MemoryController _memoryController;
|
||||
private DisplayController _displayController;
|
||||
private ShugartController _shugartController;
|
||||
private EthernetController _ethernetController;
|
||||
private SA1000Drive _hardDrive;
|
||||
|
||||
//
|
||||
// Display for rendering
|
||||
//
|
||||
private DWindow _display;
|
||||
|
||||
//
|
||||
// System scheduler
|
||||
private Scheduler _scheduler;
|
||||
|
||||
//
|
||||
// Execution state
|
||||
//
|
||||
private Thread _executionThread;
|
||||
private bool _abortExecution;
|
||||
private int _cpCycles;
|
||||
private double _elapsedCycles;
|
||||
private SystemExecutionContext _currentExecutionContext;
|
||||
|
||||
//
|
||||
// Constants
|
||||
//
|
||||
|
||||
// Ratio of CP cycles per 8085 cycle (appx. 7.3Mhz to 3.0Mhz)
|
||||
private const double _cpCyclesPer8085Cycle = 2.43 * 2.0;
|
||||
|
||||
// Cycles per display field
|
||||
private const double _cpCyclesPerField = 7299270.1 / 38.7;
|
||||
|
||||
private FrameTimer _frameTimer;
|
||||
}
|
||||
}
|
||||
147
D/UI/AboutBox.Designer.cs
generated
Normal file
147
D/UI/AboutBox.Designer.cs
generated
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
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.UI
|
||||
{
|
||||
partial class AboutBox
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.DarkstarVersion = new System.Windows.Forms.Label();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.emailLink = new System.Windows.Forms.LinkLabel();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// DarkstarVersion
|
||||
//
|
||||
this.DarkstarVersion.AutoSize = true;
|
||||
this.DarkstarVersion.Location = new System.Drawing.Point(128, 9);
|
||||
this.DarkstarVersion.Name = "DarkstarVersion";
|
||||
this.DarkstarVersion.Size = new System.Drawing.Size(144, 13);
|
||||
this.DarkstarVersion.TabIndex = 0;
|
||||
this.DarkstarVersion.Text = "Darkstar Version Placeholder";
|
||||
this.DarkstarVersion.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(96, 31);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(139, 13);
|
||||
this.label2.TabIndex = 1;
|
||||
this.label2.Text = "A Xerox Star/1108 Emulator";
|
||||
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(56, 54);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(235, 13);
|
||||
this.label3.TabIndex = 2;
|
||||
this.label3.Text = "(c) 2017, 2018 Living Computers: Museum+Labs";
|
||||
this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.Location = new System.Drawing.Point(67, 79);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(224, 18);
|
||||
this.label4.TabIndex = 5;
|
||||
this.label4.Text = "Bug reports, comments and miscellanea to";
|
||||
//
|
||||
// emailLink
|
||||
//
|
||||
this.emailLink.AutoSize = true;
|
||||
this.emailLink.Location = new System.Drawing.Point(101, 97);
|
||||
this.emailLink.Name = "emailLink";
|
||||
this.emailLink.Size = new System.Drawing.Size(134, 13);
|
||||
this.emailLink.TabIndex = 6;
|
||||
this.emailLink.TabStop = true;
|
||||
this.emailLink.Text = "joshd@livingcomputers.org";
|
||||
this.emailLink.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.emailLink_LinkClicked);
|
||||
//
|
||||
// AboutBox
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(350, 126);
|
||||
this.Controls.Add(this.emailLink);
|
||||
this.Controls.Add(this.label4);
|
||||
this.Controls.Add(this.label3);
|
||||
this.Controls.Add(this.label2);
|
||||
this.Controls.Add(this.DarkstarVersion);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.Margin = new System.Windows.Forms.Padding(2);
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "AboutBox";
|
||||
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "About Darkstar";
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Label DarkstarVersion;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.LinkLabel emailLink;
|
||||
}
|
||||
}
|
||||
48
D/UI/AboutBox.cs
Normal file
48
D/UI/AboutBox.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
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.Reflection;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace D.UI
|
||||
{
|
||||
public partial class AboutBox : Form
|
||||
{
|
||||
public AboutBox()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
DarkstarVersion.Text = string.Format("Darkstar v{0}", typeof(Program).Assembly.GetName().Version);
|
||||
}
|
||||
|
||||
private void emailLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
System.Diagnostics.Process.Start("mailto:joshd@livingcomputers.org");
|
||||
}
|
||||
}
|
||||
}
|
||||
120
D/UI/AboutBox.resx
Normal file
120
D/UI/AboutBox.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
427
D/UI/ConfigurationDialog.Designer.cs
generated
Normal file
427
D/UI/ConfigurationDialog.Designer.cs
generated
Normal file
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
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.UI
|
||||
{
|
||||
partial class ConfigurationDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.TabControl = new System.Windows.Forms.TabControl();
|
||||
this.SystemPage = new System.Windows.Forms.TabPage();
|
||||
this.ThrottleSpeedCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.HostIDTextBox = new System.Windows.Forms.TextBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.MemorySizeComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.EthernetTab = new System.Windows.Forms.TabPage();
|
||||
this.EthernetInterfaceListBox = new System.Windows.Forms.ListBox();
|
||||
this.label5 = new System.Windows.Forms.Label();
|
||||
this.DisplayTab = new System.Windows.Forms.TabPage();
|
||||
this.DisplayScaleComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.SlowPhosphorCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.TimeTabPage = new System.Windows.Forms.TabPage();
|
||||
this.TODDateTimePicker = new System.Windows.Forms.DateTimePicker();
|
||||
this.SpecifiedTimeDateRadioButton = new System.Windows.Forms.RadioButton();
|
||||
this.CurrentTimeDateY2KRadioButton = new System.Windows.Forms.RadioButton();
|
||||
this.CurrentTimeDateRadioButton = new System.Windows.Forms.RadioButton();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.OKButton = new System.Windows.Forms.Button();
|
||||
this.Cancel_Button = new System.Windows.Forms.Button();
|
||||
this.NoTimeDateChangeRadioButton = new System.Windows.Forms.RadioButton();
|
||||
this.SpecifiedDateRadioButton = new System.Windows.Forms.RadioButton();
|
||||
this.TODDatePicker = new System.Windows.Forms.DateTimePicker();
|
||||
this.TabControl.SuspendLayout();
|
||||
this.SystemPage.SuspendLayout();
|
||||
this.EthernetTab.SuspendLayout();
|
||||
this.DisplayTab.SuspendLayout();
|
||||
this.TimeTabPage.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// TabControl
|
||||
//
|
||||
this.TabControl.Controls.Add(this.SystemPage);
|
||||
this.TabControl.Controls.Add(this.EthernetTab);
|
||||
this.TabControl.Controls.Add(this.DisplayTab);
|
||||
this.TabControl.Controls.Add(this.TimeTabPage);
|
||||
this.TabControl.Location = new System.Drawing.Point(7, 8);
|
||||
this.TabControl.Name = "TabControl";
|
||||
this.TabControl.SelectedIndex = 0;
|
||||
this.TabControl.Size = new System.Drawing.Size(356, 195);
|
||||
this.TabControl.TabIndex = 0;
|
||||
//
|
||||
// SystemPage
|
||||
//
|
||||
this.SystemPage.Controls.Add(this.ThrottleSpeedCheckBox);
|
||||
this.SystemPage.Controls.Add(this.HostIDTextBox);
|
||||
this.SystemPage.Controls.Add(this.label2);
|
||||
this.SystemPage.Controls.Add(this.MemorySizeComboBox);
|
||||
this.SystemPage.Controls.Add(this.label1);
|
||||
this.SystemPage.Location = new System.Drawing.Point(4, 22);
|
||||
this.SystemPage.Name = "SystemPage";
|
||||
this.SystemPage.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.SystemPage.Size = new System.Drawing.Size(348, 169);
|
||||
this.SystemPage.TabIndex = 0;
|
||||
this.SystemPage.Text = "System";
|
||||
this.SystemPage.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ThrottleSpeedCheckBox
|
||||
//
|
||||
this.ThrottleSpeedCheckBox.AutoSize = true;
|
||||
this.ThrottleSpeedCheckBox.Location = new System.Drawing.Point(9, 53);
|
||||
this.ThrottleSpeedCheckBox.Name = "ThrottleSpeedCheckBox";
|
||||
this.ThrottleSpeedCheckBox.Size = new System.Drawing.Size(146, 17);
|
||||
this.ThrottleSpeedCheckBox.TabIndex = 4;
|
||||
this.ThrottleSpeedCheckBox.Text = "Throttle Execution Speed";
|
||||
this.ThrottleSpeedCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// HostIDTextBox
|
||||
//
|
||||
this.HostIDTextBox.Location = new System.Drawing.Point(133, 27);
|
||||
this.HostIDTextBox.Name = "HostIDTextBox";
|
||||
this.HostIDTextBox.Size = new System.Drawing.Size(98, 20);
|
||||
this.HostIDTextBox.TabIndex = 3;
|
||||
this.HostIDTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.OnHostIDValidating);
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(6, 30);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(119, 13);
|
||||
this.label2.TabIndex = 2;
|
||||
this.label2.Text = "Host ID (MAC Address):";
|
||||
//
|
||||
// MemorySizeComboBox
|
||||
//
|
||||
this.MemorySizeComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.MemorySizeComboBox.FormattingEnabled = true;
|
||||
this.MemorySizeComboBox.Items.AddRange(new object[] {
|
||||
"1024",
|
||||
"768",
|
||||
"512",
|
||||
"256",
|
||||
"128"});
|
||||
this.MemorySizeComboBox.Location = new System.Drawing.Point(110, 3);
|
||||
this.MemorySizeComboBox.Name = "MemorySizeComboBox";
|
||||
this.MemorySizeComboBox.Size = new System.Drawing.Size(121, 21);
|
||||
this.MemorySizeComboBox.TabIndex = 1;
|
||||
this.MemorySizeComboBox.SelectionChangeCommitted += new System.EventHandler(this.OnMemorySizeChanged);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(6, 7);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(97, 13);
|
||||
this.label1.TabIndex = 0;
|
||||
this.label1.Text = "Memory Size (KW):";
|
||||
//
|
||||
// EthernetTab
|
||||
//
|
||||
this.EthernetTab.Controls.Add(this.EthernetInterfaceListBox);
|
||||
this.EthernetTab.Controls.Add(this.label5);
|
||||
this.EthernetTab.Location = new System.Drawing.Point(4, 22);
|
||||
this.EthernetTab.Name = "EthernetTab";
|
||||
this.EthernetTab.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.EthernetTab.Size = new System.Drawing.Size(348, 169);
|
||||
this.EthernetTab.TabIndex = 1;
|
||||
this.EthernetTab.Text = "Ethernet";
|
||||
this.EthernetTab.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// EthernetInterfaceListBox
|
||||
//
|
||||
this.EthernetInterfaceListBox.FormattingEnabled = true;
|
||||
this.EthernetInterfaceListBox.Location = new System.Drawing.Point(10, 24);
|
||||
this.EthernetInterfaceListBox.Name = "EthernetInterfaceListBox";
|
||||
this.EthernetInterfaceListBox.Size = new System.Drawing.Size(332, 134);
|
||||
this.EthernetInterfaceListBox.TabIndex = 1;
|
||||
//
|
||||
// label5
|
||||
//
|
||||
this.label5.AutoSize = true;
|
||||
this.label5.Location = new System.Drawing.Point(7, 7);
|
||||
this.label5.Name = "label5";
|
||||
this.label5.Size = new System.Drawing.Size(240, 13);
|
||||
this.label5.TabIndex = 0;
|
||||
this.label5.Text = "Select the network interface to use with Darkstar:";
|
||||
//
|
||||
// DisplayTab
|
||||
//
|
||||
this.DisplayTab.Controls.Add(this.DisplayScaleComboBox);
|
||||
this.DisplayTab.Controls.Add(this.label3);
|
||||
this.DisplayTab.Controls.Add(this.SlowPhosphorCheckBox);
|
||||
this.DisplayTab.Location = new System.Drawing.Point(4, 22);
|
||||
this.DisplayTab.Name = "DisplayTab";
|
||||
this.DisplayTab.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.DisplayTab.Size = new System.Drawing.Size(348, 169);
|
||||
this.DisplayTab.TabIndex = 2;
|
||||
this.DisplayTab.Text = "Display";
|
||||
this.DisplayTab.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// DisplayScaleComboBox
|
||||
//
|
||||
this.DisplayScaleComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.DisplayScaleComboBox.FormattingEnabled = true;
|
||||
this.DisplayScaleComboBox.Items.AddRange(new object[] {
|
||||
"1x",
|
||||
"2x",
|
||||
"4x"});
|
||||
this.DisplayScaleComboBox.Location = new System.Drawing.Point(84, 28);
|
||||
this.DisplayScaleComboBox.Name = "DisplayScaleComboBox";
|
||||
this.DisplayScaleComboBox.Size = new System.Drawing.Size(55, 21);
|
||||
this.DisplayScaleComboBox.TabIndex = 2;
|
||||
this.DisplayScaleComboBox.SelectionChangeCommitted += new System.EventHandler(this.OnDisplayScaleChanged);
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(7, 31);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(71, 13);
|
||||
this.label3.TabIndex = 1;
|
||||
this.label3.Text = "Display Scale";
|
||||
//
|
||||
// SlowPhosphorCheckBox
|
||||
//
|
||||
this.SlowPhosphorCheckBox.AutoSize = true;
|
||||
this.SlowPhosphorCheckBox.Location = new System.Drawing.Point(7, 7);
|
||||
this.SlowPhosphorCheckBox.Name = "SlowPhosphorCheckBox";
|
||||
this.SlowPhosphorCheckBox.Size = new System.Drawing.Size(148, 17);
|
||||
this.SlowPhosphorCheckBox.TabIndex = 0;
|
||||
this.SlowPhosphorCheckBox.Text = "Slow Phosphor Simulation";
|
||||
this.SlowPhosphorCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// TimeTabPage
|
||||
//
|
||||
this.TimeTabPage.Controls.Add(this.TODDatePicker);
|
||||
this.TimeTabPage.Controls.Add(this.SpecifiedDateRadioButton);
|
||||
this.TimeTabPage.Controls.Add(this.NoTimeDateChangeRadioButton);
|
||||
this.TimeTabPage.Controls.Add(this.TODDateTimePicker);
|
||||
this.TimeTabPage.Controls.Add(this.SpecifiedTimeDateRadioButton);
|
||||
this.TimeTabPage.Controls.Add(this.CurrentTimeDateY2KRadioButton);
|
||||
this.TimeTabPage.Controls.Add(this.CurrentTimeDateRadioButton);
|
||||
this.TimeTabPage.Controls.Add(this.label4);
|
||||
this.TimeTabPage.Location = new System.Drawing.Point(4, 22);
|
||||
this.TimeTabPage.Name = "TimeTabPage";
|
||||
this.TimeTabPage.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.TimeTabPage.Size = new System.Drawing.Size(348, 169);
|
||||
this.TimeTabPage.TabIndex = 3;
|
||||
this.TimeTabPage.Text = "Time";
|
||||
this.TimeTabPage.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// TODDateTimePicker
|
||||
//
|
||||
this.TODDateTimePicker.CustomFormat = "MM\'/\'dd\'/\'yyyy HH\':\'mm\':\'ss";
|
||||
this.TODDateTimePicker.Format = System.Windows.Forms.DateTimePickerFormat.Custom;
|
||||
this.TODDateTimePicker.Location = new System.Drawing.Point(136, 70);
|
||||
this.TODDateTimePicker.Name = "TODDateTimePicker";
|
||||
this.TODDateTimePicker.ShowUpDown = true;
|
||||
this.TODDateTimePicker.Size = new System.Drawing.Size(200, 20);
|
||||
this.TODDateTimePicker.TabIndex = 4;
|
||||
//
|
||||
// SpecifiedTimeDateRadioButton
|
||||
//
|
||||
this.SpecifiedTimeDateRadioButton.AutoSize = true;
|
||||
this.SpecifiedTimeDateRadioButton.Location = new System.Drawing.Point(10, 70);
|
||||
this.SpecifiedTimeDateRadioButton.Name = "SpecifiedTimeDateRadioButton";
|
||||
this.SpecifiedTimeDateRadioButton.Size = new System.Drawing.Size(120, 17);
|
||||
this.SpecifiedTimeDateRadioButton.TabIndex = 3;
|
||||
this.SpecifiedTimeDateRadioButton.TabStop = true;
|
||||
this.SpecifiedTimeDateRadioButton.Text = "Specified date/time:";
|
||||
this.SpecifiedTimeDateRadioButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// CurrentTimeDateY2KRadioButton
|
||||
//
|
||||
this.CurrentTimeDateY2KRadioButton.AutoSize = true;
|
||||
this.CurrentTimeDateY2KRadioButton.Location = new System.Drawing.Point(10, 47);
|
||||
this.CurrentTimeDateY2KRadioButton.Name = "CurrentTimeDateY2KRadioButton";
|
||||
this.CurrentTimeDateY2KRadioButton.Size = new System.Drawing.Size(273, 17);
|
||||
this.CurrentTimeDateY2KRadioButton.TabIndex = 2;
|
||||
this.CurrentTimeDateY2KRadioButton.TabStop = true;
|
||||
this.CurrentTimeDateY2KRadioButton.Text = "Current time/date with Y2K compensation (-28 years)";
|
||||
this.CurrentTimeDateY2KRadioButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// CurrentTimeDateRadioButton
|
||||
//
|
||||
this.CurrentTimeDateRadioButton.AutoSize = true;
|
||||
this.CurrentTimeDateRadioButton.Location = new System.Drawing.Point(10, 24);
|
||||
this.CurrentTimeDateRadioButton.Name = "CurrentTimeDateRadioButton";
|
||||
this.CurrentTimeDateRadioButton.Size = new System.Drawing.Size(107, 17);
|
||||
this.CurrentTimeDateRadioButton.TabIndex = 1;
|
||||
this.CurrentTimeDateRadioButton.TabStop = true;
|
||||
this.CurrentTimeDateRadioButton.Text = "Current time/date";
|
||||
this.CurrentTimeDateRadioButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Location = new System.Drawing.Point(7, 7);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(228, 13);
|
||||
this.label4.TabIndex = 0;
|
||||
this.label4.Text = "At power up/reset, set emulated TOD clock to:";
|
||||
//
|
||||
// OKButton
|
||||
//
|
||||
this.OKButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.OKButton.Location = new System.Drawing.Point(207, 209);
|
||||
this.OKButton.Name = "OKButton";
|
||||
this.OKButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.OKButton.TabIndex = 1;
|
||||
this.OKButton.Text = "OK";
|
||||
this.OKButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Cancel_Button
|
||||
//
|
||||
this.Cancel_Button.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.Cancel_Button.Location = new System.Drawing.Point(288, 209);
|
||||
this.Cancel_Button.Name = "Cancel_Button";
|
||||
this.Cancel_Button.Size = new System.Drawing.Size(75, 23);
|
||||
this.Cancel_Button.TabIndex = 2;
|
||||
this.Cancel_Button.Text = "Cancel";
|
||||
this.Cancel_Button.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// NoTimeDateChangeRadioButton
|
||||
//
|
||||
this.NoTimeDateChangeRadioButton.AutoSize = true;
|
||||
this.NoTimeDateChangeRadioButton.Location = new System.Drawing.Point(10, 119);
|
||||
this.NoTimeDateChangeRadioButton.Name = "NoTimeDateChangeRadioButton";
|
||||
this.NoTimeDateChangeRadioButton.Size = new System.Drawing.Size(205, 17);
|
||||
this.NoTimeDateChangeRadioButton.TabIndex = 5;
|
||||
this.NoTimeDateChangeRadioButton.TabStop = true;
|
||||
this.NoTimeDateChangeRadioButton.Text = "No change (do not modify TOD clock)";
|
||||
this.NoTimeDateChangeRadioButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// SpecifiedDateRadioButton
|
||||
//
|
||||
this.SpecifiedDateRadioButton.AutoSize = true;
|
||||
this.SpecifiedDateRadioButton.Location = new System.Drawing.Point(10, 93);
|
||||
this.SpecifiedDateRadioButton.Name = "SpecifiedDateRadioButton";
|
||||
this.SpecifiedDateRadioButton.Size = new System.Drawing.Size(118, 17);
|
||||
this.SpecifiedDateRadioButton.TabIndex = 6;
|
||||
this.SpecifiedDateRadioButton.TabStop = true;
|
||||
this.SpecifiedDateRadioButton.Text = "Specified date only:";
|
||||
this.SpecifiedDateRadioButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// TODDatePicker
|
||||
//
|
||||
this.TODDatePicker.CustomFormat = "MM\'/\'dd\'/\'yyyy";
|
||||
this.TODDatePicker.Format = System.Windows.Forms.DateTimePickerFormat.Custom;
|
||||
this.TODDatePicker.Location = new System.Drawing.Point(136, 93);
|
||||
this.TODDatePicker.Name = "TODDatePicker";
|
||||
this.TODDatePicker.ShowUpDown = true;
|
||||
this.TODDatePicker.Size = new System.Drawing.Size(200, 20);
|
||||
this.TODDatePicker.TabIndex = 7;
|
||||
//
|
||||
// ConfigurationDialog
|
||||
//
|
||||
this.AcceptButton = this.OKButton;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(367, 238);
|
||||
this.Controls.Add(this.Cancel_Button);
|
||||
this.Controls.Add(this.OKButton);
|
||||
this.Controls.Add(this.TabControl);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "ConfigurationDialog";
|
||||
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "System Configuration";
|
||||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.OnClosed);
|
||||
this.Load += new System.EventHandler(this.OnLoad);
|
||||
this.TabControl.ResumeLayout(false);
|
||||
this.SystemPage.ResumeLayout(false);
|
||||
this.SystemPage.PerformLayout();
|
||||
this.EthernetTab.ResumeLayout(false);
|
||||
this.EthernetTab.PerformLayout();
|
||||
this.DisplayTab.ResumeLayout(false);
|
||||
this.DisplayTab.PerformLayout();
|
||||
this.TimeTabPage.ResumeLayout(false);
|
||||
this.TimeTabPage.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TabControl TabControl;
|
||||
private System.Windows.Forms.TabPage SystemPage;
|
||||
private System.Windows.Forms.TabPage EthernetTab;
|
||||
private System.Windows.Forms.TabPage DisplayTab;
|
||||
private System.Windows.Forms.ComboBox MemorySizeComboBox;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.TextBox HostIDTextBox;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.ComboBox DisplayScaleComboBox;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.CheckBox SlowPhosphorCheckBox;
|
||||
private System.Windows.Forms.Button OKButton;
|
||||
private System.Windows.Forms.Button Cancel_Button;
|
||||
private System.Windows.Forms.CheckBox ThrottleSpeedCheckBox;
|
||||
private System.Windows.Forms.TabPage TimeTabPage;
|
||||
private System.Windows.Forms.DateTimePicker TODDateTimePicker;
|
||||
private System.Windows.Forms.RadioButton SpecifiedTimeDateRadioButton;
|
||||
private System.Windows.Forms.RadioButton CurrentTimeDateY2KRadioButton;
|
||||
private System.Windows.Forms.RadioButton CurrentTimeDateRadioButton;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.Label label5;
|
||||
private System.Windows.Forms.ListBox EthernetInterfaceListBox;
|
||||
private System.Windows.Forms.RadioButton NoTimeDateChangeRadioButton;
|
||||
private System.Windows.Forms.DateTimePicker TODDatePicker;
|
||||
private System.Windows.Forms.RadioButton SpecifiedDateRadioButton;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user