1
0
mirror of https://github.com/livingcomputermuseum/UniBone.git synced 2026-04-13 15:34:15 +00:00

Cleanup, modifications while trying to get diagnostics to pass.

This commit is contained in:
Josh Dersch
2020-03-24 01:39:31 +01:00
parent 34d4a16999
commit 6bc7703e63
6 changed files with 228 additions and 103 deletions

View File

@@ -122,7 +122,7 @@ massbus_rp_c::WriteRegister(
// while the drive is busy is invalid.
INFO("Register modification while drive busy.");
_rmr = true;
UpdateStatus(false);
UpdateStatus(false, false);
return;
}
@@ -160,11 +160,14 @@ massbus_rp_c::WriteRegister(
break;
case Registers::Error1:
// Clear any bits in the Error 1 Register specified in the
// written value:
_error1 &= ~(value & 0xff);
_controller->WriteRegister(reg, _error1);
// Pg. 2-20 of EK-RP056-MM-01:
// "The register can also be written by the controller for diagnostic purposes.
// Setting any bit in this register sets the composite error bit in the status register."
//
// Based on diagnostic (ZRJGE0) behavior, writing ANY value here forces an error.
//
INFO("Error 1 Reg write o%o, value is now o%o", value, _error1);
UpdateStatus(false, true); // Force composite error.
break;
default:
@@ -188,7 +191,7 @@ void massbus_rp_c::DoCommand(
INFO("RP function 0%o, unit %o", function, _selectedUnit);
if (!SelectedDrive()->IsAvailable())
if (!SelectedDrive()->IsConnected())
{
// Early return for disconnected drives;
// set NED and ERR bits
@@ -196,7 +199,7 @@ void massbus_rp_c::DoCommand(
_ata = true;
_ned = true; // TODO: should be done at RH11 level!
SelectedDrive()->ClearVolumeValid();
UpdateStatus(true);
UpdateStatus(true, false);
return;
}
@@ -213,7 +216,7 @@ void massbus_rp_c::DoCommand(
{
case FunctionCode::Nop:
// Nothing.
UpdateStatus(true);
UpdateStatus(true, false);
break;
case FunctionCode::ReadInPreset:
@@ -230,7 +233,7 @@ void massbus_rp_c::DoCommand(
_offset = 0;
UpdateDesiredSectorTrack();
UpdateOffset();
UpdateStatus(false); /* do not interrupt */
UpdateStatus(false, false); /* do not interrupt */
break;
case FunctionCode::ReadData:
@@ -249,7 +252,7 @@ void massbus_rp_c::DoCommand(
}
// Clear READY
UpdateStatus(false);
UpdateStatus(false, false);
pthread_mutex_lock(&_workerMutex);
@@ -282,9 +285,28 @@ massbus_rp_c::ReadRegister(
uint32_t reg)
{
INFO("*** RP reg read: unit %d register 0%o", unit, reg);
FATAL("Unimplemented register read %o", 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;
case Registers::AttentionSummary:
INFO("attn: o%o", _attnSummary);
return _attnSummary;
break;
default:
FATAL("Unimplemented register read %o", reg);
break;
}
return 0;
}
@@ -293,7 +315,8 @@ massbus_rp_c::ReadRegister(
//
void
massbus_rp_c::UpdateStatus(
bool complete)
bool complete,
bool diagForceError)
{
_error1 =
@@ -307,6 +330,11 @@ massbus_rp_c::UpdateStatus(
_err = true;
_ata = true;
}
else if (diagForceError)
{
_err = false;
_ata = true;
}
else
{
_err = false;
@@ -318,7 +346,7 @@ massbus_rp_c::UpdateStatus(
(0400) | // Drive preset -- always set for a single-controller disk
(SelectedDrive()->GetReadLastSector() ? 02000 : 0) | // Last sector read
(SelectedDrive()->IsWriteLocked() ? 04000 : 0) | // Write lock
(SelectedDrive()->IsAvailable() ? 010000 : 0) | // Medium online
(SelectedDrive()->IsPackLoaded() ? 010000 : 0) | // Medium online
(SelectedDrive()->IsPositioningInProgress() ? 020000 : 0) | // PIP
(_err ? 040000 : 0) | // Composite error
(_ata ? 0100000 : 0);
@@ -329,7 +357,7 @@ massbus_rp_c::UpdateStatus(
// Update the Attention Summary register if this disk is online:
if (_ata && SelectedDrive()->IsAvailable())
if (_ata && SelectedDrive()->IsConnected())
{
_attnSummary |= (0x1 << _selectedUnit); // TODO: these only get set, and are latched until
// manually cleared?
@@ -339,7 +367,7 @@ massbus_rp_c::UpdateStatus(
_controller->WriteRegister(static_cast<uint32_t>(Registers::AttentionSummary), _attnSummary);
// Inform controller of status update.
_controller->BusStatus(complete, SelectedDrive()->IsDriveReady(), _ata, _err, SelectedDrive()->IsAvailable(), _ned);
_controller->BusStatus(complete, SelectedDrive()->IsDriveReady(), _ata, _err, SelectedDrive()->IsConnected(), _ned);
}
void
@@ -382,7 +410,7 @@ massbus_rp_c::Reset()
_attnSummary = 0;
_error1 = 0;
_rmr = false;
UpdateStatus(false);
UpdateStatus(false, false);
_desiredSector = 0;
_desiredTrack = 0;
@@ -558,7 +586,7 @@ massbus_rp_c::Worker()
_workerState = WorkerState::Idle;
SelectedDrive()->SetDriveReady();
UpdateCurrentCylinder();
UpdateStatus(true);
UpdateStatus(true, false);
break;
}

View File

@@ -132,7 +132,7 @@ private:
void on_power_changed(void) override;
void on_init_changed(void) override;
void UpdateStatus(bool completion);
void UpdateStatus(bool completion, bool diagForceError);
void UpdateDesiredSectorTrack();
void UpdateDesiredCylinder();
void UpdateOffset();
@@ -147,21 +147,21 @@ private:
{
// Name DATI DATO
{ "INV", false, false, 0, 0 }, // 0, not used
{ "CS1", false, true, 0, 0401477 }, // Status
{ "ER1", false, true, 0, 0177777 }, // Error #1 - writable by diagnostics
{ "MR" , false, true, 0, 0177777 }, // Maintenance
{ "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
{ "SN" , false, false, 0, 0 }, // Serial Number
{ "OFF", false, false, 0, 0177777 }, // Offset
{ "DCY", false, true, 0, 0001777 }, // Desired Cylinder
{ "CCY", false, false, 0, 0 }, // Current Cylinder
{ "ER2", false, false, 0, 0 }, // Error #2
{ "ER3", false, false, 0, 0 }, // Error #3
{ "EPO", false, false, 0, 0 }, // ECC Position
{ "EPA", false, false, 0, 0 }, // ECC Pattern
{ "CS1", false, true, 0, 0041577 }, // 1, Status
{ "ER1", false, true, 0, 0177777 }, // 2, Error #1 - writable by diagnostics
{ "MR" , false, true, 0, 0177777 }, // 3, Maintenance
{ "ATN", true, true, 0, 0377 }, // 4, Attention summary
{ "DA" , false, true, 0, 0017437 }, // 5, Desired Sector/Track
{ "DT" , true, true, 0, 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
{ "ER3", false, false, 0, 0 }, // 15, Error #3
{ "EPO", false, false, 0, 0 }, // 16, ECC Position
{ "EPA", false, false, 0, 0 }, // 17, ECC Pattern
};
// Unit selected by last command register write

View File

@@ -34,11 +34,11 @@ int32_t _unibusToMassbusRegisterMap[] =
-1, // 776722
03, // 776724
06, // 776726
010, // 776730
014, // 776730
011, // 776732
012, // 776734
013, // 776736
014, // 776740
010, // 776740
015, // 776742
016, // etc.
017,
@@ -95,7 +95,23 @@ int32_t _massbusToUnibusRegisterMap[] =
rh11_c::rh11_c() :
storagecontroller_c(),
_massbus(nullptr),
_attention(false),
_error(false),
_mcbParityError(false),
_avail(false),
_ready(false),
_interruptEnable(false),
_function(0),
_go(false),
_parityError(false),
_ned(false),
_nxm(false),
_progError(false),
_outputReady(false),
_inputReady(false),
_controllerClear(false),
_busAddressIncrementProhibit(false),
_parityTest(false),
_busAddress(0),
_unit(0)
{
@@ -224,45 +240,24 @@ rh11_c::BusStatus(
{
INFO("Massbus status update attn %d, error %d, ned %d", attention, error, ned);
uint16_t currentStatus = get_register_dato_value(
RH_reg[RHCS1]);
INFO("RHCS1 is currently o%o", currentStatus);
currentStatus &= ~(0144300); // 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
_attention = attention;
_error = error;
_avail = avail;
_ready = ready;
if (completion)
{
// clear the GO bit from the CS word if the drive is finished.
currentStatus &= ~(01);
_go = false;
}
set_register_dati_value(
RH_reg[RHCS1],
currentStatus,
"BusStatus");
INFO("RHCS1 is now o%o", currentStatus);
currentStatus = get_register_dato_value(RH_reg[RHCS2]);
UpdateCS1();
INFO("RHCS2 is currently o%o", currentStatus);
currentStatus &= ~(010000);
currentStatus |=
(ned ? 010000 : 0); // non-existent drive
set_register_dati_value(
RH_reg[RHCS2],
currentStatus,
"BusStatus");
INFO("RHCS2 is now o%o", currentStatus);
if (!_controllerClear)
{
_ned = ned;
UpdateCS2();
}
if ((attention || ready) && completion)
{
@@ -270,6 +265,49 @@ rh11_c::BusStatus(
}
}
void
rh11_c::UpdateCS1()
{
uint16_t newStatus =
(_attention ? 0100000 : 0) |
(_error ? 0040000 : 0) |
(_mcbParityError ? 0020000 : 0) |
(_avail ? 0004000 : 0) | // drive available
((_busAddress & 0600000) >> 8) |
(_ready ? 0000200 : 0) | // controller ready bit
(_interruptEnable ? 0000100 : 0) |
(_function << 1) |
(_go ? 0000001 : 0);
INFO("RHCS1 is now o%o", newStatus);
set_register_dati_value(
RH_reg[RHCS1],
newStatus,
"UpdateCS1");
}
void rh11_c::UpdateCS2()
{
uint16_t newStatus =
(_parityError ? 0020000 : 0) |
(_ned ? 0010000 : 0) |
(_nxm ? 0004000 : 0) |
(_progError ? 0002000 : 0) |
(_outputReady ? 0000200 : 0) |
(_inputReady ? 0000100 : 0) |
(_parityTest ? 0000020 : 0) |
(_busAddressIncrementProhibit ? 0000010 : 0) |
(_unit);
INFO("RHCS2 is now o%o", newStatus);
set_register_dati_value(
RH_reg[RHCS2],
newStatus,
"UpdateCS2");
}
void
rh11_c::WriteRegister(
uint32_t reg,
@@ -525,16 +563,35 @@ void rh11_c::on_after_register_access(
{
if (UNIBUS_CONTROL_DATO == unibus_control)
{
// IE bit
_interruptEnable = ((value & 0x40) != 0);
// Extended bus address bits
_busAddress = (_busAddress & 0xffff) | ((value & 0x300) << 8);
INFO("RHCS1: IE %d BA 0%o", _interruptEnable, _busAddress);
INFO("RHCS1: DATO o%o", value);
_error = !!(value & 0040000);
_busAddress = (_busAddress & 0177777) | ((value & 01400) << 8);
_interruptEnable = !!(value & 0100);
_function = (value & 076) >> 1;
_go = (value & 01);
// Bit 14 (Transfer Error) is writeable; the function of this is not documented
// In the handbook or engineering manuals. The schematics are eluding me as well.
// 2.11bsd writes this bit, as do diagnostics (and they expect it to be read back..)
// SIMH suggests this is used to clear error bits, so we'll do that here.
if (_error)
{
_error = false;
_parityError = false;
_mcbParityError = false;
_ned = false;
_nxm = false;
}
INFO("RHCS1: IE %d BA o%o func o%o go %d", _interruptEnable, _busAddress, _function, _go);
// Let the massbus device take a crack at the shared bits
_massbus->WriteRegister(_unit, RHCS1, value & 0x3f);
_massbus->WriteRegister(_unit, RHCS1, value & 077);
// TODO: Per RH11-AB_OptionDescr.pdf (p 4-17):
// "The program can force an interrupt by loading bits D06 H (IE) and D07 H (RDY) in the CS1
// register which direct sets the INTR flip-flop."
//
UpdateCS1();
}
}
break;
@@ -543,25 +600,33 @@ void rh11_c::on_after_register_access(
{
if (UNIBUS_CONTROL_DATO == unibus_control)
{
_unit = (value & 0x7);
_busAddressIncrementProhibit = !!(value & 0x8);
_parityTest = !!(value & 0x10);
_unit = (value & 07);
_busAddressIncrementProhibit = !!(value & 010);
_parityTest = !!(value & 020);
_controllerClear = !!(value & 040);
_parityError = !!(value & 0020000);
INFO("RHCS2 write: o%o", value);
INFO("RHCS2: perror %d, unit %d inc %d ptest %d clear %d",
_parityError, _unit, _busAddressIncrementProhibit, _parityTest, _controllerClear);
// TODO: handle System Register Clear (bit 5)
if (value & 040) // controller clear
if (_controllerClear)
{
INFO("Controller Clear");
// clear error bits
value &= ~(010040);
set_register_dati_value(
RH_reg[RHCS2],
value,
"Reset");
_interruptEnable = false;
_massbus->Reset();
_massbus->Reset();
// clear error and the clear bits
_ned = false;
_nxm = false;
INFO("RHCS2: is now o%o", value);
_controllerClear = false;
}
INFO("RHCS2: unit %d", _unit);
UpdateCS2();
}
}
break;
@@ -571,8 +636,12 @@ void rh11_c::on_after_register_access(
if (UNIBUS_CONTROL_DATO == unibus_control)
{
INFO("RHWC: o%o", value);
}
set_register_dati_value(
RH_reg[RHWC],
value,
"HACK");
}
}
break;
@@ -582,6 +651,11 @@ void rh11_c::on_after_register_access(
{
_busAddress = (_busAddress & 0x30000) | value;
INFO("RHBA: o%o", _busAddress);
set_register_dati_value(
RH_reg[RHWC],
value,
"HACK");
}
}
break;
@@ -593,6 +667,7 @@ void rh11_c::on_after_register_access(
if (UNIBUS_CONTROL_DATO == unibus_control)
{
_massbus->WriteRegister(_unit, _unibusToMassbusRegisterMap[device_reg->index], value);
// Massbus is responsible for writing back the appropriate dati value.
}
else
{
@@ -622,6 +697,7 @@ void rh11_c::Interrupt(void)
// IE is cleared after the interrupt is raised
// Actual bit is cleared in BusStatus, this should be fixed.
_interruptEnable = false;
UpdateCS1();
}
}

View File

@@ -51,18 +51,36 @@ private:
bool DMAWrite(uint32_t address, size_t lengthInWords, uint16_t* buffer);
uint16_t* DMARead(uint32_t address, size_t lengthInWords);
void UpdateCS1();
void UpdateCS2();
private:
std::unique_ptr<massbus_device_c> _massbus;
// Control & Status reg 1 bits
volatile bool _attention;
volatile bool _error;
volatile bool _mcbParityError;
volatile bool _avail;
volatile bool _ready;
volatile bool _interruptEnable;
volatile uint16_t _function;
volatile bool _go;
volatile uint32_t _busAddress;
// Control & Status reg 2 bits
volatile bool _parityError;
volatile bool _ned;
volatile bool _nxm;
volatile bool _progError;
volatile bool _outputReady;
volatile bool _inputReady;
volatile uint16_t _unit;
volatile bool _busAddressIncrementProhibit;
volatile bool _parityTest;
volatile bool _controllerClear;
public:

View File

@@ -79,12 +79,12 @@ rp_drive_c::GetSectorSize()
}
//
// IsAvailable():
// Indicates whether this drive is available (i.e. has an image
// assigned to it and can thus be used by the controller.)
// IsPackLoaded():
// Indicates whether this drive has a pack loaded (i.e. has an image
// assigned to it)
//
bool
rp_drive_c::IsAvailable()
rp_drive_c::IsPackLoaded()
{
return file_is_open();
}
@@ -97,7 +97,7 @@ rp_drive_c::SeekTo(
_iae = !(destinationCylinder < _driveInfo.Cylinders);
if (IsAvailable() && !_iae)
if (IsConnected() && IsPackLoaded() && !_iae)
{
_currentCylinder = destinationCylinder;
return true;
@@ -137,7 +137,7 @@ rp_drive_c::Write(
// TODO: handle address overflow
if (!IsAvailable() || _iae || _wle)
if (!IsConnected() || !IsPackLoaded() || _iae || _wle)
{
return false;
}
@@ -167,10 +167,10 @@ rp_drive_c::Read(
_iae = !ValidateCHS(cylinder, track, sector);
_wle = false;
if (!IsAvailable() || _iae)
if (!IsConnected() || !IsPackLoaded() || _iae)
{
*buffer = nullptr;
INFO("Failure: avail %d valid %d", IsAvailable(), ValidateCHS(cylinder, track, sector));
INFO("Failure: connected %d loaded %d valid %d", IsConnected(), IsPackLoaded(), ValidateCHS(cylinder, track, sector));
return false;
}
else
@@ -197,9 +197,9 @@ rp_drive_c::Search(
{
_iae = !ValidateCHS(cylinder, track, sector);
if (!IsAvailable() || _iae)
if (!IsConnected() || !IsPackLoaded() || _iae)
{
INFO("Failure: avail %d valid %d", IsAvailable(), ValidateCHS(cylinder, track, sector));
INFO("Failure: connected &d loaded %d valid %d", IsConnected(), IsPackLoaded(), ValidateCHS(cylinder, track, sector));
return false;
}
else
@@ -208,7 +208,7 @@ rp_drive_c::Search(
timeout_c timeout;
INFO("Search commencing.");
timeout.wait_ms(30);
timeout.wait_ms(250);
_pip = false;
INFO("Search completed.");
_currentCylinder = cylinder;

View File

@@ -28,7 +28,8 @@ public:
uint32_t GetSectorSize(void);
uint32_t GetType(void);
bool IsAvailable(void);
bool IsConnected(void) { return _driveNumber == 0; /* todo: make config. parameter */ }
bool IsPackLoaded(void);
bool IsDriveReady(void) { return _ready; }
bool IsWriteLocked(void) { return false; /* for now */ }
bool IsPositioningInProgress(void) { return _pip; }
@@ -42,6 +43,8 @@ public:
void SetVolumeValid(void) { _vv = true; }
void ClearVolumeValid(void) { _vv = false; }
bool GetVolumeValid(void) { return _vv; }
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();