diff --git a/Contralto/CPU/NovaDisassembler.cs b/Contralto/CPU/NovaDisassembler.cs
new file mode 100644
index 0000000..f19b466
--- /dev/null
+++ b/Contralto/CPU/NovaDisassembler.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Contralto.CPU
+{
+ ///
+ /// Quick and dirty disassembler for Nova instructions, so we can
+ /// see what the emulator task is executing more clearly.
+ ///
+ public static class NovaDisassembler
+ {
+
+ }
+}
diff --git a/Contralto/CPU/Tasks/EmulatorTask.cs b/Contralto/CPU/Tasks/EmulatorTask.cs
index 65b4d09..82448a9 100644
--- a/Contralto/CPU/Tasks/EmulatorTask.cs
+++ b/Contralto/CPU/Tasks/EmulatorTask.cs
@@ -127,7 +127,7 @@ namespace Contralto.CPU
// Conditions ORed onto NEXT Comment
//
// if IR[0] = 1 3-IR[8-9] complement of SH field of IR
- // elseif IR[1-2] = 0 IR[3-4] JMP, JSR, ISZ, DSZ
+ // elseif IR[1-2] = 0 IR[3-4] JMP, JSR, ISZ, DSZ ; dispatch selects register
// elseif IR[1-2] = 1 4 LDA
// elseif IR[1-2] = 2 5 STA
// elseif IR[4-7] = 0 1
@@ -145,11 +145,11 @@ namespace Contralto.CPU
{
_nextModifier = (ushort)((_cpu._ir & 0x1800) >> 11);
}
- else if ((_cpu._ir & 0x6000) == 0x4000)
+ else if ((_cpu._ir & 0x6000) == 0x2000)
{
_nextModifier = 4;
}
- else if ((_cpu._ir & 0x6000) == 0x6000)
+ else if ((_cpu._ir & 0x6000) == 0x4000)
{
_nextModifier = 5;
}
diff --git a/Contralto/CPU/Disassembler.cs b/Contralto/CPU/UCodeDisassembler.cs
similarity index 99%
rename from Contralto/CPU/Disassembler.cs
rename to Contralto/CPU/UCodeDisassembler.cs
index ab30c6f..412086a 100644
--- a/Contralto/CPU/Disassembler.cs
+++ b/Contralto/CPU/UCodeDisassembler.cs
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace Contralto.CPU
{
// BUG: register assignments should come from L (not 0)
- public static class Disassembler
+ public static class UCodeDisassembler
{
///
diff --git a/Contralto/Contralto.csproj b/Contralto/Contralto.csproj
index 6a64338..85897e0 100644
--- a/Contralto/Contralto.csproj
+++ b/Contralto/Contralto.csproj
@@ -47,7 +47,8 @@
-
+
+
@@ -62,6 +63,7 @@
+
@@ -76,6 +78,9 @@
PreserveNewest
+
+ Always
+
Always
diff --git a/Contralto/Disk/games.dsk b/Contralto/Disk/games.dsk
new file mode 100644
index 0000000..946f0e7
Binary files /dev/null and b/Contralto/Disk/games.dsk differ
diff --git a/Contralto/IO/DiabloPack.cs b/Contralto/IO/DiabloPack.cs
new file mode 100644
index 0000000..2b583af
--- /dev/null
+++ b/Contralto/IO/DiabloPack.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Contralto.IO
+{
+
+ public struct DiskGeometry
+ {
+ public DiskGeometry(int cylinders, int tracks, int sectors)
+ {
+ Cylinders = cylinders;
+ Tracks = tracks;
+ Sectors = sectors;
+ }
+
+ public int Cylinders;
+ public int Tracks;
+ public int Sectors;
+ }
+
+ public enum DiabloDiskType
+ {
+ Diablo31,
+ Diablo44
+ }
+
+ public class DiabloDiskSector
+ {
+ public DiabloDiskSector(byte[] header, byte[] label, byte[] data)
+ {
+ if (header.Length != 4 ||
+ label.Length != 16 ||
+ data.Length != 512)
+ {
+ throw new InvalidOperationException("Invalid sector header/label/data length.");
+ }
+
+ Header = GetUShortArray(header);
+ Label = GetUShortArray(label);
+ Data = GetUShortArray(data);
+ }
+
+ private ushort[] GetUShortArray(byte[] data)
+ {
+ if ((data.Length % 2) != 0)
+ {
+ throw new InvalidOperationException("Array length must be even.");
+ }
+
+ ushort[] array = new ushort[data.Length / 2];
+
+ int offset = 0;
+ for(int i=0;i
+ /// Encapsulates disk image data for all disk packs used with the
+ /// standard Alto Disk Controller (i.e. the 31 and 44, which differ
+ /// only in the number of cylinders)
+ ///
+ public class DiabloPack
+ {
+ public DiabloPack(DiabloDiskType type)
+ {
+ _diskType = type;
+ _geometry = new DiskGeometry(type == DiabloDiskType.Diablo31 ? 203 : 406, 2, 12);
+ _sectors = new DiabloDiskSector[_geometry.Cylinders, _geometry.Tracks, _geometry.Sectors];
+ }
+
+ public DiskGeometry Geometry
+ {
+ get { return _geometry; }
+ }
+
+ public void Load(Stream imageStream)
+ {
+ for(int cylinder = 0; cylinder < _geometry.Cylinders; cylinder++)
+ {
+ for(int track = 0; track < _geometry.Tracks; track++)
+ {
+ for(int sector = 0; sector < _geometry.Sectors; sector++)
+ {
+ byte[] header = new byte[4]; // 2 words
+ byte[] label = new byte[16]; // 8 words
+ byte[] data = new byte[512]; // 256 words
+
+ //
+ // Bitsavers images have an extra word in the header for some reason.
+ // ignore it.
+ // TODO: should support different formats ("correct" raw, Alto CopyDisk format, etc.)
+ //
+ imageStream.Seek(2, SeekOrigin.Current);
+ if (imageStream.Read(header, 0, header.Length) != header.Length)
+ {
+ throw new InvalidOperationException("Short read while reading sector header.");
+ }
+
+ if (imageStream.Read(label, 0, label.Length) != label.Length)
+ {
+ throw new InvalidOperationException("Short read while reading sector label.");
+ }
+
+ if (imageStream.Read(data, 0, data.Length) != data.Length)
+ {
+ throw new InvalidOperationException("Short read while reading sector data.");
+ }
+
+ _sectors[cylinder, track, sector] = new DiabloDiskSector(header, label, data);
+ }
+ }
+ }
+
+ if (imageStream.Position != imageStream.Length)
+ {
+ throw new InvalidOperationException("Extra data at end of image file.");
+ }
+ }
+
+ public DiabloDiskSector GetSector(int cylinder, int track, int sector)
+ {
+ return _sectors[cylinder, track, sector];
+ }
+
+ private DiabloDiskSector[,,] _sectors;
+ private DiabloDiskType _diskType;
+ private DiskGeometry _geometry;
+ }
+}
diff --git a/Contralto/IO/DiskController.cs b/Contralto/IO/DiskController.cs
index 5119aef..dded8f3 100644
--- a/Contralto/IO/DiskController.cs
+++ b/Contralto/IO/DiskController.cs
@@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks;
using Contralto.Memory;
+using System.IO;
namespace Contralto.IO
{
@@ -15,10 +16,18 @@ namespace Contralto.IO
_system = system;
Reset();
- // Wakeup the sector task first thing
- _system.CPU.WakeupTask(CPU.TaskType.DiskSector);
+ // Load the pack
+ _pack = new DiabloPack(DiabloDiskType.Diablo31);
-
+ // TODO: this does not belong here.
+ FileStream fs = new FileStream("Disk\\games.dsk", FileMode.Open, FileAccess.Read);
+
+ _pack.Load(fs);
+
+ fs.Close();
+
+ // Wakeup the sector task first thing
+ _system.CPU.WakeupTask(CPU.TaskType.DiskSector);
}
public ushort KDATA
@@ -419,31 +428,37 @@ namespace Contralto.IO
private void LoadSector()
{
- // Fill in sector with test data; eventually actually load real disk data!
+ //
+ // 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; i < _headerOffset + 3; i++)
+ 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(0xbeef, CellType.Data);
+ _sectorData[i] = new DataCell(sector.Header[j], CellType.Data);
}
_sectorData[_headerOffset + 3].Data = CalculateChecksum(_sectorData, _headerOffset + 1, 2);
// Label (8 words data, 1 word cksum)
- for (int i = _labelOffset + 1; i < _labelOffset + 9; i++)
+ 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(0xdead, CellType.Data);
+ _sectorData[i] = new DataCell(sector.Label[j], CellType.Data);
}
_sectorData[_labelOffset + 9].Data = CalculateChecksum(_sectorData, _labelOffset + 1, 8);
// sector data (256 words data, 1 word cksum)
- for (int i = _dataOffset + 1; i < _dataOffset + 257; i++)
+ 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((ushort)(0x7000 + i), CellType.Data);
+ _sectorData[i] = new DataCell(sector.Data[j], CellType.Data);
}
_sectorData[_dataOffset + 257].Data = CalculateChecksum(_sectorData, _dataOffset + 1, 256);
@@ -454,7 +469,6 @@ namespace Contralto.IO
{
// Fill in sector with default data (basically, fill in non-data areas).
-
//
// header delay, 22 words
for (int i=0; i < _headerOffset; i++)
@@ -602,6 +616,8 @@ namespace Contralto.IO
private double _elapsedSeekTime;
private double _seekClocks;
+ // The pack loaded into the drive
+ DiabloPack _pack;
private AltoSystem _system;
}