mirror of
https://github.com/livingcomputermuseum/UniBone.git
synced 2026-04-02 20:17:07 +00:00
Further cleanup, implementation of missing commands.
This commit is contained in:
@@ -107,6 +107,7 @@ massbus_rp_c::SelectUnit(
|
||||
// may cause status register updates.
|
||||
SelectedDrive()->Select();
|
||||
UpdateDriveRegisters();
|
||||
UpdateDriveInfo();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,9 +123,6 @@ massbus_rp_c::WriteRegister(
|
||||
switch(static_cast<Registers>(reg))
|
||||
{
|
||||
case Registers::Control:
|
||||
//
|
||||
// Select unit as necessary.
|
||||
//
|
||||
drive->DoCommand(value);
|
||||
break;
|
||||
|
||||
@@ -142,9 +140,16 @@ massbus_rp_c::WriteRegister(
|
||||
case Registers::AttentionSummary:
|
||||
// Clear bits in the Attention Summary register specified in the
|
||||
// written value:
|
||||
_attnSummary &= ~(value & 0xff);
|
||||
_controller->WriteRegister(reg, _attnSummary);
|
||||
DEBUG("Attention Summary write o%o, value is now o%o", value, _attnSummary);
|
||||
for(int i=0;i<8;i++)
|
||||
{
|
||||
if (value & (0x1 << i))
|
||||
{
|
||||
GetDrive(i)->ClearAttention();
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAttentionSummary();
|
||||
INFO ("Attention Summary write o%o, value is now o%o", value, _attnSummary);
|
||||
break;
|
||||
|
||||
case Registers::Error1:
|
||||
@@ -167,19 +172,10 @@ uint16_t
|
||||
massbus_rp_c::ReadRegister(
|
||||
uint32_t reg)
|
||||
{
|
||||
DEBUG("RP reg read: unit %d register 0%o", _selectedUnit, reg);
|
||||
INFO ("RP reg read: unit %d register 0%o", _selectedUnit, reg);
|
||||
|
||||
switch(static_cast<Registers>(reg))
|
||||
{
|
||||
|
||||
case Registers::DriveType:
|
||||
return SelectedDrive()->GetDriveType() | 020000; // Moving head (MOVE TO CONSTANT)
|
||||
break;
|
||||
|
||||
case Registers::SerialNo:
|
||||
return SelectedDrive()->GetSerialNumber();
|
||||
break;
|
||||
|
||||
default:
|
||||
FATAL("Unimplemented register read %o", reg);
|
||||
break;
|
||||
@@ -206,37 +202,54 @@ massbus_rp_c::DriveStatus(
|
||||
{
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::Status), status);
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::Error1), error1);
|
||||
UpdateDriveRegisters();
|
||||
}
|
||||
|
||||
// Update the Attention Summary register for the reporting drive:
|
||||
if (ata)
|
||||
// if (ata) // TODO: be nice to avoid doing this every time.
|
||||
{
|
||||
_attnSummary |= (0x1 << unit);
|
||||
UpdateAttentionSummary();
|
||||
INFO ("Attention Summary is now o%o", _attnSummary);
|
||||
}
|
||||
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::AttentionSummary), _attnSummary);
|
||||
|
||||
// Inform controller of status update.
|
||||
// TODO: ready status is a hack that serializes drive commands;
|
||||
// a real RH11/RP06 setup allows overlapped seeks, we do not (yet).
|
||||
|
||||
bool ready = true;
|
||||
|
||||
for(int i=0;i<8;i++)
|
||||
{
|
||||
if (GetDrive(i)->IsConnected() && !GetDrive(i)->IsDriveReady())
|
||||
{
|
||||
ready = false;// We're ready if there isn't a command in progress right now.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_controller->BusStatus(complete, ready, ata, (error1 != 0), SelectedDrive()->IsConnected(), _ned);
|
||||
_controller->BusStatus(complete, ata, (error1 != 0), SelectedDrive()->IsConnected(), _ned);
|
||||
|
||||
pthread_mutex_unlock(&_updateLock);
|
||||
}
|
||||
|
||||
void
|
||||
massbus_rp_c::UpdateAttentionSummary()
|
||||
{
|
||||
//
|
||||
// Collect summary bits from all drives
|
||||
//
|
||||
_attnSummary = 0;
|
||||
for(int i=0;i<8;i++)
|
||||
{
|
||||
bool attn = GetDrive(i)->GetAttention();
|
||||
if (attn)
|
||||
{
|
||||
_attnSummary |= (0x1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::AttentionSummary), _attnSummary);
|
||||
}
|
||||
|
||||
void
|
||||
massbus_rp_c::UpdateDriveInfo()
|
||||
{
|
||||
rp_drive_c* drive = SelectedDrive();
|
||||
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::DriveType),
|
||||
drive->GetDriveType() | 020000);
|
||||
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::SerialNo),
|
||||
drive->GetSerialNumber());
|
||||
}
|
||||
|
||||
void
|
||||
massbus_rp_c::UpdateDriveRegisters()
|
||||
{
|
||||
|
||||
@@ -92,9 +92,11 @@ public:
|
||||
private:
|
||||
void on_power_changed(void) override;
|
||||
void on_init_changed(void) override;
|
||||
|
||||
|
||||
void UpdateAttentionSummary();
|
||||
void UpdateDriveInfo();
|
||||
void UpdateDriveRegisters();
|
||||
|
||||
|
||||
rp_drive_c* SelectedDrive();
|
||||
rp_drive_c* GetDrive(uint16_t unit);
|
||||
|
||||
@@ -110,13 +112,13 @@ private:
|
||||
{ "MR" , false, true, 0, 0177777 }, // 3, Maintenance
|
||||
{ "ATN", false, true, 0, 0377 }, // 4, Attention summary
|
||||
{ "DA" , false, true, 0, 0017437 }, // 5, Desired Sector/Track
|
||||
{ "DT" , true, true, 0, 0 }, // 6, Drive Type
|
||||
{ "DT" , false, false, 020022, 0 }, // 6, Drive Type
|
||||
{ "LA" , false, false, 0, 0 }, // 7, Look Ahead
|
||||
{ "ER2", false, false, 0, 0 }, // 10, Error #2
|
||||
{ "OFF", false, false, 0, 0177777 }, // 11, Offset
|
||||
{ "DCY", false, true, 0, 0001777 }, // 12, Desired Cylinder
|
||||
{ "CCY", false, false, 0, 0 }, // 13, Current Cylinder
|
||||
{ "SN" , true, true, 0, 0 }, // 14, Serial Number
|
||||
{ "SN" , false, false, 012345, 0 }, // 14, Serial Number
|
||||
{ "ER3", false, false, 0, 0 }, // 15, Error #3
|
||||
{ "EPO", false, false, 0, 0 }, // 16, ECC Position
|
||||
{ "EPA", false, false, 0, 0 }, // 17, ECC Pattern
|
||||
|
||||
@@ -221,34 +221,48 @@ rh11_c::rh11_c() :
|
||||
drive->parent = this;
|
||||
storagedrives.push_back(drive);
|
||||
}
|
||||
|
||||
|
||||
_massbus->SelectUnit(0);
|
||||
}
|
||||
|
||||
rh11_c::~rh11_c()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rh11_c::StartDataTransfer()
|
||||
{
|
||||
_ready = false;
|
||||
UpdateCS1(false);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
DEBUG("Massbus status update attn %d, error %d, ned %d", attention, error, ned);
|
||||
INFO ("Massbus status update attn %d, error %d, ned %d", attention, error, ned);
|
||||
|
||||
_attention = attention;
|
||||
_error = error;
|
||||
_avail = avail;
|
||||
_ready = ready;
|
||||
|
||||
|
||||
bool ready = false;
|
||||
if (completion)
|
||||
{
|
||||
// clear the GO bit from the CS word if the drive is finished.
|
||||
_go = false;
|
||||
_go = false;
|
||||
|
||||
// If the controller was busy due to a data transfer,
|
||||
// on completion, we are ready again and may need to interrupt.
|
||||
if (!_ready & completion)
|
||||
{
|
||||
_ready = ready = true;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateCS1(false /* no interrupt, yet */);
|
||||
@@ -280,7 +294,7 @@ rh11_c::UpdateCS1(bool interrupt)
|
||||
(_function << 1) |
|
||||
(_go ? 0000001 : 0);
|
||||
|
||||
DEBUG("RHCS1 is now o%o", newStatus);
|
||||
INFO ("RHCS1 is now o%o", newStatus);
|
||||
|
||||
if (interrupt)
|
||||
{
|
||||
@@ -308,7 +322,7 @@ void rh11_c::UpdateCS2()
|
||||
(_busAddressIncrementProhibit ? 0000010 : 0) |
|
||||
(_unit);
|
||||
|
||||
DEBUG("RHCS2 is now o%o", newStatus);
|
||||
INFO ("RHCS2 is now o%o", newStatus);
|
||||
|
||||
set_register_dati_value(
|
||||
RH_reg[RHCS2],
|
||||
@@ -566,7 +580,7 @@ void rh11_c::on_after_register_access(
|
||||
// We thus update only the affected bits, and only send the function
|
||||
// code to the Massbus when the LSB is written.
|
||||
|
||||
DEBUG("RHCS1: DATO o%o MASK o%o", value, dato_mask);
|
||||
INFO ("RHCS1: DATO o%o MASK o%o", value, dato_mask);
|
||||
|
||||
if ((dato_mask & 0xff00) == 0xff00)
|
||||
{
|
||||
@@ -604,12 +618,12 @@ void rh11_c::on_after_register_access(
|
||||
//
|
||||
if (ready && _interruptEnable)
|
||||
{
|
||||
DEBUG("Forced interrupt.");
|
||||
INFO ("Forced interrupt.");
|
||||
unibusadapter->INTR(intr_request, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG("RHCS1: IE %d BA o%o func o%o go %d", _interruptEnable, _busAddress, _function, _go);
|
||||
INFO ("RHCS1: IE %d BA o%o func o%o go %d", _interruptEnable, _busAddress, _function, _go);
|
||||
UpdateCS1(false /* no interrupt */);
|
||||
|
||||
if ((dato_mask & 0x00ff) == 0x00ff)
|
||||
@@ -631,8 +645,8 @@ void rh11_c::on_after_register_access(
|
||||
_controllerClear = !!(value & 040);
|
||||
_parityError = !!(value & 0020000);
|
||||
|
||||
DEBUG("RHCS2 write: o%o", value);
|
||||
DEBUG("RHCS2: perror %d, unit %d inc %d ptest %d clear %d",
|
||||
INFO ("RHCS2 write: o%o", value);
|
||||
INFO ("RHCS2: perror %d, unit %d inc %d ptest %d clear %d",
|
||||
_parityError, _unit, _busAddressIncrementProhibit, _parityTest, _controllerClear);
|
||||
|
||||
// On unit change, select new drive
|
||||
@@ -645,7 +659,7 @@ void rh11_c::on_after_register_access(
|
||||
// TODO: handle System Register Clear (bit 5)
|
||||
if (_controllerClear)
|
||||
{
|
||||
DEBUG("Controller Clear");
|
||||
INFO ("Controller Clear");
|
||||
_interruptEnable = false;
|
||||
|
||||
for (uint32_t i=0; i<drivecount; i++)
|
||||
@@ -659,7 +673,7 @@ void rh11_c::on_after_register_access(
|
||||
_ned = false;
|
||||
_nxm = false;
|
||||
|
||||
DEBUG("RHCS2: is now o%o", value);
|
||||
INFO ("RHCS2: is now o%o", value);
|
||||
_controllerClear = false;
|
||||
}
|
||||
|
||||
@@ -672,7 +686,7 @@ void rh11_c::on_after_register_access(
|
||||
{
|
||||
if (UNIBUS_CONTROL_DATO == unibus_control)
|
||||
{
|
||||
DEBUG("RHWC: o%o", value);
|
||||
INFO ("RHWC: o%o", value);
|
||||
|
||||
set_register_dati_value(
|
||||
RH_reg[RHWC],
|
||||
@@ -687,7 +701,7 @@ void rh11_c::on_after_register_access(
|
||||
if (UNIBUS_CONTROL_DATO == unibus_control)
|
||||
{
|
||||
_busAddress = (_busAddress & 0x30000) | value;
|
||||
DEBUG("RHBA: o%o", _busAddress);
|
||||
INFO ("RHBA: o%o", _busAddress);
|
||||
|
||||
set_register_dati_value(
|
||||
RH_reg[RHWC],
|
||||
|
||||
@@ -87,7 +87,9 @@ public:
|
||||
rh11_c();
|
||||
virtual ~rh11_c();
|
||||
|
||||
void BusStatus(bool completion, bool ready, bool attention, bool error, bool avail, bool ned);
|
||||
void StartDataTransfer();
|
||||
void StopDataTransfer();
|
||||
void BusStatus(bool completion, bool attention, bool error, bool avail, bool ned);
|
||||
|
||||
// Unibus register access (for devices on massbus)
|
||||
void WriteRegister(uint32_t reg, uint16_t value);
|
||||
|
||||
@@ -59,7 +59,16 @@ rp_drive_c::~rp_drive_c()
|
||||
void
|
||||
rp_drive_c::Reset()
|
||||
{
|
||||
INFO ("Drive %d reset", _driveNumber);
|
||||
|
||||
// TODO: how to deal with the worker thread.
|
||||
// In the case of a Controller Clear, for example,
|
||||
// it needs to terminate its work immediately, which may
|
||||
// not be possible if a DMA transfer is in progress.
|
||||
// If we can make the above happen, it's reasonable to block
|
||||
// here until the worker has returned to idle.
|
||||
// (Maybe?)
|
||||
|
||||
}
|
||||
|
||||
// on_param_changed():
|
||||
@@ -137,12 +146,15 @@ void rp_drive_c::DoCommand(
|
||||
|
||||
INFO ("RP function 0%o, unit %o", function, _driveNumber);
|
||||
|
||||
if (!_ready)
|
||||
if (!_ready && FunctionCode::DriveClear != function)
|
||||
{
|
||||
// For now, halt -- This should never happen with valid code.
|
||||
// After things are stable, this should set error bits.
|
||||
FATAL("Unit %d - Command sent while not ready!", _driveNumber);
|
||||
}
|
||||
|
||||
// TODO: when Error Summary bit is set in ER1, the drive will accept no commands
|
||||
// apart from a DRIVE CLEAR command.
|
||||
|
||||
_ned = false;
|
||||
_ata = false;
|
||||
@@ -162,7 +174,7 @@ void rp_drive_c::DoCommand(
|
||||
// by unloading the disk image and waiting until a new one is loaded.
|
||||
// Right now I'm just treating it as a no-op, at least until I can find a good
|
||||
// way to test it using real software.
|
||||
DEBUG("RP Unload");
|
||||
INFO ("RP Unload");
|
||||
_ata = true;
|
||||
UpdateStatus(true, false);
|
||||
break;
|
||||
@@ -185,9 +197,11 @@ void rp_drive_c::DoCommand(
|
||||
break;
|
||||
|
||||
case FunctionCode::Release:
|
||||
DEBUG("RP Release");
|
||||
INFO ("RP Release");
|
||||
// This is a no-op, this only applies to dual-ported configurations,
|
||||
// which we are not.
|
||||
_ata = false;
|
||||
UpdateStatus(false, false);
|
||||
break;
|
||||
|
||||
case FunctionCode::ReadInPreset:
|
||||
@@ -206,7 +220,7 @@ void rp_drive_c::DoCommand(
|
||||
break;
|
||||
|
||||
case FunctionCode::PackAcknowledge:
|
||||
DEBUG("RP Pack Acknowledge");
|
||||
INFO ("RP Pack Acknowledge");
|
||||
_vv = true;
|
||||
UpdateStatus(false, false);
|
||||
break;
|
||||
@@ -244,6 +258,13 @@ void rp_drive_c::DoCommand(
|
||||
// Positioning in progress.
|
||||
_pip = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a data transfer command,
|
||||
// let the controller know so it can clear its READY bit
|
||||
// for the duration.
|
||||
_controller->StartDataTransfer();
|
||||
}
|
||||
|
||||
UpdateStatus(false, false);
|
||||
|
||||
@@ -266,6 +287,7 @@ void rp_drive_c::DoCommand(
|
||||
// Wake the worker
|
||||
pthread_cond_signal(&_workerWakeupCond);
|
||||
pthread_mutex_unlock(&_workerMutex);
|
||||
INFO ("Command queued for worker.");
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -281,14 +303,14 @@ rp_drive_c::worker(unsigned instance)
|
||||
{
|
||||
UNUSED(instance);
|
||||
|
||||
worker_init_realtime_priority(rt_device);
|
||||
// worker_init_realtime_priority(rt_device);
|
||||
|
||||
_workerState = WorkerState::Idle;
|
||||
WorkerCommand command = { 0 };
|
||||
|
||||
timeout_c timeout;
|
||||
|
||||
INFO ("rp_drive worker started.");
|
||||
INFO ("rp_drive %d worker started.", _driveNumber);
|
||||
while (!workers_terminate)
|
||||
{
|
||||
switch(_workerState)
|
||||
@@ -312,31 +334,69 @@ rp_drive_c::worker(unsigned instance)
|
||||
|
||||
case WorkerState::Execute:
|
||||
{
|
||||
INFO ("Worker executing function o%o", command.function);
|
||||
switch(command.function)
|
||||
{
|
||||
case FunctionCode::ReadHeaderAndData:
|
||||
case FunctionCode::ReadData:
|
||||
{
|
||||
uint16_t* buffer = nullptr;
|
||||
if (Read(
|
||||
command.word_count,
|
||||
&buffer))
|
||||
INFO ("Read wc %d", command.word_count);
|
||||
if (FunctionCode::ReadHeaderAndData == command.function)
|
||||
{
|
||||
//
|
||||
// Data read: do DMA transfer to memory.
|
||||
//
|
||||
// Per EK-RP056-MM-01 a READ HEADER AND DATA command
|
||||
// is functionally identical to a READ DATA command
|
||||
// except four extra words are sent prior to the sector data.
|
||||
// These are:
|
||||
// 1. Cylinder address and format bit:
|
||||
// TODO: where is this format bit?
|
||||
// 2. Sector/Track address:
|
||||
// bits 0-4 specify sector, bits 8-12 indicate track.
|
||||
// (i.e identical to the DA register format)
|
||||
// 3, 4. Key Field - programmer defined, at format time.
|
||||
// We return a header that matches the expected disk address.
|
||||
uint16_t* header = new uint16_t[4];
|
||||
assert(header);
|
||||
|
||||
header[0] = _desiredCylinder;
|
||||
header[1] = _desiredSector | (_desiredTrack << 8);
|
||||
header[2] = 0;
|
||||
header[3] = 0;
|
||||
|
||||
_controller->DiskReadTransfer(
|
||||
command.bus_address,
|
||||
command.word_count,
|
||||
buffer);
|
||||
|
||||
// Free buffer
|
||||
delete buffer;
|
||||
std::min(4, command.word_count),
|
||||
header);
|
||||
|
||||
command.bus_address += 8;
|
||||
command.word_count -= 4;
|
||||
delete[] header;
|
||||
}
|
||||
else
|
||||
|
||||
// Any words left?
|
||||
if (command.word_count > 0)
|
||||
{
|
||||
// Read failed:
|
||||
DEBUG("Read failed.");
|
||||
_ata = true;
|
||||
uint16_t* buffer = nullptr;
|
||||
if (Read(
|
||||
command.word_count,
|
||||
&buffer))
|
||||
{
|
||||
//
|
||||
// Data read: do DMA transfer to memory.
|
||||
//
|
||||
_controller->DiskReadTransfer(
|
||||
command.bus_address,
|
||||
command.word_count,
|
||||
buffer);
|
||||
|
||||
// Free buffer
|
||||
delete[] buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read failed:
|
||||
INFO ("Read failed.");
|
||||
_ata = true;
|
||||
}
|
||||
}
|
||||
|
||||
_workerState = WorkerState::Finish;
|
||||
@@ -357,11 +417,11 @@ rp_drive_c::worker(unsigned instance)
|
||||
buffer))
|
||||
{
|
||||
// Write failed:
|
||||
DEBUG("Write failed.");
|
||||
INFO ("Write failed.");
|
||||
_ata = true;
|
||||
}
|
||||
|
||||
delete buffer;
|
||||
delete[] buffer;
|
||||
|
||||
_workerState = WorkerState::Finish;
|
||||
}
|
||||
@@ -372,7 +432,7 @@ rp_drive_c::worker(unsigned instance)
|
||||
if (!Search())
|
||||
{
|
||||
// Search failed
|
||||
DEBUG("Search failed");
|
||||
INFO ("Search failed");
|
||||
}
|
||||
|
||||
// Return to ready state, set attention bit.
|
||||
@@ -381,11 +441,16 @@ rp_drive_c::worker(unsigned instance)
|
||||
}
|
||||
break;
|
||||
|
||||
case FunctionCode::Recalibrate:
|
||||
INFO ("RECALIBRATE");
|
||||
// Treat a Recal as a seek to zero.
|
||||
_desiredCylinder = 0;
|
||||
// Fall through to seek.
|
||||
case FunctionCode::Seek:
|
||||
if (!SeekTo())
|
||||
{
|
||||
// Seek failed
|
||||
DEBUG("Seek failed");
|
||||
INFO ("Seek failed");
|
||||
}
|
||||
_ata = true;
|
||||
_workerState = WorkerState::Finish;
|
||||
@@ -397,7 +462,7 @@ rp_drive_c::worker(unsigned instance)
|
||||
// cylinders so these are both effectively no-ops, but
|
||||
// they're no-ops that need to take a small amount of time
|
||||
// to complete.
|
||||
DEBUG("OFFSET/RETURN TO CL");
|
||||
INFO ("OFFSET/RETURN TO CL");
|
||||
timeout.wait_ms(10);
|
||||
_ata = true;
|
||||
_workerState = WorkerState::Finish;
|
||||
@@ -418,7 +483,7 @@ rp_drive_c::worker(unsigned instance)
|
||||
pthread_mutex_lock(&_workerMutex);
|
||||
_newCommand.ready = false;
|
||||
pthread_mutex_unlock(&_workerMutex);
|
||||
UpdateStatus(true, false);
|
||||
UpdateStatus(true, false);
|
||||
break;
|
||||
|
||||
}
|
||||
@@ -550,7 +615,7 @@ rp_drive_c::Read(
|
||||
if (!IsConnected() || !IsPackLoaded() || _iae)
|
||||
{
|
||||
*buffer = nullptr;
|
||||
DEBUG("Failure: connected %d loaded %d valid %d", IsConnected(), IsPackLoaded(), _iae);
|
||||
INFO ("Failure: connected %d loaded %d valid %d", IsConnected(), IsPackLoaded(), _iae);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -562,7 +627,7 @@ rp_drive_c::Read(
|
||||
assert(nullptr != *buffer);
|
||||
|
||||
uint32_t offset = GetSectorForCHS(_currentCylinder, _desiredTrack, _desiredSector);
|
||||
DEBUG("Read from sector offset o%o", offset);
|
||||
INFO ("Read from sector offset o%o", offset);
|
||||
file_read(reinterpret_cast<uint8_t*>(*buffer), offset * GetSectorSize(), countInWords * 2);
|
||||
timeout_c timeout;
|
||||
timeout.wait_us(2500);
|
||||
@@ -578,7 +643,7 @@ rp_drive_c::Search(void)
|
||||
|
||||
if (!IsConnected() || !IsPackLoaded() || _iae)
|
||||
{
|
||||
DEBUG("Failure: connected &d loaded %d valid %d", IsConnected(), IsPackLoaded(), _iae);
|
||||
INFO ("Failure: connected &d loaded %d valid %d", IsConnected(), IsPackLoaded(), _iae);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -586,9 +651,9 @@ rp_drive_c::Search(void)
|
||||
// This is just a no-op, as we don't emulate read errors. We just delay a tiny bit.
|
||||
timeout_c timeout;
|
||||
|
||||
DEBUG("Search commencing.");
|
||||
INFO ("Search commencing.");
|
||||
timeout.wait_ms(20);
|
||||
DEBUG("Search completed.");
|
||||
INFO ("Search completed.");
|
||||
_currentCylinder = _desiredCylinder;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -62,13 +62,15 @@ public:
|
||||
void SetDesiredTrack(uint32_t track) { _desiredTrack = track; }
|
||||
void SetDesiredSector(uint32_t sector) { _desiredSector = sector; }
|
||||
void SetOffset(uint16_t offset) { _offset = offset; }
|
||||
void ClearAttention() { _ata = false; }
|
||||
uint32_t GetDesiredCylinder(void) { return _desiredCylinder; }
|
||||
uint32_t GetDesiredTrack(void) { return _desiredTrack; }
|
||||
uint32_t GetDesiredSector(void) { return _desiredSector; }
|
||||
uint16_t GetOffset(void) { return _offset; }
|
||||
uint32_t GetCurrentCylinder(void) { return _currentCylinder; }
|
||||
|
||||
uint16_t GetDriveType(void) { return _driveInfo.TypeNumber; }
|
||||
bool GetAttention() { return _ata; }
|
||||
|
||||
uint16_t GetDriveType(void) { return _driveInfo.TypeNumber; }
|
||||
uint16_t GetSerialNumber(void) { return 012345; } // TODO: Make configurable parameter
|
||||
uint32_t GetSectorSize(void);
|
||||
|
||||
@@ -91,9 +93,9 @@ private:
|
||||
|
||||
struct WorkerCommand
|
||||
{
|
||||
volatile uint32_t bus_address;
|
||||
volatile uint32_t word_count;
|
||||
volatile FunctionCode function;
|
||||
uint32_t bus_address;
|
||||
int32_t word_count;
|
||||
FunctionCode function;
|
||||
volatile bool ready;
|
||||
} _newCommand;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user