mirror of
https://github.com/livingcomputermuseum/UniBone.git
synced 2026-04-15 16:10:41 +00:00
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.
This commit is contained in:
@@ -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<uint32_t>(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<FunctionCode>((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<uint32_t>(Registers::Status), _status);
|
||||
_controller->WriteRegister(static_cast<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(Registers::LookAhead), lookAhead);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -317,6 +339,13 @@ massbus_rp_c::UpdateOffset()
|
||||
_controller->WriteRegister(static_cast<uint32_t>(Registers::Offset), _offset);
|
||||
}
|
||||
|
||||
void
|
||||
massbus_rp_c::UpdateCurrentCylinder()
|
||||
{
|
||||
_controller->WriteRegister(static_cast<uint32_t>(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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<uint8_t*>(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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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_device_c> _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
|
||||
|
||||
@@ -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<uint8_t*>(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<uint8_t*>(*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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user