1
0
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:
Josh Dersch
2019-05-07 03:20:58 +02:00
parent be3b6d57ed
commit 3204e65499
5 changed files with 321 additions and 29 deletions

View 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();
}

View 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;
};

View File

@@ -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,

View File

@@ -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();
}
}

View File

@@ -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();