mirror of
https://github.com/livingcomputermuseum/UniBone.git
synced 2026-01-28 04:47:46 +00:00
Fixed UDA reset behavior, a few things were not getting re-initialized. Adjusted timings. 2.11bsd boots/runs without
apparent issues on 11/84. Tested RT-11 on 11/84 and 11/05, mini-unix on 11/05.
This commit is contained in:
192
10.02_devices/2_src/mscp_drive.cpp
Normal file
192
10.02_devices/2_src/mscp_drive.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
mscp_drive.cpp: Implementation of MSCP disks.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
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<uint64_t>(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();
|
||||
}
|
||||
|
||||
|
||||
89
10.02_devices/2_src/mscp_drive.hpp
Normal file
89
10.02_devices/2_src/mscp_drive.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
mscp_drive.hpp: Implementation of MSCP drive, used with MSCP controller.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
};
|
||||
@@ -156,7 +156,7 @@ mscp_server::Poll(void)
|
||||
ControlMessageHeader* header =
|
||||
reinterpret_cast<ControlMessageHeader*>(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> 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<EraseParameters*>(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<SetControllerCharacteristicsParameters*>(
|
||||
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<ReadParameters*>(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<WriteParameters*>(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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user