1
0
mirror of https://github.com/livingcomputermuseum/ContrAlto.git synced 2026-01-24 03:16:49 +00:00

Hooked disk emulation up to disk images (currently hardcoded). Fixed a small bug in IDISP, tiny stub of Nova disassembler added.

This commit is contained in:
Josh Dersch 2015-10-26 17:46:43 -07:00
parent 3b29addb98
commit 1dfd1e0be9
7 changed files with 197 additions and 16 deletions

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Contralto.CPU
{
/// <summary>
/// Quick and dirty disassembler for Nova instructions, so we can
/// see what the emulator task is executing more clearly.
/// </summary>
public static class NovaDisassembler
{
}
}

View File

@ -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;
}

View File

@ -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
{
/// <summary>

View File

@ -47,7 +47,8 @@
<Compile Include="CPU\ALU.cs" />
<Compile Include="CPU\ConstantMemory.cs" />
<Compile Include="CPU\CPU.cs" />
<Compile Include="CPU\Disassembler.cs" />
<Compile Include="CPU\NovaDisassembler.cs" />
<Compile Include="CPU\UCodeDisassembler.cs" />
<Compile Include="CPU\Tasks\DiskTask.cs" />
<Compile Include="CPU\Tasks\EmulatorTask.cs" />
<Compile Include="CPU\MicroInstruction.cs" />
@ -62,6 +63,7 @@
</Compile>
<Compile Include="IClockable.cs" />
<Compile Include="IO\DiskController.cs" />
<Compile Include="IO\DiabloPack.cs" />
<Compile Include="IO\Keyboard.cs" />
<Compile Include="Memory\IMemoryMappedDevice.cs" />
<Compile Include="Memory\Memory.cs" />
@ -76,6 +78,9 @@
<None Include="Disassembly\altoIIcode3.mu">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Disk\games.dsk">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="ROM\2kctl.u3">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>

BIN
Contralto/Disk/games.dsk Normal file

Binary file not shown.

143
Contralto/IO/DiabloPack.cs Normal file
View File

@ -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<array.Length;i++)
{
array[i] = (ushort)((data[offset]) | (data[offset + 1] << 8));
offset += 2;
}
return array;
}
public ushort[] Header;
public ushort[] Label;
public ushort[] Data;
}
/// <summary>
/// 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)
/// </summary>
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;
}
}

View File

@ -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;
}