mirror of
https://github.com/livingcomputermuseum/UniBone.git
synced 2026-04-13 23:44:17 +00:00
Code cleanup/simplification. Moved stuff out to rp_drive_c that belonged there.
This commit is contained in:
@@ -44,12 +44,14 @@ public:
|
||||
// Writable bits
|
||||
virtual uint16_t RegisterWritableBits(uint32_t register) = 0;
|
||||
|
||||
// Selects the specified unit
|
||||
virtual void SelectUnit(uint32_t uint) = 0;
|
||||
|
||||
//
|
||||
// MASSBUS Register reads and writes
|
||||
// MASSBUS Register reads and writes (to the unit selected by SelectUnit)
|
||||
//
|
||||
virtual void WriteRegister(uint32_t unit, uint32_t register, uint16_t value) = 0;
|
||||
virtual uint16_t ReadRegister(uint32_t unit, uint32_t register) = 0;
|
||||
virtual void WriteRegister(uint32_t register, uint16_t value) = 0;
|
||||
virtual uint16_t ReadRegister(uint32_t register) = 0;
|
||||
|
||||
//
|
||||
// Block transfers
|
||||
|
||||
@@ -36,9 +36,6 @@ massbus_rp_c::massbus_rp_c(
|
||||
device_c(),
|
||||
_controller(controller),
|
||||
_selectedUnit(0),
|
||||
_desiredSector(0),
|
||||
_desiredTrack(0),
|
||||
_desiredCylinder(0),
|
||||
_workerState(WorkerState::Idle),
|
||||
_workerWakeupCond(PTHREAD_COND_INITIALIZER),
|
||||
_workerMutex(PTHREAD_MUTEX_INITIALIZER),
|
||||
@@ -124,21 +121,33 @@ massbus_rp_c::RegisterWritableBits(
|
||||
return _registerMetadata[reg].WritableBits;
|
||||
}
|
||||
|
||||
void
|
||||
massbus_rp_c::SelectUnit(
|
||||
uint32_t unit)
|
||||
{
|
||||
_selectedUnit = unit;
|
||||
UpdateStatus(_selectedUnit, false, false);
|
||||
UpdateDriveRegisters();
|
||||
}
|
||||
|
||||
void
|
||||
massbus_rp_c::WriteRegister(
|
||||
uint32_t unit,
|
||||
uint32_t reg,
|
||||
uint16_t value)
|
||||
{
|
||||
DEBUG("RP reg write: unit %d register 0%o value 0%o", unit, reg, value);
|
||||
DEBUG("RP reg write: unit %d register 0%o value 0%o", _selectedUnit, reg, value);
|
||||
|
||||
if (!SelectedDrive()->IsDriveReady() &&
|
||||
rp_drive_c* drive = SelectedDrive();
|
||||
|
||||
if (!drive->IsDriveReady() &&
|
||||
reg != 0 && // CS1 is allowed as long as GO isn't set (will be checked in DoCommand)
|
||||
reg != (uint32_t)Registers::AttentionSummary)
|
||||
{
|
||||
// Any attempt to modify a drive register other than Attention Summary
|
||||
// while the drive is busy is invalid.
|
||||
DEBUG("Register modification while drive busy.");
|
||||
// while the drive is busy is invalid.
|
||||
// For now treat this as fatal (it's not but real code shouldn't be doing it so this
|
||||
// is a diagnostic at the moment.)
|
||||
FATAL("Register modification while drive busy.");
|
||||
_rmr = true;
|
||||
UpdateStatus(_selectedUnit, false, false);
|
||||
return;
|
||||
@@ -147,24 +156,18 @@ massbus_rp_c::WriteRegister(
|
||||
switch(static_cast<Registers>(reg))
|
||||
{
|
||||
case Registers::Control:
|
||||
DoCommand(unit, value);
|
||||
DoCommand(value);
|
||||
break;
|
||||
|
||||
case Registers::DesiredSectorTrackAddress:
|
||||
_desiredTrack = (value & 0x1f00) >> 8;
|
||||
_desiredSector = (value & 0x1f);
|
||||
UpdateDesiredSectorTrack();
|
||||
|
||||
DEBUG("Desired Sector Track Address: track %d, sector %d",
|
||||
_desiredTrack,
|
||||
_desiredSector);
|
||||
drive->SetDesiredTrack((value & 0x1f00) >> 8);
|
||||
drive->SetDesiredSector(value & 0x1f);
|
||||
UpdateDriveRegisters();
|
||||
break;
|
||||
|
||||
case Registers::DesiredCylinderAddress:
|
||||
_desiredCylinder = value & 0x3ff;
|
||||
UpdateDesiredCylinder();
|
||||
|
||||
DEBUG("Desired Cylinder Address o%o (o%o)", _desiredCylinder, value);
|
||||
drive->SetDesiredCylinder(value & 0x3ff);
|
||||
UpdateDriveRegisters();
|
||||
break;
|
||||
|
||||
case Registers::AttentionSummary:
|
||||
@@ -193,30 +196,27 @@ massbus_rp_c::WriteRegister(
|
||||
}
|
||||
|
||||
void massbus_rp_c::DoCommand(
|
||||
uint32_t unit,
|
||||
uint16_t command)
|
||||
{
|
||||
FunctionCode function = static_cast<FunctionCode>((command & RP_FUNC) >> 1);
|
||||
_selectedUnit = unit;
|
||||
rp_drive_c* drive = SelectedDrive();
|
||||
|
||||
// check for GO bit; if unset we have nothing to do here,
|
||||
// but we will update status in case the drive unit has changed.
|
||||
if ((command & RP_GO) == 0)
|
||||
{
|
||||
UpdateStatus(_selectedUnit, false, false);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG("RP function 0%o, unit %o", function, _selectedUnit);
|
||||
|
||||
if (!SelectedDrive()->IsConnected())
|
||||
if (!drive->IsConnected())
|
||||
{
|
||||
// Early return for disconnected drives;
|
||||
// set NED and ERR bits
|
||||
_err = true;
|
||||
_ata = true;
|
||||
_ned = true; // TODO: should be done at RH11 level!
|
||||
SelectedDrive()->ClearVolumeValid();
|
||||
drive->ClearVolumeValid();
|
||||
UpdateStatus(_selectedUnit, true, false);
|
||||
return;
|
||||
}
|
||||
@@ -286,19 +286,18 @@ 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."
|
||||
//
|
||||
SelectedDrive()->SetVolumeValid();
|
||||
SelectedDrive()->SetDriveReady();
|
||||
_desiredSector = 0;
|
||||
_desiredTrack = 0;
|
||||
_offset = 0;
|
||||
UpdateDesiredSectorTrack();
|
||||
UpdateOffset();
|
||||
drive->SetVolumeValid();
|
||||
drive->SetDriveReady();
|
||||
drive->SetDesiredSector(0);
|
||||
drive->SetDesiredTrack(0);;
|
||||
drive->SetOffset(0);
|
||||
UpdateDriveRegisters();
|
||||
UpdateStatus(_selectedUnit, false, false); /* do not interrupt */
|
||||
break;
|
||||
|
||||
case FunctionCode::PackAcknowledge:
|
||||
DEBUG("RP Pack Acknowledge");
|
||||
SelectedDrive()->SetVolumeValid();
|
||||
drive->SetVolumeValid();
|
||||
UpdateStatus(_selectedUnit, false, false);
|
||||
break;
|
||||
|
||||
@@ -314,7 +313,7 @@ void massbus_rp_c::DoCommand(
|
||||
DEBUG("RP Read/Write Data or head-motion command");
|
||||
{
|
||||
// Clear the unit's DRY bit
|
||||
SelectedDrive()->ClearDriveReady();
|
||||
drive->ClearDriveReady();
|
||||
|
||||
if (function == FunctionCode::Search ||
|
||||
function == FunctionCode::Seek ||
|
||||
@@ -322,7 +321,7 @@ void massbus_rp_c::DoCommand(
|
||||
function == FunctionCode::Offset ||
|
||||
function == FunctionCode::ReturnToCenterline)
|
||||
{
|
||||
SelectedDrive()->SetPositioningInProgress();
|
||||
drive->SetPositioningInProgress();
|
||||
}
|
||||
|
||||
UpdateStatus(_selectedUnit, false, false);
|
||||
@@ -331,11 +330,7 @@ void massbus_rp_c::DoCommand(
|
||||
|
||||
// Save a copy of command data for the worker to consume
|
||||
_newCommand.unit = _selectedUnit;
|
||||
_newCommand.drive = SelectedDrive();
|
||||
_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;
|
||||
@@ -355,10 +350,9 @@ void massbus_rp_c::DoCommand(
|
||||
|
||||
uint16_t
|
||||
massbus_rp_c::ReadRegister(
|
||||
uint32_t unit,
|
||||
uint32_t reg)
|
||||
{
|
||||
DEBUG("RP reg read: unit %d register 0%o", unit, reg);
|
||||
DEBUG("RP reg read: unit %d register 0%o", _selectedUnit, reg);
|
||||
|
||||
switch(static_cast<Registers>(reg))
|
||||
{
|
||||
@@ -384,7 +378,7 @@ massbus_rp_c::ReadRegister(
|
||||
//
|
||||
void
|
||||
massbus_rp_c::UpdateStatus(
|
||||
uint16_t unit,
|
||||
uint32_t unit,
|
||||
bool complete,
|
||||
bool diagForceError)
|
||||
{
|
||||
@@ -445,36 +439,26 @@ massbus_rp_c::UpdateStatus(
|
||||
}
|
||||
|
||||
void
|
||||
massbus_rp_c::UpdateDesiredSectorTrack()
|
||||
massbus_rp_c::UpdateDriveRegisters()
|
||||
{
|
||||
uint16_t desiredSectorTrack = (_desiredSector | (_desiredTrack << 8));
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::DesiredSectorTrackAddress), desiredSectorTrack);
|
||||
}
|
||||
rp_drive_c* drive = SelectedDrive();
|
||||
|
||||
void
|
||||
massbus_rp_c::UpdateDesiredCylinder()
|
||||
{
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::DesiredCylinderAddress), _desiredCylinder);
|
||||
}
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::CurrentCylinderAddress),
|
||||
drive->GetCurrentCylinder());
|
||||
|
||||
void
|
||||
massbus_rp_c::UpdateOffset()
|
||||
{
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::Offset), _offset);
|
||||
}
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::DesiredCylinderAddress),
|
||||
drive->GetDesiredCylinder());
|
||||
|
||||
void
|
||||
massbus_rp_c::UpdateCurrentCylinder()
|
||||
{
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::CurrentCylinderAddress),
|
||||
SelectedDrive()->GetCurrentCylinder());
|
||||
uint16_t desiredSectorTrack = drive->GetDesiredSector() | (drive->GetDesiredTrack() << 8);
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::DesiredSectorTrackAddress),
|
||||
desiredSectorTrack);
|
||||
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::Offset), drive->GetOffset());
|
||||
}
|
||||
|
||||
void
|
||||
massbus_rp_c::Reset()
|
||||
{
|
||||
// TODO: reset all drives
|
||||
|
||||
// Reset registers to their defaults
|
||||
_ata = false;
|
||||
_attnSummary = 0;
|
||||
@@ -483,19 +467,8 @@ massbus_rp_c::Reset()
|
||||
_selectedUnit = 0;
|
||||
UpdateStatus(_selectedUnit, false, false);
|
||||
|
||||
_desiredSector = 0;
|
||||
_desiredTrack = 0;
|
||||
UpdateDesiredSectorTrack();
|
||||
UpdateDriveRegisters();
|
||||
|
||||
_desiredCylinder = 0;
|
||||
UpdateDesiredCylinder();
|
||||
|
||||
UpdateCurrentCylinder();
|
||||
|
||||
_offset = 0;
|
||||
UpdateOffset();
|
||||
|
||||
_selectedUnit = 0;
|
||||
_newCommand.ready = false;
|
||||
|
||||
}
|
||||
@@ -548,31 +521,23 @@ massbus_rp_c::Worker()
|
||||
break;
|
||||
|
||||
case WorkerState::Execute:
|
||||
{
|
||||
rp_drive_c* drive = GetDrive(command.unit);
|
||||
switch(command.function)
|
||||
{
|
||||
case FunctionCode::ReadData:
|
||||
{
|
||||
DEBUG("READ CHS %d/%d/%d, %d words to address o%o",
|
||||
_newCommand.cylinder,
|
||||
_newCommand.track,
|
||||
_newCommand.sector,
|
||||
_newCommand.word_count,
|
||||
_newCommand.bus_address);
|
||||
|
||||
uint16_t* buffer = nullptr;
|
||||
if (_newCommand.drive->Read(
|
||||
_newCommand.cylinder,
|
||||
_newCommand.track,
|
||||
_newCommand.sector,
|
||||
_newCommand.word_count,
|
||||
if (drive->Read(
|
||||
command.word_count,
|
||||
&buffer))
|
||||
{
|
||||
//
|
||||
// Data read: do DMA transfer to memory.
|
||||
//
|
||||
_controller->DiskReadTransfer(
|
||||
_newCommand.bus_address,
|
||||
_newCommand.word_count,
|
||||
command.bus_address,
|
||||
command.word_count,
|
||||
buffer);
|
||||
|
||||
// Free buffer
|
||||
@@ -586,7 +551,7 @@ massbus_rp_c::Worker()
|
||||
}
|
||||
|
||||
// Return drive to ready state
|
||||
_newCommand.drive->SetDriveReady();
|
||||
drive->SetDriveReady();
|
||||
|
||||
_workerState = WorkerState::Finish;
|
||||
}
|
||||
@@ -594,25 +559,15 @@ massbus_rp_c::Worker()
|
||||
|
||||
case FunctionCode::WriteData:
|
||||
{
|
||||
DEBUG("WRITE CHS %d/%d/%d, %d words from address o%o",
|
||||
_newCommand.cylinder,
|
||||
_newCommand.track,
|
||||
_newCommand.sector,
|
||||
_newCommand.word_count,
|
||||
_newCommand.bus_address);
|
||||
|
||||
//
|
||||
// Data write: do DMA transfer from memory.
|
||||
//
|
||||
uint16_t* buffer = _controller->DiskWriteTransfer(
|
||||
_newCommand.bus_address,
|
||||
_newCommand.word_count);
|
||||
command.bus_address,
|
||||
command.word_count);
|
||||
|
||||
if (!buffer || !_newCommand.drive->Write(
|
||||
_newCommand.cylinder,
|
||||
_newCommand.track,
|
||||
_newCommand.sector,
|
||||
_newCommand.word_count,
|
||||
if (!buffer || !drive->Write(
|
||||
command.word_count,
|
||||
buffer))
|
||||
{
|
||||
// Write failed:
|
||||
@@ -623,7 +578,7 @@ massbus_rp_c::Worker()
|
||||
delete buffer;
|
||||
|
||||
// Return drive to ready state
|
||||
_newCommand.drive->SetDriveReady();
|
||||
drive->SetDriveReady();
|
||||
|
||||
_workerState = WorkerState::Finish;
|
||||
}
|
||||
@@ -631,15 +586,7 @@ massbus_rp_c::Worker()
|
||||
|
||||
case FunctionCode::Search:
|
||||
{
|
||||
DEBUG("SEARCH CHS %d/%d/%d",
|
||||
_newCommand.cylinder,
|
||||
_newCommand.track,
|
||||
_newCommand.sector);
|
||||
|
||||
if (!_newCommand.drive->Search(
|
||||
_newCommand.cylinder,
|
||||
_newCommand.track,
|
||||
_newCommand.sector))
|
||||
if (!drive->Search())
|
||||
{
|
||||
// Search failed
|
||||
DEBUG("Search failed");
|
||||
@@ -647,20 +594,19 @@ massbus_rp_c::Worker()
|
||||
|
||||
|
||||
// Return to ready state, set attention bit.
|
||||
_newCommand.drive->SetDriveReady();
|
||||
drive->SetDriveReady();
|
||||
_ata = true;
|
||||
_workerState = WorkerState::Finish;
|
||||
}
|
||||
break;
|
||||
|
||||
case FunctionCode::Seek:
|
||||
DEBUG("SEEK Cylinder %d", _newCommand.cylinder);
|
||||
if (!_newCommand.drive->SeekTo(_newCommand.cylinder))
|
||||
if (!drive->SeekTo())
|
||||
{
|
||||
// Seek failed
|
||||
DEBUG("Seek failed");
|
||||
}
|
||||
_newCommand.drive->SetDriveReady();
|
||||
drive->SetDriveReady();
|
||||
_ata = true;
|
||||
_workerState = WorkerState::Finish;
|
||||
break;
|
||||
@@ -673,7 +619,7 @@ massbus_rp_c::Worker()
|
||||
// to complete.
|
||||
DEBUG("OFFSET/RETURN TO CL");
|
||||
timeout.wait_ms(10);
|
||||
_newCommand.drive->SetDriveReady();
|
||||
drive->SetDriveReady();
|
||||
_ata = true;
|
||||
_workerState = WorkerState::Finish;
|
||||
break;
|
||||
@@ -682,14 +628,14 @@ massbus_rp_c::Worker()
|
||||
FATAL("Unimplemented drive function %d", command.function);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case WorkerState::Finish:
|
||||
_workerState = WorkerState::Idle;
|
||||
_newCommand.drive->SetDriveReady();
|
||||
UpdateCurrentCylinder();
|
||||
GetDrive(_newCommand.unit)->SetDriveReady();
|
||||
UpdateStatus(_newCommand.unit, true, false);
|
||||
UpdateDriveRegisters();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
@@ -102,8 +102,10 @@ public:
|
||||
uint16_t RegisterResetValue(uint32_t register) override;
|
||||
uint16_t RegisterWritableBits(uint32_t register) override;
|
||||
|
||||
void WriteRegister(uint32_t unit, uint32_t register, uint16_t value) override;
|
||||
uint16_t ReadRegister(uint32_t unit, uint32_t register) override;
|
||||
void WriteRegister(uint32_t register, uint16_t value) override;
|
||||
uint16_t ReadRegister(uint32_t register) override;
|
||||
|
||||
void SelectUnit(uint32_t unit);
|
||||
|
||||
// Background worker functions
|
||||
void Worker();
|
||||
@@ -113,13 +115,9 @@ private:
|
||||
struct WorkerCommand
|
||||
{
|
||||
uint16_t unit;
|
||||
rp_drive_c* drive;
|
||||
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;
|
||||
|
||||
@@ -130,16 +128,13 @@ private:
|
||||
Finish = 2,
|
||||
} _workerState;
|
||||
|
||||
void DoCommand(uint32_t unit, uint16_t command);
|
||||
void DoCommand(uint16_t command);
|
||||
|
||||
void on_power_changed(void) override;
|
||||
void on_init_changed(void) override;
|
||||
|
||||
void UpdateStatus(uint16_t unit, bool completion, bool diagForceError);
|
||||
void UpdateDesiredSectorTrack();
|
||||
void UpdateDesiredCylinder();
|
||||
void UpdateOffset();
|
||||
void UpdateCurrentCylinder();
|
||||
void UpdateStatus(uint32_t unit, bool completion, bool diagForceError);
|
||||
void UpdateDriveRegisters();
|
||||
|
||||
rp_drive_c* SelectedDrive();
|
||||
rp_drive_c* GetDrive(uint16_t unit);
|
||||
@@ -176,11 +171,6 @@ private:
|
||||
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;
|
||||
|
||||
|
||||
@@ -615,7 +615,7 @@ void rh11_c::on_after_register_access(
|
||||
if ((dato_mask & 0x00ff) == 0x00ff)
|
||||
{
|
||||
// Let the massbus device take a crack at the shared bits.
|
||||
_massbus->WriteRegister(_unit, RHCS1, value & 077);
|
||||
_massbus->WriteRegister(RHCS1, value & 077);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -625,7 +625,7 @@ void rh11_c::on_after_register_access(
|
||||
{
|
||||
if (UNIBUS_CONTROL_DATO == unibus_control)
|
||||
{
|
||||
_unit = (value & 07);
|
||||
uint16_t newUnit = (value & 07);
|
||||
_busAddressIncrementProhibit = !!(value & 010);
|
||||
_parityTest = !!(value & 020);
|
||||
_controllerClear = !!(value & 040);
|
||||
@@ -634,13 +634,25 @@ void rh11_c::on_after_register_access(
|
||||
DEBUG("RHCS2 write: o%o", value);
|
||||
DEBUG("RHCS2: perror %d, unit %d inc %d ptest %d clear %d",
|
||||
_parityError, _unit, _busAddressIncrementProhibit, _parityTest, _controllerClear);
|
||||
|
||||
|
||||
// On unit change, select new drive
|
||||
if (newUnit != _unit)
|
||||
{
|
||||
_unit = newUnit;
|
||||
_massbus->SelectUnit(_unit);
|
||||
}
|
||||
|
||||
// TODO: handle System Register Clear (bit 5)
|
||||
if (_controllerClear)
|
||||
{
|
||||
DEBUG("Controller Clear");
|
||||
_interruptEnable = false;
|
||||
|
||||
for (uint32_t i=0; i<drivecount; i++)
|
||||
{
|
||||
GetDrive(i)->Reset();
|
||||
}
|
||||
|
||||
_massbus->Reset();
|
||||
|
||||
// clear error and the clear bits
|
||||
@@ -691,7 +703,7 @@ void rh11_c::on_after_register_access(
|
||||
{
|
||||
if (UNIBUS_CONTROL_DATO == unibus_control)
|
||||
{
|
||||
_massbus->WriteRegister(_unit, _unibusToMassbusRegisterMap[device_reg->index], value);
|
||||
_massbus->WriteRegister(_unibusToMassbusRegisterMap[device_reg->index], value);
|
||||
// Massbus is responsible for writing back the appropriate dati value.
|
||||
}
|
||||
else
|
||||
@@ -699,7 +711,7 @@ void rh11_c::on_after_register_access(
|
||||
DEBUG("massbus reg read %o", device_reg->index);
|
||||
set_register_dati_value(
|
||||
device_reg,
|
||||
_massbus->ReadRegister(_unit, _unibusToMassbusRegisterMap[device_reg->index]),
|
||||
_massbus->ReadRegister(_unibusToMassbusRegisterMap[device_reg->index]),
|
||||
"on_after_register_access");
|
||||
}
|
||||
}
|
||||
@@ -715,6 +727,8 @@ void rh11_c::on_after_register_access(
|
||||
void rh11_c::reset_controller(void)
|
||||
{
|
||||
reset_unibus_registers();
|
||||
|
||||
// TODO: do more
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ using namespace std;
|
||||
rp_drive_c::rp_drive_c(storagecontroller_c *controller, uint32_t driveNumber) :
|
||||
storagedrive_c(controller),
|
||||
_driveNumber(driveNumber),
|
||||
_desiredCylinder(0),
|
||||
_currentCylinder(0),
|
||||
_desiredTrack(0),
|
||||
_offset(0),
|
||||
_ready(true),
|
||||
_lst(false),
|
||||
_aoe(false),
|
||||
@@ -39,6 +43,12 @@ rp_drive_c::~rp_drive_c()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rp_drive_c::Reset()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// on_param_changed():
|
||||
// Handles configuration parameter changes.
|
||||
bool
|
||||
@@ -96,20 +106,19 @@ rp_drive_c::IsPackLoaded()
|
||||
}
|
||||
|
||||
bool
|
||||
rp_drive_c::SeekTo(
|
||||
uint32_t destinationCylinder)
|
||||
rp_drive_c::SeekTo()
|
||||
{
|
||||
// TODO: delay by appropriate amount
|
||||
|
||||
timeout_c timeout;
|
||||
|
||||
_iae = !(destinationCylinder < _driveInfo.Cylinders);
|
||||
_iae = !(_desiredCylinder < _driveInfo.Cylinders);
|
||||
|
||||
if (IsConnected() && IsPackLoaded() && !_iae)
|
||||
{
|
||||
timeout.wait_ms(20);
|
||||
|
||||
_currentCylinder = destinationCylinder;
|
||||
_currentCylinder = _desiredCylinder;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -118,12 +127,6 @@ rp_drive_c::SeekTo(
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
rp_drive_c::GetCurrentCylinder()
|
||||
{
|
||||
return _currentCylinder;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// TODO: on all reads/writes, an implied seek takes place if the
|
||||
@@ -136,13 +139,10 @@ rp_drive_c::GetCurrentCylinder()
|
||||
//
|
||||
bool
|
||||
rp_drive_c::Write(
|
||||
uint32_t cylinder,
|
||||
uint32_t track,
|
||||
uint32_t sector,
|
||||
size_t countInWords,
|
||||
uint16_t* buffer)
|
||||
{
|
||||
_iae = !ValidateCHS(cylinder, track, sector);
|
||||
_iae = !ValidateCHS(_desiredCylinder, _desiredTrack, _desiredSector);
|
||||
_wle = IsWriteLocked();
|
||||
|
||||
// TODO: handle address overflow
|
||||
@@ -153,11 +153,11 @@ rp_drive_c::Write(
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentCylinder = cylinder;
|
||||
uint32_t offset = GetSectorForCHS(cylinder, track, sector);
|
||||
_currentCylinder = _desiredCylinder;
|
||||
uint32_t offset = GetSectorForCHS(_currentCylinder, _desiredTrack, _desiredSector);
|
||||
file_write(reinterpret_cast<uint8_t*>(buffer), offset * GetSectorSize(), countInWords * 2);
|
||||
//timeout_c timeout;
|
||||
//timeout.wait_ms(20);
|
||||
timeout_c timeout;
|
||||
timeout.wait_us(500);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -170,51 +170,45 @@ rp_drive_c::Write(
|
||||
//
|
||||
bool
|
||||
rp_drive_c::Read(
|
||||
uint32_t cylinder,
|
||||
uint32_t track,
|
||||
uint32_t sector,
|
||||
size_t countInWords,
|
||||
uint16_t** buffer)
|
||||
{
|
||||
|
||||
_iae = !ValidateCHS(cylinder, track, sector);
|
||||
_iae = !ValidateCHS(_desiredCylinder, _desiredTrack, _desiredSector);
|
||||
_wle = false;
|
||||
|
||||
if (!IsConnected() || !IsPackLoaded() || _iae)
|
||||
{
|
||||
*buffer = nullptr;
|
||||
DEBUG("Failure: connected %d loaded %d valid %d", IsConnected(), IsPackLoaded(), ValidateCHS(cylinder, track, sector));
|
||||
DEBUG("Failure: connected %d loaded %d valid %d", IsConnected(), IsPackLoaded(), _iae);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentCylinder = cylinder;
|
||||
_currentCylinder = _desiredCylinder;
|
||||
|
||||
*buffer = new uint16_t[countInWords];
|
||||
|
||||
assert(nullptr != *buffer);
|
||||
|
||||
uint32_t offset = GetSectorForCHS(cylinder, track, sector);
|
||||
uint32_t offset = GetSectorForCHS(_currentCylinder, _desiredTrack, _desiredSector);
|
||||
DEBUG("Read from sector offset o%o", offset);
|
||||
file_read(reinterpret_cast<uint8_t*>(*buffer), offset * GetSectorSize(), countInWords * 2);
|
||||
//timeout_c timeout;
|
||||
//timeout.wait_ms(20);
|
||||
timeout_c timeout;
|
||||
timeout.wait_us(500);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
rp_drive_c::Search(
|
||||
uint32_t cylinder,
|
||||
uint32_t track,
|
||||
uint32_t sector)
|
||||
rp_drive_c::Search(void)
|
||||
{
|
||||
_iae = !ValidateCHS(cylinder, track, sector);
|
||||
_iae = !ValidateCHS(_desiredCylinder, _desiredTrack, _desiredSector);
|
||||
|
||||
if (!IsConnected() || !IsPackLoaded() || _iae)
|
||||
{
|
||||
DEBUG("Failure: connected &d loaded %d valid %d", IsConnected(), IsPackLoaded(), ValidateCHS(cylinder, track, sector));
|
||||
DEBUG("Failure: connected &d loaded %d valid %d", IsConnected(), IsPackLoaded(), _iae);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -226,7 +220,7 @@ rp_drive_c::Search(
|
||||
timeout.wait_ms(20);
|
||||
_pip = false;
|
||||
DEBUG("Search completed.");
|
||||
_currentCylinder = cylinder;
|
||||
_currentCylinder = _desiredCylinder;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -23,12 +23,24 @@ public:
|
||||
rp_drive_c(storagecontroller_c *controller, uint32_t driveNumber);
|
||||
~rp_drive_c(void);
|
||||
|
||||
void Reset();
|
||||
|
||||
bool on_param_changed(parameter_c *param) override;
|
||||
|
||||
uint32_t GetSectorSize(void);
|
||||
uint32_t GetType(void);
|
||||
|
||||
bool IsConnected(void) { return _driveNumber == 0; /* todo: make config. parameter */ }
|
||||
void SetDesiredCylinder(uint32_t cylinder) { _desiredCylinder = cylinder; }
|
||||
void SetDesiredTrack(uint32_t track) { _desiredTrack = track; }
|
||||
void SetDesiredSector(uint32_t sector) { _desiredSector = sector; }
|
||||
void SetOffset(uint16_t offset) { _offset = offset; }
|
||||
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; }
|
||||
|
||||
bool IsConnected(void) { return true; /* todo: make config. parameter */ }
|
||||
bool IsPackLoaded(void);
|
||||
bool IsDriveReady(void) { return _ready; }
|
||||
bool IsWriteLocked(void) { return false; /* for now */ }
|
||||
@@ -46,18 +58,20 @@ public:
|
||||
uint16_t GetDriveType(void) { return _driveInfo.TypeNumber; }
|
||||
uint16_t GetSerialNumber(void) { return 012345; } // TODO: Make configurable parameter
|
||||
|
||||
bool SeekTo(uint32_t cylinder);
|
||||
uint32_t GetCurrentCylinder();
|
||||
|
||||
bool Write(uint32_t cylinder, uint32_t track, uint32_t sector, uint32_t countInWords, uint16_t* buffer);
|
||||
bool Read(uint32_t cylinder, uint32_t track, uint32_t sector, uint32_t countInWords, uint16_t** outBuffer);
|
||||
bool Search(uint32_t cylinder, uint32_t track, uint32_t sector);
|
||||
bool SeekTo();
|
||||
bool Write(uint32_t countInWords, uint16_t* buffer);
|
||||
bool Read(uint32_t countInWords, uint16_t** outBuffer);
|
||||
bool Search();
|
||||
|
||||
public:
|
||||
void on_power_changed(void) override;
|
||||
void on_init_changed(void) override;
|
||||
|
||||
private:
|
||||
uint32_t _desiredCylinder;
|
||||
uint32_t _desiredTrack;
|
||||
uint32_t _desiredSector;
|
||||
uint16_t _offset;
|
||||
uint32_t _currentCylinder;
|
||||
uint32_t _driveNumber;
|
||||
bool _ready;
|
||||
|
||||
Reference in New Issue
Block a user