1
0
mirror of https://github.com/livingcomputermuseum/ContrAlto.git synced 2026-04-20 01:23:35 +00:00

Implemented disk writes (roughly). Bravo now works. DIEX passes with writes enabled. Begun investigation into drive selection logic. Added Mesa source code with annotation, is displayed in ROM1 tab.

This commit is contained in:
Josh Dersch
2015-12-02 12:39:10 -08:00
parent f256042cf4
commit 2c2ea68a63
12 changed files with 1389 additions and 1242 deletions

View File

@@ -16,7 +16,7 @@ namespace Contralto.IO
_pack = new DiabloPack(DiabloDiskType.Diablo31);
// TODO: this does not belong here.
FileStream fs = new FileStream("Disk\\games.dsk", FileMode.Open, FileAccess.Read);
FileStream fs = new FileStream("Disk\\nonprog.dsk", FileMode.Open, FileAccess.Read);
_pack.Load(fs);
@@ -38,6 +38,7 @@ namespace Contralto.IO
set
{
_kDataWrite = value;
_kDataWriteLatch = true;
}
}
@@ -48,10 +49,13 @@ namespace Contralto.IO
{
_kAdr = value;
_recNo = 0;
_syncWordWritten = false;
// "In addition, it causes the head address bit to be loaded from KDATA[13]."
int newHead = (_kDataWrite & 0x4) >> 2;
_disk = ((_kDataWrite & 0x2) >> 1) ^ (_kAdr & 0x1);
if (newHead != _head)
{
// If we switch heads, we need to reload the sector
@@ -79,8 +83,24 @@ namespace Contralto.IO
(_kDataWrite & 0x2) >> 1,
(_kDataWrite & 0x1));
Log.Write(LogComponent.DiskController, " -Selected disk is {0}", ((_kDataWrite & 0x2) >> 1) ^ (_kAdr & 0x1));
Log.Write(LogComponent.DiskController, " -Selected disk is {0}", _disk);
if (((_kAdr & 0xc) >> 2) == 2 ||
((_kAdr & 0xc) >> 2) == 3)
{
Console.WriteLine("DATA WRITE");
}
if (_disk != 0)
{
Console.WriteLine("*** DISK 1 SELECTED ***");
}
if ((_kDataWrite & 0x1) != 0)
{
// Restore operation to cyl. 0:
InitSeek(0);
}
}
}
@@ -121,7 +141,8 @@ namespace Contralto.IO
{
get
{
// Bits 4-7 of KSTAT are always 1s.
// 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
@@ -139,12 +160,7 @@ namespace Contralto.IO
{
get { return _dataXfer; }
}
/// <summary>
/// This is a hack to see how the microcode expects INIT to work
/// </summary>
public int Cylinder
{
get { return _cylinder; }
@@ -179,9 +195,8 @@ namespace Contralto.IO
{
get
{
// TODO: verify if this is correct.
// Not ready if we're in the middle of a seek.
return (_kStat & 0x0040) == 0;
// TODO: verify what generates this signal
return true;
}
}
@@ -192,9 +207,11 @@ namespace Contralto.IO
_cylinder = _destCylinder = 0;
_sector = 0;
_head = 0;
_disk = 0;
_kStat = 0;
_kDataRead = 0;
_kDataWrite = 0;
_kDataWriteLatch = false;
_sendAdr = false;
_wdInhib = true;
@@ -202,6 +219,9 @@ namespace Contralto.IO
_wdInit = false;
_syncWordWritten = false;
_sectorModified = false;
_diskBitCounterEnable = false;
_sectorWordIndex = 0;
@@ -229,7 +249,14 @@ 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.
//
@@ -238,9 +265,10 @@ namespace Contralto.IO
_kStat = (ushort)((_kStat & 0x0fff) | (_sector << 12));
// Reset internal state machine for sector data
_sectorWordIndex = 0;
_sectorWordIndex = 0;
_syncWordWritten = false;
_kDataRead = 0;
_kDataRead = 0;
// Load new sector in
LoadSector();
@@ -346,6 +374,8 @@ namespace Contralto.IO
_kAdr = (ushort)(_kAdr << 2);
_recNo++;
_syncWordWritten = false;
if (_recNo > 3)
{
// sanity check for now
@@ -370,7 +400,12 @@ namespace Contralto.IO
Log.Write(LogComponent.DiskController, "STROBE: Seek initialized.");
_destCylinder = (_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.
@@ -395,7 +430,7 @@ namespace Contralto.IO
_seekEvent.TimestampNsec = _seekDuration;
_system.Scheduler.Schedule(_seekEvent);
Log.Write(LogComponent.DiskController, "Seek to {0} from {1} commencing. Will take {2} nsec.", _destCylinder, _cylinder, _seekDuration);
}
}
@@ -411,7 +446,7 @@ namespace Contralto.IO
//
double seekTimeMsec = 15.0 + 8.6 * Math.Sqrt(dt);
return (ulong)(seekTimeMsec * Conversion.MsecToNsec); // hack to speed things up
return (ulong)(seekTimeMsec * Conversion.MsecToNsec);
}
/// <summary>
@@ -465,16 +500,47 @@ namespace Contralto.IO
{
if (!_xferOff)
{
// Debugging: on a read/check, if we are overwriting a word that was never read by the
// microcode via KDATA, log it.
if (_debugRead && (((KADR & 0x00c0) >> 6) == 0 || ((KADR & 0x00c0) >> 6) == 1))
if (!IsWrite())
{
Console.WriteLine("--- missed sector word {0}({1}) ---", _sectorWordIndex, _kDataRead);
}
// Read operation:
// Debugging: on a read/check, if we are overwriting a word that was never read by the
// microcode via KDATA, log it.
if (_debugRead)
{
Console.WriteLine("--- 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));
_kDataRead = diskWord;
_debugRead = _sectorData[_sectorWordIndex].Type == CellType.Data;
}
else
{
// Write
Log.Write(LogType.Normal, LogComponent.DiskController, "Sector {0} Word {1} (rec {2}) to be written with {3} from KDATA", _sector, _sectorWordIndex, _recNo, Conversion.ToOctal(_kDataWrite));
if (_kDataWriteLatch)
{
_kDataRead = _kDataWrite;
_kDataWriteLatch = false;
}
if (_syncWordWritten && _sectorWordIndex < _sectorData.Length)
{
if (_sectorData[_sectorWordIndex].Type == CellType.Data)
{
Console.WriteLine("Data written to data section.");
_sectorData[_sectorWordIndex].Data = _kDataWrite;
}
else
{
Console.WriteLine("Data written to non-data section.");
_sectorData[_sectorWordIndex].Data = _kDataWrite;
}
_sectorModified = true;
}
}
}
if (!_wdInhib)
@@ -489,16 +555,38 @@ 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 (!_wffo && diskWord == 1)
if (!IsWrite() && !_wffo && diskWord == 1)
{
_diskBitCounterEnable = true;
}
else if (IsWrite() && _wffo && _kDataWrite == 1 && !_syncWordWritten)
{
Log.Write(LogType.Normal, LogComponent.DiskController, "Sector {0} Sync Word {1} (rec {2}) written.", _sector, _sectorWordIndex, _recNo);
_syncWordWritten = true;
// "Adjust" the write index to the start of the data area for the current record.
// This is cheating.
switch(_recNo)
{
case 0:
_sectorWordIndex = _headerOffset;
break;
case 1:
_sectorWordIndex = _labelOffset;
break;
case 2:
_sectorWordIndex = _dataOffset;
break;
}
}
if (bWakeup)
{
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++;
@@ -549,6 +637,37 @@ namespace Contralto.IO
}
/// <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).
@@ -576,7 +695,7 @@ namespace Contralto.IO
_sectorData[_dataOffset] = new DataCell(1, CellType.Sync);
// read-postamble
for (int i = _dataOffset + 257; i < _sectorWordCount;i++)
for (int i = _dataOffset + 258; i < _sectorWordCount;i++)
{
_sectorData[i] = new DataCell(0, CellType.Gap);
}
@@ -606,8 +725,14 @@ namespace Contralto.IO
return checksum;
}
private bool IsWrite()
{
return ((_kAdr & 0x00c0) >> 6) == 2 || ((_kAdr & 0x00c0) >> 6) == 3;
}
private ushort _kDataRead;
private ushort _kDataWrite;
private bool _kDataWriteLatch;
private ushort _kAdr;
private ushort _kCom;
private ushort _kStat;
@@ -634,12 +759,18 @@ namespace Contralto.IO
private int _head;
private int _sector;
// Selected disk
private int _disk;
// bit clock flag
private bool _diskBitCounterEnable;
// WDINIT signal
private bool _wdInit;
private bool _syncWordWritten;
private bool _sectorModified;
// Sector timing. Based on table on pg. 43 of the Alto Hardware Manual
// From altoconsts23.mu: [all constants in octal, for reference]