From a72a84562344000e31bb5a61d5f3f10f667d99c9 Mon Sep 17 00:00:00 2001 From: Josh Dersch Date: Wed, 29 Jan 2020 02:03:35 +0100 Subject: [PATCH] Slow progress. RH11 can now boot 2.11BSD and load the kernel into memory; XP driver then fails to read the label block, though it looks like the proper transfers take place. Minor code cleanup. --- 10.02_devices/2_src/massbus_rp.cpp | 153 ++++++++++++++++++----------- 10.02_devices/2_src/massbus_rp.hpp | 41 ++++---- 10.02_devices/2_src/rh11.cpp | 132 ++++++++++++++++++++++--- 10.02_devices/2_src/rh11.hpp | 24 +++-- 10.02_devices/2_src/rp_drive.cpp | 11 ++- 10.02_devices/2_src/rp_drive.hpp | 6 +- 6 files changed, 263 insertions(+), 104 deletions(-) diff --git a/10.02_devices/2_src/massbus_rp.cpp b/10.02_devices/2_src/massbus_rp.cpp index 59e93c4..f69fa31 100644 --- a/10.02_devices/2_src/massbus_rp.cpp +++ b/10.02_devices/2_src/massbus_rp.cpp @@ -34,11 +34,11 @@ massbus_rp_c::massbus_rp_c( _workerState(WorkerState::Idle), _workerWakeupCond(PTHREAD_COND_INITIALIZER), _workerMutex(PTHREAD_MUTEX_INITIALIZER), - _vv(false), _err(false), _ata(false), _ready(true), - _ned(false) + _ned(false), + _attnSummary(0) { name.value="MASSBUS_RP"; type_name.value = "massbus_rp_c"; @@ -135,7 +135,15 @@ massbus_rp_c::WriteRegister( UpdateDesiredCylinder(); INFO("Desired Cylinder Address o%o (o%o)", _desiredCylinder, value); - break; + break; + + case Registers::AttentionSummary: + // Clear bits in the Attention Summary register specified in the + // written value: + _attnSummary &= ~(value & 0xff); + _controller->WriteRegister(static_cast(Registers::AttentionSummary), _attnSummary); + INFO("Attention Summary write o%o, value is now o%o", value, _attnSummary); + break; default: FATAL("Unimplemented RP register write."); @@ -155,7 +163,7 @@ void massbus_rp_c::DoCommand( FunctionCode function = static_cast((command & RP_FUNC) >> 1); _selectedUnit = unit; - + INFO("RP function 0%o, unit %o", function, _selectedUnit); if (!SelectedDrive()->IsAvailable()) @@ -163,9 +171,10 @@ void massbus_rp_c::DoCommand( // Early return for disconnected drives; // set NED and ERR bits _err = true; + _ata = true; _ned = true; // TODO: should be done at RH11 level! - _vv = false; - UpdateStatus(); + SelectedDrive()->ClearVolumeValid(); + UpdateStatus(true); return; } @@ -175,6 +184,8 @@ void massbus_rp_c::DoCommand( { case FunctionCode::Nop: // Nothing. + _ata = false; + UpdateStatus(true); break; case FunctionCode::ReadInPreset: @@ -184,11 +195,14 @@ void massbus_rp_c::DoCommand( // sector/track address register, and clears the FMT, HCI, and ECI // bits in the offset register. It is used to bootstrap the device." // - _vv = true; + SelectedDrive()->SetVolumeValid(); + SelectedDrive()->SetDriveReady(); _desiredSector = 0; _desiredTrack = 0; _offset = 0; - UpdateStatus(); + _ata = false; + _ready = true; + UpdateStatus(true); UpdateDesiredSectorTrack(); UpdateOffset(); break; @@ -199,17 +213,6 @@ void massbus_rp_c::DoCommand( case FunctionCode::ReadHeaderAndData: case FunctionCode::Search: INFO("RP Read/Write Data or Search"); - - // Ensure the drive is ready, error if not - if (!SelectedDrive()->IsDriveReady()) - { - _vv = false; - _err = true; - _ata = true; - _ready = true; - UpdateStatus(); - } - else { // Clear the unit's DRY bit SelectedDrive()->ClearDriveReady(); @@ -222,18 +225,20 @@ void massbus_rp_c::DoCommand( // Clear ATA and READY _ata = false; _ready = false; - UpdateStatus(); + UpdateStatus(false); pthread_mutex_lock(&_workerMutex); // Save a copy of command data for the worker to consume _newCommand.unit = _selectedUnit; _newCommand.function = function; + _newCommand.cylinder = _desiredCylinder; + _newCommand.track = _desiredTrack; + _newCommand.sector = _desiredSector; _newCommand.bus_address = _controller->GetBusAddress(); _newCommand.word_count = _controller->GetWordCount(); _newCommand.ready = true; - // Wake the worker pthread_cond_signal(&_workerWakeupCond); pthread_mutex_unlock(&_workerMutex); @@ -252,9 +257,9 @@ massbus_rp_c::ReadRegister( uint32_t unit, uint32_t reg) { - INFO("RP reg read: unit %d register 0%o", unit, reg); + INFO("*** RP reg read: unit %d register 0%o", unit, reg); - FATAL("Unimplemented RP register read."); + FATAL("Unimplemented register read %o", reg); return 0; } @@ -263,7 +268,8 @@ massbus_rp_c::ReadRegister( // Register update functions // void -massbus_rp_c::UpdateStatus() +massbus_rp_c::UpdateStatus( + bool complete) { _error1 = @@ -274,6 +280,7 @@ massbus_rp_c::UpdateStatus() if (_error1 != 0) { _err = true; + _ata = true; } else { @@ -281,7 +288,7 @@ massbus_rp_c::UpdateStatus() } _status = - (_vv ? 0100 : 0) | + (SelectedDrive()->GetVolumeValid() ? 0100 : 0) | (SelectedDrive()->IsDriveReady() ? 0200 : 0) | (0400) | // Drive preset -- always set for a single-controller disk (SelectedDrive()->GetReadLastSector() ? 02000 : 0) | // Last sector read @@ -291,11 +298,22 @@ massbus_rp_c::UpdateStatus() (_err ? 040000 : 0) | // Composite error (_ata ? 0100000 : 0); + INFO("Unit %d Status: o%o", _selectedUnit, _status); _controller->WriteRegister(static_cast(Registers::Status), _status); _controller->WriteRegister(static_cast(Registers::Error1), _error1); + // Update the Attention Summary register if this disk is online: + + if (_ata && SelectedDrive()->IsAvailable()) + { + _attnSummary |= (0x1 << _selectedUnit); // TODO: these only get set, and are latched until + // manually cleared? + } + + _controller->WriteRegister(static_cast(Registers::AttentionSummary), _attnSummary); + // Inform controller of status update. - _controller->BusStatus(_ready, _ata, _err, _ned); + _controller->BusStatus(complete, _ready, _ata, _err, SelectedDrive()->IsAvailable(), _ned); } void @@ -303,6 +321,10 @@ massbus_rp_c::UpdateDesiredSectorTrack() { uint16_t desiredSectorTrack = (_desiredSector | (_desiredTrack << 8)); _controller->WriteRegister(static_cast(Registers::DesiredSectorTrackAddress), desiredSectorTrack); + + // Fudge: We update the look-ahead sector value to be the last-requested sector - 1 + uint16_t lookAhead = (((_desiredSector - 5) % 22) << 6); + _controller->WriteRegister(static_cast(Registers::LookAhead), lookAhead); } void @@ -317,6 +339,13 @@ massbus_rp_c::UpdateOffset() _controller->WriteRegister(static_cast(Registers::Offset), _offset); } +void +massbus_rp_c::UpdateCurrentCylinder() +{ + _controller->WriteRegister(static_cast(Registers::CurrentCylinderAddress), + SelectedDrive()->GetCurrentCylinder()); +} + void massbus_rp_c::Reset() { @@ -325,7 +354,8 @@ massbus_rp_c::Reset() // Reset registers to their defaults _ata = false; _ready = true; - UpdateStatus(); + _attnSummary = 0; + UpdateStatus(false); _desiredSector = 0; _desiredTrack = 0; @@ -334,6 +364,8 @@ massbus_rp_c::Reset() _desiredCylinder = 0; UpdateDesiredCylinder(); + UpdateCurrentCylinder(); + _offset = 0; UpdateOffset(); @@ -380,7 +412,6 @@ massbus_rp_c::Worker() pthread_mutex_unlock(&_workerMutex); _workerState = WorkerState::Execute; - INFO("worker awoken."); break; case WorkerState::Execute: @@ -389,24 +420,24 @@ massbus_rp_c::Worker() case FunctionCode::ReadData: { INFO("READ CHS %d/%d/%d, %d words to address o%o", - _desiredCylinder, - _desiredTrack, - _desiredSector, + _newCommand.cylinder, + _newCommand.track, + _newCommand.sector, _newCommand.word_count, _newCommand.bus_address); uint16_t* buffer = nullptr; if (SelectedDrive()->Read( - _desiredCylinder, - _desiredTrack, - _desiredSector, + _newCommand.cylinder, + _newCommand.track, + _newCommand.sector, _newCommand.word_count, &buffer)) { // // Data read: do DMA transfer to memory. // - _controller->DMAWrite( + _controller->DiskReadTransfer( _newCommand.bus_address, _newCommand.word_count, buffer); @@ -418,15 +449,14 @@ massbus_rp_c::Worker() { // Read failed: INFO("Read failed."); + _ata = true; } // Return drive to ready state SelectedDrive()->SetDriveReady(); - // Signal attention and update status. - _ata = true; + // Signal ready status. _ready = true; - UpdateStatus(); _workerState = WorkerState::Finish; } break; @@ -434,25 +464,29 @@ massbus_rp_c::Worker() case FunctionCode::WriteData: { INFO("WRITE CHS %d/%d/%d, %d words from address o%o", - _desiredCylinder, - _desiredTrack, - _desiredSector, + _newCommand.cylinder, + _newCommand.track, + _newCommand.sector, _newCommand.word_count, _newCommand.bus_address); - - uint16_t* buffer = new uint16_t[_newCommand.word_count]; - assert(buffer); + // + // Data write: do DMA transfer from memory. + // + uint16_t* buffer = _controller->DiskWriteTransfer( + _newCommand.bus_address, + _newCommand.word_count); - if (!SelectedDrive()->Write( - _desiredCylinder, - _desiredTrack, - _desiredSector, + if (!buffer || !SelectedDrive()->Write( + _newCommand.cylinder, + _newCommand.track, + _newCommand.sector, _newCommand.word_count, buffer)) { // Write failed: INFO("Write failed."); + _ata = true; } delete buffer; @@ -460,10 +494,8 @@ massbus_rp_c::Worker() // Return drive to ready state SelectedDrive()->SetDriveReady(); - // Signal attention and update status. - _ata = true; + // Signal ready status. _ready = true; - UpdateStatus(); _workerState = WorkerState::Finish; } break; @@ -471,24 +503,24 @@ massbus_rp_c::Worker() case FunctionCode::Search: { INFO("SEARCH CHS %d/%d/%d", - _desiredCylinder, - _desiredTrack, - _desiredSector); + _newCommand.cylinder, + _newCommand.track, + _newCommand.sector); if (!SelectedDrive()->Search( - _desiredCylinder, - _desiredTrack, - _desiredSector)) + _newCommand.cylinder, + _newCommand.track, + _newCommand.sector)) { // Search failed INFO("Search failed"); } - // Return to ready state + + // Return to ready state, set attention bit. SelectedDrive()->SetDriveReady(); _ata = true; _ready = true; - UpdateStatus(); _workerState = WorkerState::Finish; } break; @@ -503,7 +535,8 @@ massbus_rp_c::Worker() case WorkerState::Finish: _workerState = WorkerState::Idle; SelectedDrive()->SetDriveReady(); - UpdateStatus(); + UpdateCurrentCylinder(); + UpdateStatus(true); break; } diff --git a/10.02_devices/2_src/massbus_rp.hpp b/10.02_devices/2_src/massbus_rp.hpp index fef7006..4935287 100644 --- a/10.02_devices/2_src/massbus_rp.hpp +++ b/10.02_devices/2_src/massbus_rp.hpp @@ -108,6 +108,9 @@ private: volatile uint32_t bus_address; volatile uint32_t word_count; volatile FunctionCode function; + volatile uint32_t cylinder; + volatile uint32_t track; + volatile uint32_t sector; volatile bool ready; } _newCommand; @@ -123,10 +126,11 @@ private: void on_power_changed(void) override; void on_init_changed(void) override; - void UpdateStatus(); + void UpdateStatus(bool completion); void UpdateDesiredSectorTrack(); void UpdateDesiredCylinder(); void UpdateOffset(); + void UpdateCurrentCylinder(); rp_drive_c* SelectedDrive(); @@ -140,7 +144,7 @@ private: { "CS1", false, 0, 0177700 }, // Status { "ER1", false, true , 0, 0177777 }, // Error #1 - writable by diagnostics { "MR" , false, true , 0, 0177777 }, // Maintenance - { "ATN", false, false, 0, 0 }, // Attention summary + { "ATN", false, true, 0, 0377 }, // Attention summary { "DA" , false, true, 0, 0017437 }, // Desired Sector/Track { "LA" , false, false, 0, 0 }, // Look Ahead { "DT" , false, false, 0, 0 }, // Drive Type @@ -155,29 +159,28 @@ private: }; // Unit selected by last command register write - uint32_t _selectedUnit; + volatile uint32_t _selectedUnit; // Register data - uint16_t _status; - uint16_t _error1; - uint16_t _maint; - uint16_t _attn; - uint16_t _desiredSector; - uint16_t _desiredTrack; - uint16_t _offset; - uint16_t _desiredCylinder; - uint16_t _currentCylinder; - uint16_t _error2; - uint16_t _error3; + volatile uint16_t _status; + volatile uint16_t _error1; + volatile uint16_t _maint; + volatile uint16_t _attnSummary; + volatile uint16_t _desiredSector; + volatile uint16_t _desiredTrack; + volatile uint16_t _offset; + volatile uint16_t _desiredCylinder; + volatile uint16_t _currentCylinder; + volatile uint16_t _error2; + volatile uint16_t _error3; // Status bits that we track - bool _vv; - bool _err; - bool _ata; + volatile bool _err; + volatile bool _ata; // RH11 ready signal (ugly: this should be in the rh11 code!) - bool _ready; - bool _ned; // ditto + volatile bool _ready; + volatile bool _ned; // ditto // Worker thread pthread_t _workerThread; diff --git a/10.02_devices/2_src/rh11.cpp b/10.02_devices/2_src/rh11.cpp index 5ffc02e..4ccb2cd 100755 --- a/10.02_devices/2_src/rh11.cpp +++ b/10.02_devices/2_src/rh11.cpp @@ -107,7 +107,7 @@ rh11_c::rh11_c() : // base addr, intr-vector, intr level // TODO: make configurable based on type (fixed, tape, moving-head disk) // right now it is hardcoded for moving-head disks. - set_default_bus_params(0776700, 11, 0254, 5); + set_default_bus_params(0776700, 21, 0254, 6); _massbus.reset(new massbus_rp_c(this)); @@ -146,7 +146,7 @@ rh11_c::rh11_c() : RH_reg[i]->active_on_dati = false; RH_reg[i]->active_on_dato = true; RH_reg[i]->reset_value = 0; - RH_reg[i]->writable_bits = 0xffff; + RH_reg[i]->writable_bits = 0xfffe; break; case RHCS2: @@ -212,11 +212,14 @@ rh11_c::~rh11_c() { } +// TODO: RENAME! This is invoked when the drive is finished with the given command. void rh11_c::BusStatus( + bool completion, bool ready, bool attention, bool error, + bool avail, bool ned) { INFO("Massbus status update attn %d, error %d, ned %d", attention, error, ned); @@ -226,12 +229,19 @@ rh11_c::BusStatus( INFO("RHCS1 is currently o%o", currentStatus); - currentStatus &= ~(0140200); // move to constant + currentStatus &= ~(0140300); // clear status bits, IE, and GO bit : move to constant currentStatus |= (attention ? 0100000 : 0) | // check when this actually gets set? (error ? 0040000 : 0) | + (avail ? 0004000 : 0) | // drive available (ready ? 0000200 : 0); // controller ready bit (should clear when busy) + if (completion) + { + // clear the GO bit from the CS word if the drive is finished. + currentStatus &= ~(01); + } + set_register_dati_value( RH_reg[RHCS1], currentStatus, @@ -254,7 +264,7 @@ rh11_c::BusStatus( INFO("RHCS2 is now o%o", currentStatus); - if (attention) + if ((attention || ready) && completion) { Interrupt(); } @@ -294,12 +304,100 @@ rh11_c::GetBusAddress() return _busAddress; } +// +// Transfers data read from disk to the Unibus. +// Updates RHBA and RHWC registers appropriately. +// +bool +rh11_c::DiskReadTransfer( + uint32_t address, + size_t lengthInWords, + uint16_t* diskBuffer) +{ + // Write the disk data to memory + if (DMAWrite( + address, + lengthInWords, + diskBuffer)) + { + IncrementBusAddress(lengthInWords); + DecrementWordCount(lengthInWords); + return true; + } + else + { + return false; + } +} + +// +// Transfers data from the Unibus to be written to disk. +// Updates RHBA and RHWC registers appropriately. +// +uint16_t* +rh11_c::DiskWriteTransfer( + uint32_t address, + size_t lengthInWords) +{ + uint16_t* buffer = DMARead( + address, + lengthInWords); + + if (buffer) + { + IncrementBusAddress(lengthInWords); + DecrementWordCount(lengthInWords); + } + + return buffer; +} + +void +rh11_c::IncrementBusAddress(uint32_t delta) +{ + _busAddress += delta; + + uint16_t currentStatus = get_register_dato_value(RH_reg[RHCS1]); + + // Clear extended address bits + currentStatus &= ~(0x300); + + currentStatus |= ((_busAddress & 0x30000) >> 8); + set_register_dati_value( + RH_reg[RHCS1], + currentStatus, + "SetBusAddress"); + + set_register_dati_value( + RH_reg[RHBA], + (_busAddress & 0xffff), + "IncrementBusAddress"); + + INFO("BA Reg incr: o%o", _busAddress); +} + uint16_t rh11_c::GetWordCount() { return -get_register_dato_value(RH_reg[RHWC]); } +void +rh11_c::DecrementWordCount(uint16_t delta) +{ + uint16_t currentWordCount = get_register_dato_value(RH_reg[RHWC]); + + currentWordCount += delta; + + set_register_dati_value( + RH_reg[RHWC], + currentWordCount, + "DecrementWordCount"); + + + INFO("WC Reg decr: o%o", currentWordCount); +} + bool rh11_c::DMAWrite( uint32_t address, @@ -323,6 +421,7 @@ rh11_c::DMAWrite( lengthInWords); INFO("Success: %d", dma_request.success); + assert(dma_request.success); return dma_request.success; } @@ -339,8 +438,6 @@ rh11_c::DMARead( uint16_t* buffer = new uint16_t[lengthInWords]; assert (buffer); - memset(reinterpret_cast(buffer), 0xc3, lengthInWords * 2); - unibusadapter->DMA( dma_request, true, @@ -355,6 +452,7 @@ rh11_c::DMARead( } else { + delete buffer; return nullptr; } } @@ -412,8 +510,6 @@ void rh11_c::on_after_register_access( unibusdevice_register_t *device_reg, uint8_t unibus_control) { - UNUSED(unibus_control); - uint16_t value = device_reg->active_dato_flipflops; switch(device_reg->index) @@ -423,15 +519,15 @@ void rh11_c::on_after_register_access( if (UNIBUS_CONTROL_DATO == unibus_control) { // IE bit - _interruptEnable = !!(value & 0x40); + _interruptEnable = ((value & 0x40) != 0); // Extended bus address bits _busAddress = (_busAddress & 0xffff) | ((value & 0x300) << 8); - // Let the massbus device take a crack at the shared bits - _massbus->WriteRegister(_unit, RHCS1, value & 0x3f); + INFO("RHCS1: IE %d BA 0%o", _interruptEnable, _busAddress); - INFO("RHCS1: IE %x BA 0%o", _interruptEnable, _busAddress); + // Let the massbus device take a crack at the shared bits + _massbus->WriteRegister(_unit, RHCS1, value & 0x3f); } } break; @@ -447,12 +543,16 @@ void rh11_c::on_after_register_access( // TODO: handle System Register Clear (bit 5) if (value & 040) // controller clear { + INFO("Controller Clear"); // clear error bits value &= ~(010040); set_register_dati_value( RH_reg[RHCS2], value, - "Reset"); + "Reset"); + + _interruptEnable = false; + _massbus->Reset(); } INFO("RHCS2: unit %d", _unit); } @@ -489,6 +589,7 @@ void rh11_c::on_after_register_access( } else { + INFO("massbus reg read %o", device_reg->index); set_register_dati_value( device_reg, _massbus->ReadRegister(_unit, _unibusToMassbusRegisterMap[device_reg->index]), @@ -506,10 +607,15 @@ void rh11_c::on_after_register_access( void rh11_c::Interrupt(void) { + INFO("interrupt enable is %d", _interruptEnable); if(_interruptEnable) { INFO("Interrupt!"); unibusadapter->INTR(intr_request, nullptr, 0); + + // IE is cleared after the interrupt is raised + // Actual bit is cleared in BusStatus, this should be fixed. + _interruptEnable = false; } } diff --git a/10.02_devices/2_src/rh11.hpp b/10.02_devices/2_src/rh11.hpp index aa4cc44..d387a67 100755 --- a/10.02_devices/2_src/rh11.hpp +++ b/10.02_devices/2_src/rh11.hpp @@ -45,25 +45,31 @@ private: void Interrupt(void); void reset_controller(void); + void IncrementBusAddress(uint32_t delta); + void DecrementWordCount(uint16_t delta); + + bool DMAWrite(uint32_t address, size_t lengthInWords, uint16_t* buffer); + uint16_t* DMARead(uint32_t address, size_t lengthInWords); + private: std::unique_ptr _massbus; // Control & Status reg 1 bits - bool _interruptEnable; - uint32_t _busAddress; + volatile bool _interruptEnable; + volatile uint32_t _busAddress; // Control & Status reg 2 bits - uint16_t _unit; - bool _busAddressIncrementProhibit; - bool _parityTest; + volatile uint16_t _unit; + volatile bool _busAddressIncrementProhibit; + volatile bool _parityTest; public: rh11_c(); virtual ~rh11_c(); - void BusStatus(bool ready, bool attention, bool error, bool ned); + void BusStatus(bool completion, bool ready, bool attention, bool error, bool avail, bool ned); // Unibus register access (for devices on massbus) void WriteRegister(uint32_t reg, uint16_t value); @@ -73,9 +79,9 @@ public: uint32_t GetBusAddress(); uint16_t GetWordCount(); - bool DMAWrite(uint32_t address, size_t lengthInWords, uint16_t* buffer); - uint16_t* DMARead(uint32_t address, size_t lengthInWords); - + bool DiskReadTransfer(uint32_t address, size_t lengthInWords, uint16_t* buffer); + uint16_t* DiskWriteTransfer(uint32_t address, size_t lengthInWords); + public: // background worker function diff --git a/10.02_devices/2_src/rp_drive.cpp b/10.02_devices/2_src/rp_drive.cpp index 930c71c..5ea5aa4 100644 --- a/10.02_devices/2_src/rp_drive.cpp +++ b/10.02_devices/2_src/rp_drive.cpp @@ -23,7 +23,8 @@ rp_drive_c::rp_drive_c(storagecontroller_c *controller, uint32_t driveNumber) : _aoe(false), _iae(false), _wle(false), - _pip(false) + _pip(false), + _vv(false) { set_workers_count(0) ; // needs no worker() log_label = "RP"; @@ -142,6 +143,7 @@ rp_drive_c::Write( } else { + _currentCylinder = cylinder; uint32_t offset = GetSectorForCHS(cylinder, track, sector); file_write(reinterpret_cast(buffer), offset * GetSectorSize(), countInWords * 2); return true; @@ -173,6 +175,8 @@ rp_drive_c::Read( } else { + _currentCylinder = cylinder; + *buffer = new uint16_t[countInWords]; assert(nullptr != *buffer); @@ -180,6 +184,7 @@ rp_drive_c::Read( uint32_t offset = GetSectorForCHS(cylinder, track, sector); INFO("Read from sector offset o%o", offset); file_read(reinterpret_cast(*buffer), offset * GetSectorSize(), countInWords * 2); + return true; } } @@ -205,9 +210,11 @@ rp_drive_c::Search( INFO("Search commencing."); _pip = true; - timeout.wait_ms(50); + timeout.wait_ms(500); _pip = false; + _currentCylinder = cylinder; + return true; } diff --git a/10.02_devices/2_src/rp_drive.hpp b/10.02_devices/2_src/rp_drive.hpp index e35a881..3c64531 100644 --- a/10.02_devices/2_src/rp_drive.hpp +++ b/10.02_devices/2_src/rp_drive.hpp @@ -39,7 +39,10 @@ public: bool GetWriteLockError(void) { return _wle; } void SetDriveReady(void) { _ready = true; } void ClearDriveReady(void) { _ready = false; } - + void SetVolumeValid(void) { _vv = true; } + void ClearVolumeValid(void) { _vv = false; } + bool GetVolumeValid(void) { return _vv; } + bool SeekTo(uint32_t cylinder); uint32_t GetCurrentCylinder(); @@ -60,6 +63,7 @@ private: bool _iae; bool _wle; bool _pip; + bool _vv; bool ValidateCHS(uint32_t cylinder, uint32_t track, uint32_t sector); uint32_t GetSectorForCHS(uint32_t cylinder, uint32_t track, uint32_t sector);