private void InitSeek(int destCylinder)
 {
     _deviceCheck = !SelectedDrive.Seek(destCylinder);
 }
        private void ReadWordCallback(ulong timeNsec, ulong skewNsec, object context)
        {
            if (_readWordCount > 0)
            {
                // Enqueue data from disk.
                ushort dataWord;

                switch (_sectorBlock)
                {
                case SectorBlock.Header:
                    dataWord = SelectedDrive.ReadHeader(_readIndex);
                    break;

                case SectorBlock.Label:
                    dataWord = SelectedDrive.ReadLabel(_readIndex);
                    break;

                case SectorBlock.Data:
                    dataWord = SelectedDrive.ReadData(_readIndex);
                    break;

                default:
                    throw new InvalidOperationException(String.Format("Unexpected Sector Block of {0} on read.", _sectorBlock));
                }

                Log.Write(LogType.Verbose, LogComponent.TridentController, "Read word {0}:{1}", _readIndex, Conversion.ToOctal(dataWord));

                EnqueueInputFIFO(dataWord);

                //
                // Compare data with check data in output fifo, if any.
                // From the microcode comments:
                // "Note that the first two words of a block are always checked,
                //  followed by additional words until a zero word or the end of the block."
                //
                // If we hit a tag word, the check is also completed.
                // TODO: verify this w/schematic & microcode.

                if (_outputFifo.Count > 0)
                {
                    int checkWord = _outputFifo.Peek();
                    if ((checkWord & 0x10000) == 0 && (!_checkDone || _checkedWordCount < 2))
                    {
                        // Actually pull the word off
                        checkWord = (ushort)DequeueOutputFIFO();

                        Log.Write(LogType.Verbose, LogComponent.TridentController, "Pulled checkword {0} from output FIFO", Conversion.ToOctal(checkWord));

                        // A zero word indicates the check is complete (we will
                        // still read the minimum two words in)
                        if (checkWord == 0)
                        {
                            _checkDone = true;
                        }
                        // Compare didn't.
                        else if (checkWord != dataWord)
                        {
                            _compareError = true;
                        }
                        _checkedWordCount++;
                    }
                }
            }
            else
            {
                // Last four words (0 through -3) are checksum and ECC words.
                // The checksum words are ignored by the microcode, and
                // since we're not simulating faulty disks, these are always zero.
                EnqueueInputFIFO(0);
                Log.Write(LogComponent.TridentController, "Read ECC/checksum word 0");
            }

            _readIndex++;
            _readWordCount--;

            if (_readWordCount > -4)
            {
                // More words to read, queue up the next.
                _readWordEvent.TimestampNsec = _readWordDuration;
                _system.Scheduler.Schedule(_readWordEvent);
            }
            else
            {
                Log.Write(LogComponent.TridentController, "CHS {0}/{1}/{2} {3} read from drive {4} complete.", SelectedDrive.Cylinder, SelectedDrive.Head, _sector, _sectorBlock, _selectedDrive);
                _readState    = ReadState.Idle;
                _commandState = CommandState.Command;

                _sectorBlock++;

                //
                // Kick the output event if necessary.
                //
                RescheduleOutputEvent();
            }
        }
Example #3
0
        /// <summary>
        /// "Rotates" the emulated disk platter one clock's worth.
        /// </summary>
        private void SpinDisk()
        {
            //
            // Roughly:  If transfer is enabled:
            //   Select data word based on elapsed time in this sector.
            //   On a new word, wake up the disk word task if not inhibited.
            //
            // If transfer is not enabled BUT the disk word task is enabled,
            // we will still wake up the disk word task if the appropriate clock
            // source is selected.
            //
            // We simulate the movement of a sector under the heads by dividing
            // the sector into word-sized timeslices.  Not all of these slices
            // will actually contain valid data -- some are empty, used by the microcode
            // for lead-in or inter-record delays, but the slices are still used to
            // keep things in line time-wise; the real hardware uses a crystal-controlled clock
            // to generate these slices during these periods (and the clock comes from the
            // drive itself when actual data is present).  For our purposes, the two clocks
            // are one and the same.
            //

            //
            // Pick out the word that just passed under the head.  This may not be
            // actual data (it could be the pre-header delay, inter-record gaps or sync words)
            // and we may not actually end up doing anything with it, but we may
            // need it to decide whether to do anything at all.
            //
            DataCell diskWord = SelectedDrive.ReadWord(_sectorWordIndex);

            bool bWakeup = false;

            //
            // If the word task is enabled AND the write ("crystal") clock is enabled
            // then we will wake up the word task now.
            //
            if (!_seclate && !_wdInhib && !_bClkSource)
            {
                bWakeup = true;
            }

            //
            // If the clock is enabled OR the WFFO bit is set (go ahead and run the bit clock)
            // and we weren't late reading this sector,  then we will wake up the word task
            // and read in the data if transfers are not inhibited.
            //
            if (!_seclate && (_wffo || _diskBitCounterEnable))
            {
                if (!_xferOff)
                {
                    if (!IsWrite())
                    {
                        // 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)
                        {
                            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.Data));
                        _kDataRead = diskWord.Data;
                        _debugRead = diskWord.Type == CellType.Data;

                        _lastDiskActivity = DiskActivityType.Read;
                    }
                    else
                    {
                        // Write
                        Log.Write(LogType.Verbose, 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)
                        {
                            // Commit actual data to disk now that the sync word has been laid down
                            SelectedDrive.WriteWord(_sectorWordIndex, _kDataWrite);
                            _lastDiskActivity = DiskActivityType.Write;
                        }
                    }
                }

                if (!_wdInhib)
                {
                    bWakeup = true;
                }
            }

            //
            // If the WFFO bit is cleared (wait for the sync word to be read)
            // then we check the word for a "1" (the sync word) to enable
            // the clock.  This occurs late in the cycle so that the NEXT word
            // (not the sync word) is actually read.
            //
            if (!IsWrite() && !_wffo && diskWord.Data == 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 = DiabloDrive.HeaderOffset;
                    break;

                case 1:
                    _sectorWordIndex = DiabloDrive.LabelOffset;
                    break;

                case 2:
                    _sectorWordIndex = DiabloDrive.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++;
        }
Example #4
0
 internal static void MakeDriveValid(SelectedDrive item)
 {
     item.SelectedDrivePath = @"C:\";
     Assert.IsTrue(String.IsNullOrWhiteSpace(item.Error), "SelectedDrive had validation errors: {0}", item.Error);
 }
Example #5
0
 internal static void MakeDriveInvalidNoImages(SelectedDrive item)
 {
     item.SelectedDrivePath = @"C:\";
     Assert.IsTrue(!String.IsNullOrWhiteSpace(item.Error));
     Assert.IsTrue(item.PhotoFiles.Count == 0);
 }
Example #6
0
 internal static void MakeDriveInvalidNoDriveAndNoImages(SelectedDrive item)
 {
     item.SelectedDrivePath = String.Empty;
     Assert.IsTrue(!String.IsNullOrWhiteSpace(item.Error));
     Assert.IsTrue(item.PhotoFiles.Count == 0);
 }
Example #7
0
 internal static void MakeDriveValid(SelectedDrive item)
 {
     item.SelectedDrivePath = @"C:\";
     Assert.IsTrue(String.IsNullOrWhiteSpace(item.Error), "SelectedDrive had validation errors: {0}", item.Error);
 }