mirror of
https://github.com/livingcomputermuseum/ContrAlto.git
synced 2026-02-22 15:18:06 +00:00
Refactored drive logic (mostly) to allow for multiple drives. Fixed drive selection logic. Started work on "real" UI.
This commit is contained in:
@@ -65,14 +65,11 @@ namespace Contralto
|
||||
|
||||
/// <summary>
|
||||
/// Attaches an emulated display device to the system.
|
||||
/// TODO: This is currently tightly-coupled with the Debugger, make
|
||||
/// more general.
|
||||
/// </summary>
|
||||
/// <param name="d"></param>
|
||||
public void AttachDisplay(Debugger d)
|
||||
public void AttachDisplay(IAltoDisplay d)
|
||||
{
|
||||
_displayController.AttachDisplay(d);
|
||||
// _fakeDisplayController.AttachDisplay(d);
|
||||
_displayController.AttachDisplay(d);
|
||||
}
|
||||
|
||||
public void SingleStep()
|
||||
|
||||
263
Contralto/AltoWindow.Designer.cs
generated
Normal file
263
Contralto/AltoWindow.Designer.cs
generated
Normal file
@@ -0,0 +1,263 @@
|
||||
namespace Contralto
|
||||
{
|
||||
partial class AltoWindow
|
||||
{
|
||||
/// <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.DisplayBox = new System.Windows.Forms.PictureBox();
|
||||
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
|
||||
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SystemStartMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SystemResetMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.drive0ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.loadToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.unloadToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.drive1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.loadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.unloadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.debuggerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.showDebuggerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.StatusLine = new System.Windows.Forms.StatusStrip();
|
||||
this.StatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
((System.ComponentModel.ISupportInitialize)(this.DisplayBox)).BeginInit();
|
||||
this.menuStrip1.SuspendLayout();
|
||||
this.StatusLine.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// DisplayBox
|
||||
//
|
||||
this.DisplayBox.BackColor = System.Drawing.SystemColors.Window;
|
||||
this.DisplayBox.Location = new System.Drawing.Point(0, 27);
|
||||
this.DisplayBox.Name = "DisplayBox";
|
||||
this.DisplayBox.Size = new System.Drawing.Size(606, 808);
|
||||
this.DisplayBox.TabIndex = 1;
|
||||
this.DisplayBox.TabStop = false;
|
||||
this.DisplayBox.MouseDown += new System.Windows.Forms.MouseEventHandler(this.OnDisplayMouseDown);
|
||||
this.DisplayBox.MouseMove += new System.Windows.Forms.MouseEventHandler(this.OnDisplayMouseMove);
|
||||
this.DisplayBox.MouseUp += new System.Windows.Forms.MouseEventHandler(this.OnDisplayMouseUp);
|
||||
//
|
||||
// menuStrip1
|
||||
//
|
||||
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.fileToolStripMenuItem,
|
||||
this.settingsToolStripMenuItem,
|
||||
this.debuggerToolStripMenuItem,
|
||||
this.helpToolStripMenuItem});
|
||||
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
|
||||
this.menuStrip1.Name = "menuStrip1";
|
||||
this.menuStrip1.Size = new System.Drawing.Size(608, 24);
|
||||
this.menuStrip1.TabIndex = 2;
|
||||
this.menuStrip1.Text = "menuStrip1";
|
||||
//
|
||||
// fileToolStripMenuItem
|
||||
//
|
||||
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.exitToolStripMenuItem});
|
||||
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
|
||||
this.fileToolStripMenuItem.Size = new System.Drawing.Size(35, 20);
|
||||
this.fileToolStripMenuItem.Text = "File";
|
||||
//
|
||||
// exitToolStripMenuItem
|
||||
//
|
||||
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
|
||||
this.exitToolStripMenuItem.Size = new System.Drawing.Size(92, 22);
|
||||
this.exitToolStripMenuItem.Text = "Exit";
|
||||
//
|
||||
// settingsToolStripMenuItem
|
||||
//
|
||||
this.settingsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.SystemStartMenuItem,
|
||||
this.SystemResetMenuItem,
|
||||
this.drive0ToolStripMenuItem,
|
||||
this.drive1ToolStripMenuItem,
|
||||
this.optionsToolStripMenuItem});
|
||||
this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
|
||||
this.settingsToolStripMenuItem.Size = new System.Drawing.Size(54, 20);
|
||||
this.settingsToolStripMenuItem.Text = "System";
|
||||
//
|
||||
// SystemStartMenuItem
|
||||
//
|
||||
this.SystemStartMenuItem.Name = "SystemStartMenuItem";
|
||||
this.SystemStartMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.SystemStartMenuItem.Text = "Start";
|
||||
this.SystemStartMenuItem.Click += new System.EventHandler(this.OnSystemStartMenuClick);
|
||||
//
|
||||
// SystemResetMenuItem
|
||||
//
|
||||
this.SystemResetMenuItem.Enabled = false;
|
||||
this.SystemResetMenuItem.Name = "SystemResetMenuItem";
|
||||
this.SystemResetMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.SystemResetMenuItem.Text = "Reset";
|
||||
//
|
||||
// drive0ToolStripMenuItem
|
||||
//
|
||||
this.drive0ToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.loadToolStripMenuItem1,
|
||||
this.unloadToolStripMenuItem1});
|
||||
this.drive0ToolStripMenuItem.Name = "drive0ToolStripMenuItem";
|
||||
this.drive0ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.drive0ToolStripMenuItem.Text = "Drive 0";
|
||||
//
|
||||
// loadToolStripMenuItem1
|
||||
//
|
||||
this.loadToolStripMenuItem1.Name = "loadToolStripMenuItem1";
|
||||
this.loadToolStripMenuItem1.Size = new System.Drawing.Size(119, 22);
|
||||
this.loadToolStripMenuItem1.Text = "Load...";
|
||||
//
|
||||
// unloadToolStripMenuItem1
|
||||
//
|
||||
this.unloadToolStripMenuItem1.Name = "unloadToolStripMenuItem1";
|
||||
this.unloadToolStripMenuItem1.Size = new System.Drawing.Size(119, 22);
|
||||
this.unloadToolStripMenuItem1.Text = "Unload...";
|
||||
//
|
||||
// drive1ToolStripMenuItem
|
||||
//
|
||||
this.drive1ToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.loadToolStripMenuItem,
|
||||
this.unloadToolStripMenuItem});
|
||||
this.drive1ToolStripMenuItem.Name = "drive1ToolStripMenuItem";
|
||||
this.drive1ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.drive1ToolStripMenuItem.Text = "Drive 1";
|
||||
//
|
||||
// loadToolStripMenuItem
|
||||
//
|
||||
this.loadToolStripMenuItem.Name = "loadToolStripMenuItem";
|
||||
this.loadToolStripMenuItem.Size = new System.Drawing.Size(119, 22);
|
||||
this.loadToolStripMenuItem.Text = "Load...";
|
||||
//
|
||||
// unloadToolStripMenuItem
|
||||
//
|
||||
this.unloadToolStripMenuItem.Name = "unloadToolStripMenuItem";
|
||||
this.unloadToolStripMenuItem.Size = new System.Drawing.Size(119, 22);
|
||||
this.unloadToolStripMenuItem.Text = "Unload...";
|
||||
//
|
||||
// optionsToolStripMenuItem
|
||||
//
|
||||
this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem";
|
||||
this.optionsToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.optionsToolStripMenuItem.Text = "Options...";
|
||||
//
|
||||
// debuggerToolStripMenuItem
|
||||
//
|
||||
this.debuggerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.showDebuggerToolStripMenuItem});
|
||||
this.debuggerToolStripMenuItem.Name = "debuggerToolStripMenuItem";
|
||||
this.debuggerToolStripMenuItem.Size = new System.Drawing.Size(66, 20);
|
||||
this.debuggerToolStripMenuItem.Text = "Debugger";
|
||||
//
|
||||
// showDebuggerToolStripMenuItem
|
||||
//
|
||||
this.showDebuggerToolStripMenuItem.Name = "showDebuggerToolStripMenuItem";
|
||||
this.showDebuggerToolStripMenuItem.Size = new System.Drawing.Size(150, 22);
|
||||
this.showDebuggerToolStripMenuItem.Text = "Show Debugger";
|
||||
//
|
||||
// helpToolStripMenuItem
|
||||
//
|
||||
this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.aboutToolStripMenuItem});
|
||||
this.helpToolStripMenuItem.Name = "helpToolStripMenuItem";
|
||||
this.helpToolStripMenuItem.Size = new System.Drawing.Size(40, 20);
|
||||
this.helpToolStripMenuItem.Text = "Help";
|
||||
//
|
||||
// aboutToolStripMenuItem
|
||||
//
|
||||
this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem";
|
||||
this.aboutToolStripMenuItem.Size = new System.Drawing.Size(103, 22);
|
||||
this.aboutToolStripMenuItem.Text = "About";
|
||||
//
|
||||
// StatusLine
|
||||
//
|
||||
this.StatusLine.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.StatusLabel});
|
||||
this.StatusLine.Location = new System.Drawing.Point(0, 837);
|
||||
this.StatusLine.Name = "StatusLine";
|
||||
this.StatusLine.Size = new System.Drawing.Size(608, 22);
|
||||
this.StatusLine.TabIndex = 3;
|
||||
this.StatusLine.Text = "statusStrip1";
|
||||
this.StatusLine.KeyDown += new System.Windows.Forms.KeyEventHandler(this.OnKeyDown);
|
||||
//
|
||||
// StatusLabel
|
||||
//
|
||||
this.StatusLabel.Name = "StatusLabel";
|
||||
this.StatusLabel.Size = new System.Drawing.Size(63, 17);
|
||||
this.StatusLabel.Text = "StatusLabel";
|
||||
//
|
||||
// AltoWindow
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(608, 859);
|
||||
this.Controls.Add(this.StatusLine);
|
||||
this.Controls.Add(this.DisplayBox);
|
||||
this.Controls.Add(this.menuStrip1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.MainMenuStrip = this.menuStrip1;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "AltoWindow";
|
||||
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
|
||||
this.Text = "ContrAlto";
|
||||
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.OnKeyDown);
|
||||
this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.OnKeyUp);
|
||||
((System.ComponentModel.ISupportInitialize)(this.DisplayBox)).EndInit();
|
||||
this.menuStrip1.ResumeLayout(false);
|
||||
this.menuStrip1.PerformLayout();
|
||||
this.StatusLine.ResumeLayout(false);
|
||||
this.StatusLine.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.PictureBox DisplayBox;
|
||||
private System.Windows.Forms.MenuStrip menuStrip1;
|
||||
private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem aboutToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem SystemStartMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem SystemResetMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem drive0ToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem loadToolStripMenuItem1;
|
||||
private System.Windows.Forms.ToolStripMenuItem unloadToolStripMenuItem1;
|
||||
private System.Windows.Forms.ToolStripMenuItem drive1ToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem loadToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem unloadToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem optionsToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem debuggerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem showDebuggerToolStripMenuItem;
|
||||
private System.Windows.Forms.StatusStrip StatusLine;
|
||||
private System.Windows.Forms.ToolStripStatusLabel StatusLabel;
|
||||
}
|
||||
}
|
||||
126
Contralto/AltoWindow.resx
Normal file
126
Contralto/AltoWindow.resx
Normal file
@@ -0,0 +1,126 @@
|
||||
<?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>
|
||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="StatusLine.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>126, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -64,6 +64,12 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AltoSystem.cs" />
|
||||
<Compile Include="AltoWindow.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="AltoWindow.Designer.cs">
|
||||
<DependentUpon>AltoWindow.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="CPU\ALU.cs" />
|
||||
<Compile Include="CPU\ConstantMemory.cs" />
|
||||
<Compile Include="CPU\CPU.cs" />
|
||||
@@ -88,7 +94,9 @@
|
||||
</Compile>
|
||||
<Compile Include="Display\FakeDisplayController.cs" />
|
||||
<Compile Include="Display\DisplayController.cs" />
|
||||
<Compile Include="Display\IAltoDisplay.cs" />
|
||||
<Compile Include="IClockable.cs" />
|
||||
<Compile Include="IO\Diablo30Drive.cs" />
|
||||
<Compile Include="IO\DiskController.cs" />
|
||||
<Compile Include="IO\DiabloPack.cs" />
|
||||
<Compile Include="IO\Keyboard.cs" />
|
||||
@@ -114,6 +122,9 @@
|
||||
<None Include="Disk\bcpl.dsk">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Disk\bravox.dsk">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Disk\Clark-Games.dsk">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
@@ -260,6 +271,9 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="AltoWindow.resx">
|
||||
<DependentUpon>AltoWindow.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger.resx">
|
||||
<DependentUpon>Debugger.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
||||
@@ -12,13 +12,14 @@ using Contralto.CPU;
|
||||
using System.Threading;
|
||||
using System.Drawing.Imaging;
|
||||
using Contralto.IO;
|
||||
using Contralto.Display;
|
||||
|
||||
namespace Contralto
|
||||
{
|
||||
/// <summary>
|
||||
/// A basic & hacky debugger. To be improved.
|
||||
/// </summary>
|
||||
public partial class Debugger : Form
|
||||
public partial class Debugger : Form, IAltoDisplay
|
||||
{
|
||||
public Debugger(AltoSystem system)
|
||||
{
|
||||
@@ -76,7 +77,7 @@ namespace Contralto
|
||||
RefreshUI();
|
||||
}
|
||||
|
||||
public void RefreshAltoDisplay()
|
||||
public void Render()
|
||||
{
|
||||
BeginInvoke(new StepDelegate(RefreshDisplayBox));
|
||||
}
|
||||
|
||||
BIN
Contralto/Disk/bravox.dsk
Normal file
BIN
Contralto/Disk/bravox.dsk
Normal file
Binary file not shown.
@@ -16,7 +16,7 @@ namespace Contralto.Display
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void AttachDisplay(Debugger display)
|
||||
public void AttachDisplay(IAltoDisplay display)
|
||||
{
|
||||
_display = display;
|
||||
}
|
||||
@@ -207,7 +207,7 @@ namespace Contralto.Display
|
||||
// Done with field.
|
||||
|
||||
// Draw the completed field to the emulated display.
|
||||
_display.RefreshAltoDisplay();
|
||||
_display.Render();
|
||||
|
||||
// And start over
|
||||
FieldStart();
|
||||
@@ -370,7 +370,7 @@ namespace Contralto.Display
|
||||
private Queue<ushort> _dataBuffer = new Queue<ushort>(16);
|
||||
|
||||
private AltoSystem _system;
|
||||
private Debugger _display;
|
||||
private IAltoDisplay _display;
|
||||
|
||||
private int _fields;
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
_clocks -= _frameClocks;
|
||||
|
||||
RenderDisplay();
|
||||
_display.RefreshAltoDisplay();
|
||||
_display.Render();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
_display.RefreshAltoDisplay();
|
||||
_display.Render();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
_display.DrawDisplayWord(scanline, wordOffset, (ushort)(dcb.whiteOnBlack ? 0x0 : 0xffff), false);
|
||||
}
|
||||
|
||||
_display.RefreshAltoDisplay();
|
||||
_display.Render();
|
||||
|
||||
// decrement scan line counter for this DCB, if < 0, grab next DCB.
|
||||
dcb.scanlineCount--;
|
||||
@@ -144,7 +144,7 @@
|
||||
private double _clocks;
|
||||
|
||||
private AltoSystem _system;
|
||||
private Debugger _display;
|
||||
private IAltoDisplay _display;
|
||||
|
||||
// Timing constants
|
||||
// 38uS per scanline; 4uS for hblank.
|
||||
|
||||
25
Contralto/Display/IAltoDisplay.cs
Normal file
25
Contralto/Display/IAltoDisplay.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Contralto.Display
|
||||
{
|
||||
public interface IAltoDisplay
|
||||
{
|
||||
/// <summary>
|
||||
/// Renders a word's worth of data to the specified scanline and word offset.
|
||||
/// </summary>
|
||||
/// <param name="scanline"></param>
|
||||
/// <param name="wordOffset"></param>
|
||||
/// <param name="dataWord"></param>
|
||||
/// <param name="lowRes"></param>
|
||||
void DrawDisplayWord(int scanline, int wordOffset, ushort dataWord, bool lowRes);
|
||||
|
||||
/// <summary>
|
||||
/// Causes the display to be rendered
|
||||
/// </summary>
|
||||
void Render();
|
||||
}
|
||||
}
|
||||
328
Contralto/IO/Diablo30Drive.cs
Normal file
328
Contralto/IO/Diablo30Drive.cs
Normal file
@@ -0,0 +1,328 @@
|
||||
using Contralto.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Contralto.IO
|
||||
{
|
||||
|
||||
// The data for the current sector
|
||||
public enum CellType
|
||||
{
|
||||
Data,
|
||||
Gap,
|
||||
Sync,
|
||||
}
|
||||
|
||||
public struct DataCell
|
||||
{
|
||||
public DataCell(ushort data, CellType type)
|
||||
{
|
||||
Data = data;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public ushort Data;
|
||||
public CellType Type;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0} {1}", Data, Type);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encapsulates logic that belongs to the drive, including loading/saving packs,
|
||||
/// seeking and reading sector data.
|
||||
/// </summary>
|
||||
public class Diablo30Drive
|
||||
{
|
||||
public Diablo30Drive(AltoSystem system)
|
||||
{
|
||||
_system = system;
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_sector = 0;
|
||||
_cylinder = 0;
|
||||
_head = 0;
|
||||
|
||||
InitSector();
|
||||
LoadSector();
|
||||
}
|
||||
|
||||
public void LoadPack(DiabloPack pack)
|
||||
{
|
||||
_pack = pack;
|
||||
}
|
||||
|
||||
public void UnloadPack()
|
||||
{
|
||||
_pack = null;
|
||||
}
|
||||
|
||||
public bool IsLoaded()
|
||||
{
|
||||
return _pack != null;
|
||||
}
|
||||
|
||||
public int Sector
|
||||
{
|
||||
get { return _sector; }
|
||||
set
|
||||
{
|
||||
// If the last sector was modified,
|
||||
// commit it before moving to the next.
|
||||
if (_sectorModified)
|
||||
{
|
||||
CommitSector();
|
||||
_sectorModified = false;
|
||||
}
|
||||
|
||||
_sector = value;
|
||||
LoadSector();
|
||||
}
|
||||
}
|
||||
|
||||
public int Head
|
||||
{
|
||||
get { return _head; }
|
||||
set
|
||||
{
|
||||
if (value != _head)
|
||||
{
|
||||
// If we switch heads, we need to reload the sector.
|
||||
|
||||
// If the last sector was modified,
|
||||
// commit it before moving to the next.
|
||||
if (_sectorModified)
|
||||
{
|
||||
CommitSector();
|
||||
_sectorModified = false;
|
||||
}
|
||||
|
||||
_head = value;
|
||||
LoadSector();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Cylinder
|
||||
{
|
||||
get { return _cylinder; }
|
||||
set
|
||||
{
|
||||
if (value != _cylinder)
|
||||
{
|
||||
// If we switch cylinders, we need to reload the sector.
|
||||
// If the last sector was modified,
|
||||
// commit it before moving to the next.
|
||||
if (_sectorModified)
|
||||
{
|
||||
CommitSector();
|
||||
_sectorModified = false;
|
||||
}
|
||||
|
||||
_cylinder = value;
|
||||
LoadSector();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DataCell ReadWord(int index)
|
||||
{
|
||||
return _sectorData[index];
|
||||
}
|
||||
|
||||
public void WriteWord(int index, ushort data)
|
||||
{
|
||||
if (index < _sectorData.Length)
|
||||
{
|
||||
if (_sectorData[index].Type == CellType.Data)
|
||||
{
|
||||
_sectorData[index].Data = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Write(LogType.Warning, LogComponent.DiskController, "Data written to non-data section (Sector {0} Word {1} Rec {2} Data {3})", _sector, index, 666, Conversion.ToOctal(data));
|
||||
}
|
||||
|
||||
_sectorModified = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void LoadSector()
|
||||
{
|
||||
if (_pack == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Pull data off disk and pack it into our faked-up sector.
|
||||
// Note that this data is packed in in REVERSE ORDER because that's
|
||||
// how it gets written out and it's how the Alto expects it to be read back in.
|
||||
//
|
||||
DiabloDiskSector sector = _pack.GetSector(_cylinder, _head, _sector);
|
||||
|
||||
// Header (2 words data, 1 word cksum)
|
||||
for (int i = _headerOffset + 1, j = 1; i < _headerOffset + 3; i++, j--)
|
||||
{
|
||||
// actual data to be loaded from disk / cksum calculated
|
||||
_sectorData[i] = new DataCell(sector.Header[j], CellType.Data);
|
||||
}
|
||||
|
||||
ushort checksum = CalculateChecksum(_sectorData, _headerOffset + 1, 2);
|
||||
_sectorData[_headerOffset + 3].Data = checksum;
|
||||
Log.Write(LogType.Verbose, LogComponent.DiskController, "Header checksum for C/H/S {0}/{1}/{2} is {3}", _cylinder, _head, _sector, Conversion.ToOctal(checksum));
|
||||
|
||||
// Label (8 words data, 1 word cksum)
|
||||
for (int i = _labelOffset + 1, j = 7; i < _labelOffset + 9; i++, j--)
|
||||
{
|
||||
// actual data to be loaded from disk / cksum calculated
|
||||
_sectorData[i] = new DataCell(sector.Label[j], CellType.Data);
|
||||
}
|
||||
|
||||
checksum = CalculateChecksum(_sectorData, _labelOffset + 1, 8);
|
||||
_sectorData[_labelOffset + 9].Data = checksum;
|
||||
Log.Write(LogType.Verbose, LogComponent.DiskController, "Label checksum for C/H/S {0}/{1}/{2} is {3}", _cylinder, _head, _sector, Conversion.ToOctal(checksum));
|
||||
|
||||
// sector data (256 words data, 1 word cksum)
|
||||
for (int i = _dataOffset + 1, j = 255; i < _dataOffset + 257; i++, j--)
|
||||
{
|
||||
// actual data to be loaded from disk / cksum calculated
|
||||
_sectorData[i] = new DataCell(sector.Data[j], CellType.Data);
|
||||
}
|
||||
|
||||
checksum = CalculateChecksum(_sectorData, _dataOffset + 1, 256);
|
||||
_sectorData[_dataOffset + 257].Data = checksum;
|
||||
Log.Write(LogType.Verbose, LogComponent.DiskController, "Data checksum for C/H/S {0}/{1}/{2} is {3}", _cylinder, _head, _sector, Conversion.ToOctal(checksum));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Commits modified sector data back to the emulated disk.
|
||||
/// Intended to be called at the end of the sector / beginning of the next.
|
||||
/// TODO: we should modify this so that checksums are persisted, possibly...
|
||||
/// </summary>
|
||||
private void CommitSector()
|
||||
{
|
||||
if (_pack == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DiabloDiskSector sector = _pack.GetSector(_cylinder, _head, _sector);
|
||||
|
||||
// Header (2 words data, 1 word cksum)
|
||||
for (int i = _headerOffset + 1, j = 1; i < _headerOffset + 3; i++, j--)
|
||||
{
|
||||
// actual data to be loaded from disk / cksum calculated
|
||||
sector.Header[j] = _sectorData[i].Data;
|
||||
}
|
||||
|
||||
// Label (8 words data, 1 word cksum)
|
||||
for (int i = _labelOffset + 1, j = 7; i < _labelOffset + 9; i++, j--)
|
||||
{
|
||||
// actual data to be loaded from disk / cksum calculated
|
||||
sector.Label[j] = _sectorData[i].Data;
|
||||
}
|
||||
|
||||
// sector data (256 words data, 1 word cksum)
|
||||
for (int i = _dataOffset + 1, j = 255; i < _dataOffset + 257; i++, j--)
|
||||
{
|
||||
// actual data to be loaded from disk / cksum calculated
|
||||
sector.Data[j] = _sectorData[i].Data;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitSector()
|
||||
{
|
||||
// Fill in sector with default data (basically, fill in non-data areas).
|
||||
|
||||
//
|
||||
// header delay, 22 words
|
||||
for (int i = 0; i < _headerOffset; i++)
|
||||
{
|
||||
_sectorData[i] = new DataCell(0, CellType.Gap);
|
||||
}
|
||||
|
||||
_sectorData[_headerOffset] = new DataCell(1, CellType.Sync);
|
||||
// inter-reccord delay between header & label (10 words)
|
||||
for (int i = _headerOffset + 4; i < _labelOffset; i++)
|
||||
{
|
||||
_sectorData[i] = new DataCell(0, CellType.Gap);
|
||||
}
|
||||
|
||||
_sectorData[_labelOffset] = new DataCell(1, CellType.Sync);
|
||||
// inter-reccord delay between label & data (10 words)
|
||||
for (int i = _labelOffset + 10; i < _dataOffset; i++)
|
||||
{
|
||||
_sectorData[i] = new DataCell(0, CellType.Gap);
|
||||
}
|
||||
|
||||
_sectorData[_dataOffset] = new DataCell(1, CellType.Sync);
|
||||
// read-postamble
|
||||
for (int i = _dataOffset + 258; i < _sectorWordCount; i++)
|
||||
{
|
||||
_sectorData[i] = new DataCell(0, CellType.Gap);
|
||||
}
|
||||
}
|
||||
|
||||
private ushort CalculateChecksum(DataCell[] sectorData, int offset, int length)
|
||||
{
|
||||
//
|
||||
// From the uCode, the Alto's checksum algorithm is:
|
||||
// 1. Load checksum with constant value of 521B (0x151)
|
||||
// 2. For each word in the record, cksum <- word XOR cksum
|
||||
// 3. Profit
|
||||
//
|
||||
ushort checksum = 0x151;
|
||||
|
||||
for (int i = offset; i < offset + length; i++)
|
||||
{
|
||||
// Sanity check that we're checksumming actual data
|
||||
if (sectorData[i].Type != CellType.Data)
|
||||
{
|
||||
throw new InvalidOperationException("Attempt to checksum non-data area of sector.");
|
||||
}
|
||||
|
||||
checksum = (ushort)(checksum ^ sectorData[i].Data);
|
||||
}
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
||||
private AltoSystem _system;
|
||||
|
||||
//
|
||||
// Current disk position
|
||||
//
|
||||
private int _cylinder;
|
||||
private int _head;
|
||||
private int _sector;
|
||||
|
||||
// offsets in words for start of data in sector
|
||||
private const int _headerOffset = 22;
|
||||
private const int _labelOffset = _headerOffset + 14;
|
||||
private const int _dataOffset = _labelOffset + 20;
|
||||
|
||||
private bool _sectorModified;
|
||||
|
||||
private static int _sectorWordCount = 269 + 22 + 34;
|
||||
|
||||
private DataCell[] _sectorData = new DataCell[_sectorWordCount];
|
||||
|
||||
|
||||
// The pack loaded into the drive
|
||||
DiabloPack _pack;
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ namespace Contralto.IO
|
||||
get { return _geometry; }
|
||||
}
|
||||
|
||||
public void Load(Stream imageStream)
|
||||
public void Load(Stream imageStream, bool reverseByteOrder)
|
||||
{
|
||||
for(int cylinder = 0; cylinder < _geometry.Cylinders; cylinder++)
|
||||
{
|
||||
@@ -117,6 +117,13 @@ namespace Contralto.IO
|
||||
throw new InvalidOperationException("Short read while reading sector data.");
|
||||
}
|
||||
|
||||
if (reverseByteOrder)
|
||||
{
|
||||
SwapBytes(header);
|
||||
SwapBytes(label);
|
||||
SwapBytes(data);
|
||||
}
|
||||
|
||||
_sectors[cylinder, track, sector] = new DiabloDiskSector(header, label, data);
|
||||
}
|
||||
}
|
||||
@@ -133,6 +140,16 @@ namespace Contralto.IO
|
||||
return _sectors[cylinder, track, sector];
|
||||
}
|
||||
|
||||
private void SwapBytes(byte[] data)
|
||||
{
|
||||
for(int i=0;i<data.Length;i+=2)
|
||||
{
|
||||
byte t = data[i];
|
||||
data[i] = data[i + 1];
|
||||
data[i + 1] = t;
|
||||
}
|
||||
}
|
||||
|
||||
private DiabloDiskSector[,,] _sectors;
|
||||
private DiabloDiskType _diskType;
|
||||
private DiskGeometry _geometry;
|
||||
|
||||
@@ -10,23 +10,35 @@ namespace Contralto.IO
|
||||
public DiskController(AltoSystem system)
|
||||
{
|
||||
_system = system;
|
||||
Reset();
|
||||
|
||||
// Load the pack
|
||||
_pack = new DiabloPack(DiabloDiskType.Diablo31);
|
||||
// Load the drives
|
||||
_drives = new Diablo30Drive[2];
|
||||
_drives[0] = new Diablo30Drive(_system);
|
||||
_drives[1] = new Diablo30Drive(_system);
|
||||
|
||||
// TODO: this does not belong here.
|
||||
FileStream fs = new FileStream("Disk\\nonprog.dsk", FileMode.Open, FileAccess.Read);
|
||||
DiabloPack p0 = new DiabloPack(DiabloDiskType.Diablo31);
|
||||
FileStream fs = new FileStream("Disk\\diag.dsk", FileMode.Open, FileAccess.Read);
|
||||
p0.Load(fs, false);
|
||||
fs.Close();
|
||||
|
||||
_pack.Load(fs);
|
||||
_drives[0].LoadPack(p0);
|
||||
|
||||
fs.Close();
|
||||
}
|
||||
DiabloPack p1 = new DiabloPack(DiabloDiskType.Diablo31);
|
||||
fs = new FileStream("Disk\\bravox.dsk", FileMode.Open, FileAccess.Read);
|
||||
p1.Load(fs, true);
|
||||
fs.Close();
|
||||
|
||||
_drives[1].LoadPack(p1);
|
||||
|
||||
Reset();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TODO: this is messy; the read and write sides of KDATA are distinct hardware.
|
||||
/// According to docs, on a Write, eventually it appears on the Read side during an actual write to the disk
|
||||
/// but not right away. For now, this never happens (since we don't yet support writing).
|
||||
/// but not right away.
|
||||
/// </summary>
|
||||
public ushort KDATA
|
||||
{
|
||||
@@ -52,14 +64,9 @@ namespace Contralto.IO
|
||||
_syncWordWritten = false;
|
||||
|
||||
// "In addition, it causes the head address bit to be loaded from KDATA[13]."
|
||||
int newHead = (_kDataWrite & 0x4) >> 2;
|
||||
int newHead = (_kDataWrite & 0x4) >> 2;
|
||||
|
||||
if (newHead != _head)
|
||||
{
|
||||
// If we switch heads, we need to reload the sector
|
||||
_head = newHead;
|
||||
LoadSector();
|
||||
}
|
||||
SelectedDrive.Head = newHead;
|
||||
|
||||
// "0 normally, 1 if the command is to terminate immediately after the correct cylinder
|
||||
// position is reached (before any data is transferred)."
|
||||
@@ -76,12 +83,17 @@ namespace Contralto.IO
|
||||
Log.Write(LogComponent.DiskController, " -Disk Address ({0}) is C/H/S {1}/{2}/{3}, Drive {4} Restore {5}",
|
||||
Conversion.ToOctal(_kDataWrite),
|
||||
(_kDataWrite & 0x0ff8) >> 3,
|
||||
_head,
|
||||
newHead,
|
||||
(_kDataWrite & 0xf000) >> 12,
|
||||
(_kDataWrite & 0x2) >> 1,
|
||||
(_kDataWrite & 0x1));
|
||||
|
||||
Log.Write(LogComponent.DiskController, " -Selected disk is {0}", _disk);
|
||||
//if ((_kAdr & 0x1) != 0)
|
||||
{
|
||||
//_disk = ((_kDataWrite & 0x2) >> 1);
|
||||
}
|
||||
|
||||
Log.Write(LogComponent.DiskController, " -Selected disk is {0}", _disk);
|
||||
|
||||
if ((_kDataWrite & 0x1) != 0)
|
||||
{
|
||||
@@ -113,10 +125,11 @@ namespace Contralto.IO
|
||||
_wdInit = true;
|
||||
}
|
||||
|
||||
if (_sendAdr)
|
||||
|
||||
if (_sendAdr & (_kDataWrite & 0x2) != 0)
|
||||
{
|
||||
// Select disk if _sendAdr is true
|
||||
_disk = ((_kDataWrite & 0x2) >> 1) ^ (_kAdr & 0x1);
|
||||
_disk = (_kAdr & 0x1);
|
||||
|
||||
if (_disk != 0)
|
||||
{
|
||||
@@ -139,50 +152,50 @@ namespace Contralto.IO
|
||||
public ushort KSTAT
|
||||
{
|
||||
get
|
||||
{
|
||||
{
|
||||
// Bits 4-7 of KSTAT are always 1s (it's a shortcut allowing the disk microcode to write
|
||||
// "-1" to bits 4-7 of the disk status word at 522 without extra code.)
|
||||
return (ushort)(_kStat | (0x0f00));
|
||||
}
|
||||
set
|
||||
{
|
||||
_kStat = value;
|
||||
_kStat = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ushort RECNO
|
||||
{
|
||||
get { return _recMap[_recNo]; }
|
||||
get { return _recMap[_recNo]; }
|
||||
}
|
||||
|
||||
public bool DataXfer
|
||||
{
|
||||
get { return _dataXfer; }
|
||||
}
|
||||
|
||||
|
||||
public int Cylinder
|
||||
{
|
||||
get { return _cylinder; }
|
||||
get { return SelectedDrive.Cylinder; }
|
||||
}
|
||||
|
||||
public int SeekCylinder
|
||||
{
|
||||
get { return _destCylinder; }
|
||||
get { return _destCylinder; }
|
||||
}
|
||||
|
||||
public int Head
|
||||
{
|
||||
get { return _head; }
|
||||
get { return SelectedDrive.Head; }
|
||||
}
|
||||
|
||||
public int Sector
|
||||
{
|
||||
get { return _sector; }
|
||||
get { return SelectedDrive.Sector; }
|
||||
}
|
||||
|
||||
public int Drive
|
||||
{
|
||||
get { return 0; }
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public double ClocksUntilNextSector
|
||||
@@ -202,10 +215,8 @@ namespace Contralto.IO
|
||||
public void Reset()
|
||||
{
|
||||
ClearStatus();
|
||||
_recNo = 0;
|
||||
_cylinder = _destCylinder = 0;
|
||||
_recNo = 0;
|
||||
_sector = 0;
|
||||
_head = 0;
|
||||
_disk = 0;
|
||||
_kStat = 0;
|
||||
_kDataRead = 0;
|
||||
@@ -219,21 +230,22 @@ namespace Contralto.IO
|
||||
_wdInit = false;
|
||||
|
||||
_syncWordWritten = false;
|
||||
_sectorModified = false;
|
||||
|
||||
_diskBitCounterEnable = false;
|
||||
_sectorWordIndex = 0;
|
||||
_sectorWordIndex = 0;
|
||||
|
||||
InitSector();
|
||||
// Reset drives
|
||||
_drives[0].Reset();
|
||||
_drives[1].Reset();
|
||||
|
||||
// Wakeup the sector task first thing
|
||||
_system.CPU.WakeupTask(CPU.TaskType.DiskSector);
|
||||
|
||||
|
||||
// Create events to be reused during execution
|
||||
_sectorEvent = new Event(_sectorDuration, null, SectorCallback);
|
||||
_wordEvent = new Event(_wordDuration, null, WordCallback);
|
||||
_seekEvent = new Event(0, null, SeekCallback);
|
||||
_seclateEvent = new Event(_seclateDuration, null, SeclateCallback);
|
||||
_seekEvent = new Event(_seekDuration, null, SeekCallback);
|
||||
|
||||
// And schedule the first sector pulse.
|
||||
_system.Scheduler.Schedule(_sectorEvent);
|
||||
@@ -249,17 +261,10 @@ namespace Contralto.IO
|
||||
|
||||
private void SectorCallback(ulong timeNsec, ulong skewNsec, object context)
|
||||
{
|
||||
// Write last sector out if it was modified
|
||||
if (_sectorModified)
|
||||
{
|
||||
CommitSector();
|
||||
_sectorModified = false;
|
||||
}
|
||||
|
||||
//
|
||||
// Next sector; move to next sector and wake up Disk Sector task.
|
||||
//
|
||||
_sector = (_sector + 1) % 12;
|
||||
_sector = (_sector + 1) % 12;
|
||||
|
||||
_kStat = (ushort)((_kStat & 0x0fff) | (_sector << 12));
|
||||
|
||||
@@ -267,15 +272,15 @@ namespace Contralto.IO
|
||||
_sectorWordIndex = 0;
|
||||
_syncWordWritten = false;
|
||||
|
||||
_kDataRead = 0;
|
||||
_kDataRead = 0;
|
||||
|
||||
// Load new sector in
|
||||
LoadSector();
|
||||
SelectedDrive.Sector = _sector;
|
||||
|
||||
// Only wake up if not actively seeking.
|
||||
if ((_kStat & 0x0040) == 0)
|
||||
{
|
||||
Log.Write(LogType.Verbose, LogComponent.DiskController, "Waking up sector task for C/H/S {0}/{1}/{2}", _cylinder, _head, _sector);
|
||||
Log.Write(LogType.Verbose, LogComponent.DiskController, "Waking up sector task for C/H/S {0}/{1}/{2}", SelectedDrive.Cylinder, SelectedDrive.Head, _sector);
|
||||
_system.CPU.WakeupTask(CPU.TaskType.DiskSector);
|
||||
|
||||
// Reset SECLATE
|
||||
@@ -295,7 +300,7 @@ namespace Contralto.IO
|
||||
{
|
||||
// Schedule next sector pulse
|
||||
_sectorEvent.TimestampNsec = _sectorDuration - skewNsec;
|
||||
_system.Scheduler.Schedule(_sectorEvent);
|
||||
_system.Scheduler.Schedule(_sectorEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,49 +318,19 @@ namespace Contralto.IO
|
||||
{
|
||||
// // Schedule next sector pulse immediately
|
||||
_sectorEvent.TimestampNsec = skewNsec;
|
||||
_system.Scheduler.Schedule(_sectorEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private void SeekCallback(ulong timeNsec, ulong skewNsec, object context)
|
||||
{
|
||||
if (_cylinder < _destCylinder)
|
||||
{
|
||||
_cylinder++;
|
||||
}
|
||||
else if (_cylinder > _destCylinder)
|
||||
{
|
||||
_cylinder--;
|
||||
}
|
||||
|
||||
Log.Write(LogComponent.DiskController, "Seek progress: cylinder {0} reached.", _cylinder);
|
||||
|
||||
// Are we *there* yet?
|
||||
if (_cylinder == _destCylinder)
|
||||
{
|
||||
// clear Seek bit
|
||||
_kStat &= 0xffbf;
|
||||
|
||||
Log.Write(LogComponent.DiskController, "Seek to {0} completed.", _cylinder);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nope.
|
||||
// Schedule next seek step.
|
||||
_seekEvent.TimestampNsec = _seekDuration - skewNsec;
|
||||
_system.Scheduler.Schedule(_seekEvent);
|
||||
_system.Scheduler.Schedule(_sectorEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private void SeclateCallback(ulong timeNsec, ulong skewNsec, object context)
|
||||
{
|
||||
if (_seclateEnable)
|
||||
{
|
||||
{
|
||||
_seclate = true;
|
||||
_kStat |= 0x0010; // TODO: move to constant field!
|
||||
Log.Write(LogComponent.DiskSectorTask, "SECLATE for sector {0}.", _sector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearStatus()
|
||||
{
|
||||
@@ -388,7 +363,7 @@ namespace Contralto.IO
|
||||
// "Initiates a disk seek operation. The KDATA register must have been loaded previously,
|
||||
// and the SENDADR bit of the KCOMM register previously set to 1."
|
||||
//
|
||||
|
||||
|
||||
// sanity check: see if SENDADR bit is set, if not we'll signal an error (since I'm trusting that
|
||||
// the official Xerox uCode is doing the right thing, this will help ferret out emulation issues.
|
||||
// eventually this can be removed.)
|
||||
@@ -398,25 +373,24 @@ namespace Contralto.IO
|
||||
}
|
||||
|
||||
Log.Write(LogComponent.DiskController, "STROBE: Seek initialized.");
|
||||
|
||||
InitSeek((_kDataWrite & 0x0ff8) >> 3);
|
||||
|
||||
InitSeek((_kDataWrite & 0x0ff8) >> 3);
|
||||
}
|
||||
|
||||
private void InitSeek(int destCylinder)
|
||||
{
|
||||
_destCylinder = destCylinder;
|
||||
|
||||
// set "seek fail" bit based on selected cylinder (if out of bounds) and do not
|
||||
// commence a seek if so.
|
||||
if (_destCylinder > 202)
|
||||
if (destCylinder > 202)
|
||||
{
|
||||
_kStat |= 0x0080;
|
||||
|
||||
Log.Write(LogComponent.DiskController, "Seek failed, specified cylinder {0} is out of range.", _destCylinder);
|
||||
Log.Write(LogComponent.DiskController, "Seek failed, specified cylinder {0} is out of range.", destCylinder);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, start a seek.
|
||||
_destCylinder = destCylinder;
|
||||
|
||||
// Clear the fail bit.
|
||||
_kStat &= 0xff7f;
|
||||
@@ -425,29 +399,15 @@ namespace Contralto.IO
|
||||
_kStat |= 0x0040;
|
||||
|
||||
// And figure out how long this will take.
|
||||
_seekDuration = (ulong)(CalculateSeekTime() / (ulong)(Math.Abs(_destCylinder - _cylinder) + 1));
|
||||
_seekDuration = (ulong)(CalculateSeekTime() / (ulong)(Math.Abs(_destCylinder - SelectedDrive.Cylinder) + 1));
|
||||
|
||||
_seekEvent.TimestampNsec = _seekDuration;
|
||||
_system.Scheduler.Schedule(_seekEvent);
|
||||
|
||||
Log.Write(LogComponent.DiskController, "Seek to {0} from {1} commencing. Will take {2} nsec.", _destCylinder, _cylinder, _seekDuration);
|
||||
Log.Write(LogComponent.DiskController, "Seek to {0} from {1} commencing. Will take {2} nsec.", _destCylinder, SelectedDrive.Cylinder, _seekDuration);
|
||||
}
|
||||
}
|
||||
|
||||
private ulong CalculateSeekTime()
|
||||
{
|
||||
// How many cylinders are we moving?
|
||||
int dt = Math.Abs(_destCylinder - _cylinder);
|
||||
|
||||
//
|
||||
// From the Hardware Manual, pg 43:
|
||||
// "Seek time (approx.): 15 + 8.6 * sqrt(dt) (msec)
|
||||
//
|
||||
double seekTimeMsec = 15.0 + 8.6 * Math.Sqrt(dt);
|
||||
|
||||
return (ulong)(seekTimeMsec * Conversion.MsecToNsec);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// "Rotates" the emulated disk platter one clock's worth.
|
||||
/// </summary>
|
||||
@@ -478,7 +438,7 @@ namespace Contralto.IO
|
||||
// and we may not actually end up doing anything with it, but we may
|
||||
// need it to decide whether to do anything at all.
|
||||
//
|
||||
ushort diskWord = _sectorData[_sectorWordIndex].Data;
|
||||
DataCell diskWord = SelectedDrive.ReadWord(_sectorWordIndex);
|
||||
|
||||
bool bWakeup = false;
|
||||
//
|
||||
@@ -486,8 +446,8 @@ namespace Contralto.IO
|
||||
// then we will wake up the word task now.
|
||||
//
|
||||
if (!_seclate && !_wdInhib && !_bClkSource)
|
||||
{
|
||||
bWakeup = true;
|
||||
{
|
||||
bWakeup = true;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -509,9 +469,9 @@ namespace Contralto.IO
|
||||
Log.Write(LogType.Warning, LogComponent.DiskController, "--- missed sector word {0}({1}) ---", _sectorWordIndex, _kDataRead);
|
||||
}
|
||||
|
||||
Log.Write(LogType.Verbose, LogComponent.DiskWordTask, "Sector {0} Word {1} read into KDATA", _sector, Conversion.ToOctal(diskWord));
|
||||
_kDataRead = diskWord;
|
||||
_debugRead = _sectorData[_sectorWordIndex].Type == CellType.Data;
|
||||
Log.Write(LogType.Verbose, LogComponent.DiskWordTask, "Sector {0} Word {1} read into KDATA", _sector, Conversion.ToOctal(diskWord.Data));
|
||||
_kDataRead = diskWord.Data;
|
||||
_debugRead = diskWord.Type == CellType.Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -524,18 +484,10 @@ namespace Contralto.IO
|
||||
_kDataWriteLatch = false;
|
||||
}
|
||||
|
||||
if (_syncWordWritten && _sectorWordIndex < _sectorData.Length)
|
||||
if (_syncWordWritten)
|
||||
{
|
||||
if (_sectorData[_sectorWordIndex].Type == CellType.Data)
|
||||
{
|
||||
_sectorData[_sectorWordIndex].Data = _kDataWrite;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Write(LogType.Warning, LogComponent.DiskController, "Data written to non-data section (Sector {0} Word {1} Rec {2} Data {3})", _sector, _sectorWordIndex, _recNo, Conversion.ToOctal(_kDataWrite));
|
||||
}
|
||||
|
||||
_sectorModified = true;
|
||||
// Commit actual data to disk now that the sync word has been laid down
|
||||
SelectedDrive.WriteWord(_sectorWordIndex, _kDataWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -552,8 +504,8 @@ namespace Contralto.IO
|
||||
// the clock. This occurs late in the cycle so that the NEXT word
|
||||
// (not the sync word) is actually read. TODO: this should only happen on reads.
|
||||
//
|
||||
if (!IsWrite() && !_wffo && diskWord == 1)
|
||||
{
|
||||
if (!IsWrite() && !_wffo && diskWord.Data == 1)
|
||||
{
|
||||
_diskBitCounterEnable = true;
|
||||
}
|
||||
else if (IsWrite() && _wffo && _kDataWrite == 1 && !_syncWordWritten)
|
||||
@@ -563,7 +515,7 @@ namespace Contralto.IO
|
||||
|
||||
// "Adjust" the write index to the start of the data area for the current record.
|
||||
// This is cheating.
|
||||
switch(_recNo)
|
||||
switch (_recNo)
|
||||
{
|
||||
case 0:
|
||||
_sectorWordIndex = _headerOffset;
|
||||
@@ -583,143 +535,11 @@ namespace Contralto.IO
|
||||
{
|
||||
Log.Write(LogType.Verbose, LogComponent.DiskWordTask, "Word task awoken for word {0}.", _sectorWordIndex);
|
||||
_system.CPU.WakeupTask(TaskType.DiskWord);
|
||||
}
|
||||
}
|
||||
|
||||
// Last, move to the next word.
|
||||
_sectorWordIndex++;
|
||||
|
||||
}
|
||||
|
||||
private void LoadSector()
|
||||
{
|
||||
//
|
||||
// Pull data off disk and pack it into our faked-up sector.
|
||||
// Note that this data is packed in in REVERSE ORDER because that's
|
||||
// how it gets written out and it's how the Alto expects it to be read back in.
|
||||
//
|
||||
DiabloDiskSector sector = _pack.GetSector(_cylinder, _head, _sector);
|
||||
|
||||
// Header (2 words data, 1 word cksum)
|
||||
for (int i = _headerOffset + 1, j = 1; i < _headerOffset + 3; i++, j--)
|
||||
{
|
||||
// actual data to be loaded from disk / cksum calculated
|
||||
_sectorData[i] = new DataCell(sector.Header[j], CellType.Data);
|
||||
}
|
||||
|
||||
ushort checksum = CalculateChecksum(_sectorData, _headerOffset + 1, 2);
|
||||
_sectorData[_headerOffset + 3].Data = checksum;
|
||||
Log.Write(LogType.Verbose, LogComponent.DiskController, "Header checksum for C/H/S {0}/{1}/{2} is {3}", _cylinder, _head, _sector, Conversion.ToOctal(checksum));
|
||||
|
||||
// Label (8 words data, 1 word cksum)
|
||||
for (int i = _labelOffset + 1, j = 7; i < _labelOffset + 9; i++, j--)
|
||||
{
|
||||
// actual data to be loaded from disk / cksum calculated
|
||||
_sectorData[i] = new DataCell(sector.Label[j], CellType.Data);
|
||||
}
|
||||
|
||||
checksum = CalculateChecksum(_sectorData, _labelOffset + 1, 8);
|
||||
_sectorData[_labelOffset + 9].Data = checksum;
|
||||
Log.Write(LogType.Verbose, LogComponent.DiskController, "Label checksum for C/H/S {0}/{1}/{2} is {3}", _cylinder, _head, _sector, Conversion.ToOctal(checksum));
|
||||
|
||||
// sector data (256 words data, 1 word cksum)
|
||||
for (int i = _dataOffset + 1, j = 255; i < _dataOffset + 257; i++, j--)
|
||||
{
|
||||
// actual data to be loaded from disk / cksum calculated
|
||||
_sectorData[i] = new DataCell(sector.Data[j], CellType.Data);
|
||||
}
|
||||
|
||||
checksum = CalculateChecksum(_sectorData, _dataOffset + 1, 256);
|
||||
_sectorData[_dataOffset + 257].Data = checksum;
|
||||
Log.Write(LogType.Verbose, LogComponent.DiskController, "Data checksum for C/H/S {0}/{1}/{2} is {3}", _cylinder, _head, _sector, Conversion.ToOctal(checksum));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Commits modified sector data back to the emulated disk.
|
||||
/// Intended to be called at the end of the sector / beginning of the next.
|
||||
/// TODO: we should modify this so that checksums are persisted, possibly...
|
||||
/// </summary>
|
||||
private void CommitSector()
|
||||
{
|
||||
DiabloDiskSector sector = _pack.GetSector(_cylinder, _head, _sector);
|
||||
|
||||
// Header (2 words data, 1 word cksum)
|
||||
for (int i = _headerOffset + 1, j = 1; i < _headerOffset + 3; i++, j--)
|
||||
{
|
||||
// actual data to be loaded from disk / cksum calculated
|
||||
sector.Header[j] = _sectorData[i].Data;
|
||||
}
|
||||
|
||||
// Label (8 words data, 1 word cksum)
|
||||
for (int i = _labelOffset + 1, j = 7; i < _labelOffset + 9; i++, j--)
|
||||
{
|
||||
// actual data to be loaded from disk / cksum calculated
|
||||
sector.Label[j] = _sectorData[i].Data;
|
||||
}
|
||||
|
||||
// sector data (256 words data, 1 word cksum)
|
||||
for (int i = _dataOffset + 1, j = 255; i < _dataOffset + 257; i++, j--)
|
||||
{
|
||||
// actual data to be loaded from disk / cksum calculated
|
||||
sector.Data[j] = _sectorData[i].Data;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitSector()
|
||||
{
|
||||
// Fill in sector with default data (basically, fill in non-data areas).
|
||||
|
||||
//
|
||||
// header delay, 22 words
|
||||
for (int i=0; i < _headerOffset; i++)
|
||||
{
|
||||
_sectorData[i] = new DataCell(0, CellType.Gap);
|
||||
}
|
||||
|
||||
_sectorData[_headerOffset] = new DataCell(1, CellType.Sync);
|
||||
// inter-reccord delay between header & label (10 words)
|
||||
for (int i = _headerOffset + 4; i < _labelOffset; i++)
|
||||
{
|
||||
_sectorData[i] = new DataCell(0, CellType.Gap);
|
||||
}
|
||||
|
||||
_sectorData[_labelOffset] = new DataCell(1, CellType.Sync);
|
||||
// inter-reccord delay between label & data (10 words)
|
||||
for (int i = _labelOffset + 10; i < _dataOffset; i++)
|
||||
{
|
||||
_sectorData[i] = new DataCell(0, CellType.Gap);
|
||||
}
|
||||
|
||||
_sectorData[_dataOffset] = new DataCell(1, CellType.Sync);
|
||||
// read-postamble
|
||||
for (int i = _dataOffset + 258; i < _sectorWordCount;i++)
|
||||
{
|
||||
_sectorData[i] = new DataCell(0, CellType.Gap);
|
||||
}
|
||||
}
|
||||
|
||||
private ushort CalculateChecksum(DataCell[] sectorData, int offset, int length)
|
||||
{
|
||||
//
|
||||
// From the uCode, the Alto's checksum algorithm is:
|
||||
// 1. Load checksum with constant value of 521B (0x151)
|
||||
// 2. For each word in the record, cksum <- word XOR cksum
|
||||
// 3. Profit
|
||||
//
|
||||
ushort checksum = 0x151;
|
||||
|
||||
for(int i = offset; i < offset + length;i++)
|
||||
{
|
||||
// Sanity check that we're checksumming actual data
|
||||
if (sectorData[i].Type != CellType.Data)
|
||||
{
|
||||
throw new InvalidOperationException("Attempt to checksum non-data area of sector.");
|
||||
}
|
||||
|
||||
checksum = (ushort)(checksum ^ sectorData[i].Data);
|
||||
}
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
||||
private bool IsWrite()
|
||||
@@ -727,6 +547,55 @@ namespace Contralto.IO
|
||||
return ((_kAdr & 0x00c0) >> 6) == 2 || ((_kAdr & 0x00c0) >> 6) == 3;
|
||||
}
|
||||
|
||||
private void SeekCallback(ulong timeNsec, ulong skewNsec, object context)
|
||||
{
|
||||
if (SelectedDrive.Cylinder < _destCylinder)
|
||||
{
|
||||
SelectedDrive.Cylinder++;
|
||||
}
|
||||
else if (SelectedDrive.Cylinder > _destCylinder)
|
||||
{
|
||||
SelectedDrive.Cylinder--;
|
||||
}
|
||||
|
||||
Log.Write(LogComponent.DiskController, "Seek progress: cylinder {0} reached.", SelectedDrive.Cylinder);
|
||||
|
||||
// Are we *there* yet?
|
||||
if (SelectedDrive.Cylinder == _destCylinder)
|
||||
{
|
||||
// clear Seek bit
|
||||
_kStat &= 0xffbf;
|
||||
|
||||
Log.Write(LogComponent.DiskController, "Seek to {0} completed.", SelectedDrive.Cylinder);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nope.
|
||||
// Schedule next seek step.
|
||||
_seekEvent.TimestampNsec = _seekDuration - skewNsec;
|
||||
_system.Scheduler.Schedule(_seekEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private ulong CalculateSeekTime()
|
||||
{
|
||||
// How many cylinders are we moving?
|
||||
int dt = Math.Abs(_destCylinder - SelectedDrive.Cylinder);
|
||||
|
||||
//
|
||||
// From the Hardware Manual, pg 43:
|
||||
// "Seek time (approx.): 15 + 8.6 * sqrt(dt) (msec)
|
||||
//
|
||||
double seekTimeMsec = 15.0 + 8.6 * Math.Sqrt(dt);
|
||||
|
||||
return (ulong)(seekTimeMsec * Conversion.MsecToNsec);
|
||||
}
|
||||
|
||||
private Diablo30Drive SelectedDrive
|
||||
{
|
||||
get { return _drives[_disk]; }
|
||||
}
|
||||
|
||||
private ushort _kDataRead;
|
||||
private ushort _kDataWrite;
|
||||
private bool _kDataWriteLatch;
|
||||
@@ -750,12 +619,16 @@ namespace Contralto.IO
|
||||
// Transfer bit
|
||||
private bool _dataXfer;
|
||||
|
||||
// Current disk position
|
||||
private int _cylinder;
|
||||
private int _destCylinder;
|
||||
private int _head;
|
||||
// Current sector
|
||||
private int _sector;
|
||||
|
||||
//
|
||||
// Seek state
|
||||
//
|
||||
private int _destCylinder;
|
||||
private ulong _seekDuration;
|
||||
private Event _seekEvent;
|
||||
|
||||
// Selected disk
|
||||
private int _disk;
|
||||
|
||||
@@ -766,7 +639,6 @@ namespace Contralto.IO
|
||||
private bool _wdInit;
|
||||
|
||||
private bool _syncWordWritten;
|
||||
private bool _sectorModified;
|
||||
|
||||
// Sector timing. Based on table on pg. 43 of the Alto Hardware Manual
|
||||
|
||||
@@ -785,7 +657,7 @@ namespace Contralto.IO
|
||||
|
||||
private Event _sectorEvent;
|
||||
private Event _wordEvent;
|
||||
|
||||
|
||||
|
||||
// offsets in words for start of data in sector
|
||||
private const int _headerOffset = 22;
|
||||
@@ -797,44 +669,10 @@ namespace Contralto.IO
|
||||
private static ulong _seclateDuration = (ulong)(85.0 * Conversion.UsecToNsec * _scale);
|
||||
private bool _seclateEnable;
|
||||
private bool _seclate;
|
||||
private Event _seclateEvent;
|
||||
private Event _seclateEvent;
|
||||
|
||||
// Cylinder seek time (in nsec) Again, see the manual.
|
||||
// Timing varies based on how many cylinders are being traveled during a seek; see
|
||||
// CalculateSeekTime() for more.
|
||||
private ulong _seekDuration;
|
||||
private Event _seekEvent;
|
||||
|
||||
// The data for the current sector
|
||||
private enum CellType
|
||||
{
|
||||
Data,
|
||||
Gap,
|
||||
Sync,
|
||||
}
|
||||
|
||||
private struct DataCell
|
||||
{
|
||||
public DataCell(ushort data, CellType type)
|
||||
{
|
||||
Data = data;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public ushort Data;
|
||||
public CellType Type;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0} {1}", Data, Type);
|
||||
}
|
||||
}
|
||||
|
||||
private DataCell[] _sectorData = new DataCell[_sectorWordCount];
|
||||
|
||||
|
||||
// The pack loaded into the drive
|
||||
DiabloPack _pack;
|
||||
// Attached drives
|
||||
private Diablo30Drive[] _drives;
|
||||
|
||||
private AltoSystem _system;
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Contralto.Logging
|
||||
static Log()
|
||||
{
|
||||
// TODO: make configurable
|
||||
_components = LogComponent.None; // LogComponent.DiskController | LogComponent.DiskSectorTask;
|
||||
_components = LogComponent.DiskController | LogComponent.DiskSectorTask;
|
||||
_type = LogType.Normal | LogType.Warning | LogType.Error;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,14 +6,23 @@ namespace Contralto
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
AltoSystem system = new AltoSystem();
|
||||
AltoSystem system = new AltoSystem();
|
||||
|
||||
// for now everything is driven through the debugger
|
||||
// for now everything is driven through the debugger
|
||||
|
||||
AltoWindow mainWindow = new AltoWindow();
|
||||
|
||||
mainWindow.AttachSystem(system);
|
||||
|
||||
/*
|
||||
Debugger d = new Debugger(system);
|
||||
system.AttachDisplay(d);
|
||||
d.LoadSourceCode(MicrocodeBank.ROM0, "Disassembly\\altoIIcode3.mu");
|
||||
d.LoadSourceCode(MicrocodeBank.ROM1, "Disassembly\\MesaROM.mu");
|
||||
d.ShowDialog();
|
||||
*/
|
||||
mainWindow.ShowDialog();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user