diff --git a/10.02_devices/2_src/mscp_drive.cpp b/10.02_devices/2_src/mscp_drive.cpp new file mode 100644 index 0000000..47fe260 --- /dev/null +++ b/10.02_devices/2_src/mscp_drive.cpp @@ -0,0 +1,192 @@ +/* + mscp_drive.cpp: Implementation of MSCP disks. +*/ + +#include + +using namespace std; + +#include "logger.hpp" +#include "utils.hpp" +#include "mscp_drive.hpp" +#include "mscp_server.hpp" + +mscp_drive_c::mscp_drive_c( + storagecontroller_c *controller, + uint32_t driveNumber) : + storagedrive_c(controller) +{ + log_label = "MSCPD"; + SetDriveType("RA81"); + SetOffline(); + + // Calculate the unit's ID: + // drive number in upper 32 bits, class/model in lower. + _unitID = (static_cast(0xffffffff) << 32) | 0x02020000; +} + +mscp_drive_c::~mscp_drive_c() +{ + if (file_is_open()) + { + file_close(); + } +} + +uint32_t mscp_drive_c::GetBlockSize() +{ + // + // For the time being this is always 512 bytes. + // + return 512; +} + +uint32_t mscp_drive_c::GetBlockCount() +{ + // TODO: need to be able to handle drives of arbitrary size, not just + // DEC-branded units. + return _driveInfo.BlockCount; +} + +uint32_t mscp_drive_c::GetMediaID() +{ + return _driveInfo.MediaID; +} + +uint64_t mscp_drive_c::GetUnitID() +{ + return _unitID; +} + +bool mscp_drive_c::IsAvailable() +{ + return file_is_open(); +} + +bool mscp_drive_c::IsOnline() +{ + return _online; +} + +void mscp_drive_c::SetOnline() +{ + _online = true; + + // + // Once online, the drive's type and image cannot be changed until + // the drive is offline. + // + type_name.readonly = true; + image_filepath.readonly = true; +} + +void mscp_drive_c::SetOffline() +{ + _online = false; + type_name.readonly = false; + image_filepath.readonly = false; +} + +// +// Writes the specified number of bytes from the provided buffer, +// starting at the specified logical block. +// +void mscp_drive_c::Write( + uint32_t blockNumber, + size_t lengthInBytes, + uint8_t* buffer) +{ + file_write( + buffer, + blockNumber * GetBlockSize(), + lengthInBytes); +} + +// +// Reads the specifed number of bytes starting at the specified logical +// block. Returns a pointer to a buffer containing the data read. +// Caller is responsible for freeing this buffer. +// +uint8_t* mscp_drive_c::Read( + uint32_t blockNumber, + size_t lengthInBytes) +{ + uint8_t* buffer = new uint8_t[lengthInBytes]; + + assert(nullptr != buffer); + + file_read( + buffer, + blockNumber * GetBlockSize(), + lengthInBytes); + + return buffer; +} + +bool mscp_drive_c::on_param_changed( + parameter_c *param) +{ + if (&type_name == param) + { + return SetDriveType(type_name.new_value.c_str()); + } + else if (&image_filepath == param) + { + // + // Try to open the image file. + // + if (file_open(image_filepath.new_value, true)) + { + image_filepath.value = image_filepath.new_value; + return true; + } + + // + // TODO: if file is a nonstandard size? + } + + return false; +} + +bool mscp_drive_c::SetDriveType(const char* typeName) +{ + // + // Search through drive data table for name, + // and if valid, set the type appropriately. + // + int index = 0; + while (g_driveTable[index].BlockCount != 0) + { + if (!strcasecmp(typeName, g_driveTable[index].TypeName)) + { + _driveInfo = g_driveTable[index]; + type_name.value = _driveInfo.TypeName; + capacity.value = GetBlockCount() * GetBlockSize(); + return true; + } + + index++; + } + + // Not found + return false; +} + +void mscp_drive_c::worker(void) +{ + // Nothing to do here at the moment. +} + +void mscp_drive_c::on_power_changed(void) +{ + // Take the drive offline due to power change + SetOffline(); +} + +void mscp_drive_c::on_init_changed(void) +{ + // Take the drive offline due to reset + SetOffline(); +} + + diff --git a/10.02_devices/2_src/mscp_drive.hpp b/10.02_devices/2_src/mscp_drive.hpp new file mode 100644 index 0000000..8bb856a --- /dev/null +++ b/10.02_devices/2_src/mscp_drive.hpp @@ -0,0 +1,89 @@ +/* + mscp_drive.hpp: Implementation of MSCP drive, used with MSCP controller. +*/ + +#pragma once + +#include +#include +#include "parameter.hpp" +#include "storagedrive.hpp" + +// +// Implements the backing store for MSCP disk images +// +class mscp_drive_c : public storagedrive_c +{ +public: + mscp_drive_c(storagecontroller_c *controller, uint32_t driveNumber); + ~mscp_drive_c(void); + + uint32_t GetBlockSize(void); + uint32_t GetBlockCount(void); + uint32_t GetMediaID(void); + uint64_t GetUnitID(void); + + void SetOnline(void); + void SetOffline(void); + bool IsOnline(void); + bool IsAvailable(void); + + void Write( + uint32_t blockNumber, + size_t lengthInBytes, + uint8_t* buffer); + + uint8_t* Read( + uint32_t blockNumber, + size_t lengthInBytes); + +public: + bool on_param_changed(parameter_c *param) override; + void on_power_changed(void) override; + void on_init_changed(void) override; + + void worker(void) override; + +private: + + struct DriveInfo + { + char TypeName[16]; + size_t BlockCount; + uint32_t MediaID; + bool Removable; + bool ReadOnly; + }; + + DriveInfo g_driveTable[23] + { + { "RX50", 800, 0x25658032, true, false }, + { "RX33", 2400, 0x25658021, true, false }, + { "RD51", 21600, 0x25644033, false, false }, + { "RD31", 41560, 0x2564401f, false, false }, + { "RC25", 50902, 0x20643019, true, false }, + { "RC25F", 50902, 0x20643319, true, false }, + { "RD52", 60480, 0x25644034, false, false }, + { "RD32", 83236, 0x25641047, false, false }, + { "RD53", 138672, 0x25644035, false, false }, + { "RA80", 237212, 0x20643019, false, false }, + { "RD54", 311200, 0x25644036, false, false }, + { "RA60", 400176, 0x22a4103c, true, false }, + { "RA70", 547041, 0x20643019, false, false }, + { "RA81", 891072, 0x25641051, false, false }, + { "RA82", 1216665, 0x25641052, false, false }, + { "RA71", 1367310, 0x25641047, false, false }, + { "RRD40", 1331200, 0x25652228, true, true }, + { "RA72", 1953300, 0x25641048, false, false }, + { "RA90", 2376153, 0x2564105a, false, false }, + { "RA92", 2940951, 0x2564105c, false, false }, + { "RA73", 3920490, 0x25641049, false, false }, + { "JD90", 2376153, 0x2564105d, false, false }, + { "", 0, 0, false, false } + }; + + bool SetDriveType(const char* typeName); + DriveInfo _driveInfo; + bool _online; + uint64_t _unitID; +}; diff --git a/10.02_devices/2_src/mscp_server.cpp b/10.02_devices/2_src/mscp_server.cpp index a256422..b10b47a 100644 --- a/10.02_devices/2_src/mscp_server.cpp +++ b/10.02_devices/2_src/mscp_server.cpp @@ -156,7 +156,7 @@ mscp_server::Poll(void) ControlMessageHeader* header = reinterpret_cast(message->Message); - INFO("Message size 0x%x opcode 0x%x rsvd 0x%x mod 0x%x unit %d, ursvd 0x%x, ref 0x%x", + DEBUG("Message size 0x%x opcode 0x%x rsvd 0x%x mod 0x%x unit %d, ursvd 0x%x, ref 0x%x", message->MessageLength, header->Word3.Command.Opcode, header->Word3.Command.Reserved, @@ -210,7 +210,7 @@ mscp_server::Poll(void) break; } - INFO("cmd 0x%x st 0x%x fl 0x%x", cmdStatus, GET_STATUS(cmdStatus), GET_FLAGS(cmdStatus)); + DEBUG("cmd 0x%x st 0x%x fl 0x%x", cmdStatus, GET_STATUS(cmdStatus), GET_FLAGS(cmdStatus)); // // Set the endcode and status bits @@ -302,7 +302,7 @@ mscp_server::Available( // Just set the specified drive as Available if appropriate. // We do nothing with the spin-down modifier. - INFO("MSCP AVAILABLE"); + DEBUG("MSCP AVAILABLE"); mscp_drive_c* drive = GetDrive(unitNumber); @@ -322,7 +322,7 @@ mscp_server::DetermineAccessPaths( shared_ptr message, uint16_t unitNumber) { - INFO("MSCP DETERMINE ACCESS PATHS drive %d", unitNumber); + DEBUG("MSCP DETERMINE ACCESS PATHS drive %d", unitNumber); // "This command must be treated as a no-op that always succeeds // if the unit is incapable of being connected to more than one @@ -352,7 +352,7 @@ mscp_server::Erase( EraseParameters* params = reinterpret_cast(GetParameterPointer(message)); - INFO ("MSCP ERASE unit %d chan count %d lbn %d", + DEBUG("MSCP ERASE unit %d chan count %d lbn %d", unitNumber, params->ByteCount, params->LBN); @@ -425,7 +425,7 @@ mscp_server::GetUnitStatus( }; #pragma pack(pop) - INFO("MSCP GET UNIT STATUS drive %d", unitNumber); + DEBUG("MSCP GET UNIT STATUS drive %d", unitNumber); // Adjust message length for response message->MessageLength = sizeof(GetUnitStatusResponseParameters) + @@ -552,7 +552,7 @@ mscp_server::Online( }; #pragma pack(pop) - INFO("MSCP ONLINE drive %d", unitNumber); + DEBUG("MSCP ONLINE drive %d", unitNumber); // Adjust message length for response message->MessageLength = sizeof(OnlineResponseParameters) + @@ -563,7 +563,6 @@ mscp_server::Online( if (nullptr == drive || !drive->IsAvailable()) { - INFO("Returning UNIT OFFLINE"); return STATUS(Status::UNIT_OFFLINE, 0x3, 0); // unknown -- todo move to enum } @@ -607,7 +606,7 @@ mscp_server::SetControllerCharacteristics( reinterpret_cast( GetParameterPointer(message)); - INFO("MSCP SET CONTROLLER CHARACTERISTICS"); + DEBUG("MSCP SET CONTROLLER CHARACTERISTICS"); // Adjust message length for response message->MessageLength = sizeof(SetControllerCharacteristicsParameters) + @@ -660,7 +659,7 @@ mscp_server::SetUnitCharacteristics( // TODO: handle Set Write Protect modifier - INFO("MSCP SET UNIT CHARACTERISTICS drive %d", unitNumber); + DEBUG("MSCP SET UNIT CHARACTERISTICS drive %d", unitNumber); // TODO: mostly same as Online command: should share logic. #pragma pack(push,1) @@ -687,7 +686,6 @@ mscp_server::SetUnitCharacteristics( if (nullptr == drive || !drive->IsAvailable()) { - INFO("Returning UNIT OFFLINE"); return STATUS(Status::UNIT_OFFLINE, 0x3, 0); } @@ -726,7 +724,7 @@ mscp_server::Read( ReadParameters* params = reinterpret_cast(GetParameterPointer(message)); - INFO ("MSCP READ unit %d chan o%o pa o%o count %d lbn %d", + DEBUG("MSCP READ unit %d chan o%o pa o%o count %d lbn %d", unitNumber, params->BufferPhysicalAddress >> 24, params->BufferPhysicalAddress & 0x00ffffff, @@ -800,7 +798,7 @@ mscp_server::Write( WriteParameters* params = reinterpret_cast(GetParameterPointer(message)); - INFO ("MSCP WRITE unit %d chan o%o pa o%o count %d lbn %d", + DEBUG("MSCP WRITE unit %d chan o%o pa o%o count %d lbn %d", unitNumber, params->BufferPhysicalAddress >> 24, params->BufferPhysicalAddress & 0x00ffffff, diff --git a/10.02_devices/2_src/uda.cpp b/10.02_devices/2_src/uda.cpp index d635399..446b917 100644 --- a/10.02_devices/2_src/uda.cpp +++ b/10.02_devices/2_src/uda.cpp @@ -19,6 +19,8 @@ uda_c::uda_c() : _responseRingPointer(0), _interruptVector(0), _interruptEnable(false), + _purgeInterruptEnable(false), + _step1Value(0), _initStep(InitializationStep::Uninitialized), _next_step(false) { @@ -81,6 +83,18 @@ void uda_c::Reset(void) _sa = 0; update_SA(); + _ringBase = 0; + _commandRingLength = 0; + _responseRingLength = 0; + _commandRingPointer = 0; + _responseRingPointer = 0; + _interruptVector = 0; + intr_vector.value = 0; + _interruptEnable = false; + _purgeInterruptEnable = false; + _next_step = false; + + // Signal the worker to begin the initialization sequence. StateTransition(InitializationStep::Uninitialized); @@ -148,7 +162,7 @@ void uda_c::worker(void) case InitializationStep::Step1: // Wait 100uS, set SA. - timeout.wait_ms(100); + timeout.wait_us(1000); INFO("Transition to Init state S1."); // @@ -163,7 +177,7 @@ void uda_c::worker(void) case InitializationStep::Step2: INFO("Transition to Init state S2."); - timeout.wait_ms(1000); + timeout.wait_us(1000); // update the SA read value for step 2: // S2 is set, unibus port type (0), SA bits 15-8 written // by the host in step 1. @@ -174,7 +188,7 @@ void uda_c::worker(void) case InitializationStep::Step3: // Wait 100uS, set SA. - timeout.wait_ms(1000); + timeout.wait_us(1000); INFO("Transition to Init state S3."); // Update the SA read value for step 3: @@ -185,7 +199,7 @@ void uda_c::worker(void) break; case InitializationStep::Step4: - timeout.wait_ms(100); + timeout.wait_us(100); // Clear communications area, set SA INFO("Clearing comm area at 0x%x.", _ringBase); @@ -269,7 +283,7 @@ uda_c::on_after_register_access( { // "When written with any value, it causes a hard initialization // of the port and the device controller." - // INFO("Reset due to IP read"); + DEBUG("Reset due to IP read"); Reset(); } else @@ -278,7 +292,7 @@ uda_c::on_after_register_access( // to initiate polling..." if (_initStep == InitializationStep::Complete) { - INFO("Request to start polling."); + DEBUG("Request to start polling."); _server->InitPolling(); } } @@ -742,7 +756,6 @@ uda_c::Interrupt(void) { if (_interruptEnable && _interruptVector != 0) { - INFO("interrupt"); interrupt(); } } diff --git a/10.03_app_demo/2_src/menu_devices.cpp b/10.03_app_demo/2_src/menu_devices.cpp index ea3f341..74d401f 100644 --- a/10.03_app_demo/2_src/menu_devices.cpp +++ b/10.03_app_demo/2_src/menu_devices.cpp @@ -78,7 +78,7 @@ void menus_c::menu_devices(void) { // cpu_c cpu; // create RL11 + drives - // RL11_c RL11; // instantiates also 4 RL01/02 drives + RL11_c RL11; // instantiates also 4 RL01/02 drives cur_device = NULL; paneldriver->reset(); // reset I2C, restart worker() @@ -95,9 +95,9 @@ void menus_c::menu_devices(void) { //demo_regs.install(); //demo_regs.worker_start(); - //RL11.install(); - //RL11.connect_to_panel(); - //RL11.worker_start(); + RL11.install(); + RL11.connect_to_panel(); + RL11.worker_start(); RK05.install(); RK05.worker_start(); @@ -340,12 +340,12 @@ void menus_c::menu_devices(void) { // cpu.worker_stop(); // cpu.uninstall(); - //RL11.worker_stop(); - //RL11.disconnect_from_panel(); - //RL11.uninstall(); + RL11.worker_stop(); + RL11.disconnect_from_panel(); + RL11.uninstall(); - // RK05.worker_stop(); - // RK05.uninstall(); + RK05.worker_stop(); + RK05.uninstall(); UDA50.worker_stop(); UDA50.uninstall();