mirror of
https://github.com/livingcomputermuseum/UniBone.git
synced 2026-01-13 15:27:09 +00:00
Initial commit of work-in-progress RH11 (MASSBUS) emulation.
This commit is contained in:
parent
a81785391e
commit
a2c8d6f2bc
51
10.02_devices/2_src/massbus_device.hpp
Normal file
51
10.02_devices/2_src/massbus_device.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
massbus_device.hpp: Generic interface for MASSBUS devices.
|
||||
|
||||
Copyright Vulcan Inc. 2020 via Living Computers: Museum + Labs, Seattle, WA.
|
||||
Contributed under the BSD 2-clause license.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Provides a virtual interface connecting a MASSBUS device implementation
|
||||
// to the RH11 Unibus device implementation. Provides metadata about
|
||||
// MASSBUS registers, defines methods for reading and writing them, and
|
||||
// provides methods for transferring blocks of data.
|
||||
//
|
||||
class massbus_device_c
|
||||
{
|
||||
public:
|
||||
|
||||
//
|
||||
// MASSBUS Register Metadata:
|
||||
//
|
||||
// Indicates whether this device implements the specified register.
|
||||
virtual bool ImplementsRegister(uint32_t register) = 0;
|
||||
|
||||
// Provides the mnemonic name for this register
|
||||
virtual std::string RegisterName(uint32_t register) = 0;
|
||||
|
||||
// Unibus DATI/DATO activity bits
|
||||
virtual bool RegisterActiveOnDATI(uint32_t register) = 0;
|
||||
virtual bool RegisterActiveOnDATO(uint32_t register) = 0;
|
||||
|
||||
// Reset value
|
||||
virtual uint16_t RegisterResetValue(uint32_t register) = 0;
|
||||
|
||||
// Writable bits
|
||||
virtual uint16_t RegisterWritableBits(uint32_t register) = 0;
|
||||
|
||||
|
||||
//
|
||||
// MASSBUS Register reads and writes
|
||||
//
|
||||
virtual void WriteRegister(uint32_t unit, uint32_t register, uint16_t value) = 0;
|
||||
virtual uint16_t ReadRegister(uint32_t unit, uint32_t register) = 0;
|
||||
|
||||
//
|
||||
// Block transfers
|
||||
// TODO: define these
|
||||
//
|
||||
|
||||
};
|
||||
168
10.02_devices/2_src/massbus_rp.cpp
Normal file
168
10.02_devices/2_src/massbus_rp.cpp
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
massbus_rp_c.cpp: Implements MASSBUS device logic for moving-head RP04/05/06 drives.
|
||||
|
||||
Copyright Vulcan Inc. 2020 via Living Computers: Museum + Labs, Seattle, WA.
|
||||
Contributed under the BSD 2-clause license.
|
||||
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
using namespace std;
|
||||
|
||||
#include "storagedrive.hpp"
|
||||
#include "rh11.hpp"
|
||||
#include "massbus_device.hpp"
|
||||
#include "massbus_rp.hpp"
|
||||
|
||||
massbus_rp_c::massbus_rp_c(
|
||||
rh11_c* controller) :
|
||||
device_c(),
|
||||
_controller(controller)
|
||||
{
|
||||
name.value="MASSBUS_RP";
|
||||
type_name.value = "massbus_rp_c";
|
||||
log_label = "MASSBUS_RP";
|
||||
|
||||
}
|
||||
|
||||
massbus_rp_c::~massbus_rp_c()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
massbus_rp_c::ImplementsRegister(
|
||||
uint32_t register)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string
|
||||
massbus_rp_c::RegisterName(
|
||||
uint32_t register)
|
||||
{
|
||||
std::string name("foo");
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
bool
|
||||
massbus_rp_c::RegisterActiveOnDATI(
|
||||
uint32_t reg)
|
||||
{
|
||||
return _registerMetadata[reg].ActiveOnDATI;
|
||||
}
|
||||
|
||||
bool
|
||||
massbus_rp_c::RegisterActiveOnDATO(
|
||||
uint32_t reg)
|
||||
{
|
||||
return _registerMetadata[reg].ActiveOnDATO;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
massbus_rp_c::RegisterResetValue(
|
||||
uint32_t reg)
|
||||
{
|
||||
return _registerMetadata[reg].ResetValue;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
massbus_rp_c::RegisterWritableBits(
|
||||
uint32_t reg)
|
||||
{
|
||||
return _registerMetadata[reg].WritableBits;
|
||||
}
|
||||
|
||||
void
|
||||
massbus_rp_c::WriteRegister(
|
||||
uint32_t unit,
|
||||
uint32_t reg,
|
||||
uint16_t value)
|
||||
{
|
||||
INFO("RP reg write: unit %d register 0%o value 0%o", unit, reg, value);
|
||||
|
||||
switch(reg)
|
||||
{
|
||||
case 0:
|
||||
DoCommand(unit, value);
|
||||
break;
|
||||
|
||||
default:
|
||||
FATAL("Unimplemented RP register write.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void massbus_rp_c::DoCommand(
|
||||
uint32_t unit,
|
||||
uint16_t command)
|
||||
{
|
||||
// check for GO bit; if unset we have nothing to do here.
|
||||
if ((command & RP_GO) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t function = (command & RP_FUNC) >> 1;
|
||||
|
||||
INFO("RP function 0%o", function);
|
||||
|
||||
switch(function)
|
||||
{
|
||||
case FunctionCode::Nop:
|
||||
// Nothing.
|
||||
break;
|
||||
|
||||
case FunctionCode::ReadInPreset:
|
||||
INFO("RP Read-In Preset");
|
||||
//
|
||||
// "This command sets the VV (volume valid) bit, clears the desired
|
||||
// sector/track address register, and clears the FMT, HCI, and ECI
|
||||
// bits in the offset register. It is used to bootstrap the device."
|
||||
//
|
||||
set_bit
|
||||
break;
|
||||
|
||||
case FunctionCode::ReadData:
|
||||
INFO("RP Read Data");
|
||||
break;
|
||||
|
||||
default:
|
||||
FATAL("Unimplemented RP function.");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint16_t
|
||||
massbus_rp_c::ReadRegister(
|
||||
uint32_t unit,
|
||||
uint32_t reg)
|
||||
{
|
||||
INFO("RP reg read: unit %d register 0%o", unit, reg);
|
||||
|
||||
FATAL("Unimplemented RP register read.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// background worker function
|
||||
void
|
||||
massbus_rp_c::worker(
|
||||
unsigned instance)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
massbus_rp_c::on_power_changed(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
massbus_rp_c::on_init_changed(void)
|
||||
{
|
||||
|
||||
}
|
||||
132
10.02_devices/2_src/massbus_rp.hpp
Normal file
132
10.02_devices/2_src/massbus_rp.hpp
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
massbus_rp_c.hpp: Implements MASSBUS device logic for moving-head RP04/05/06 drives.
|
||||
|
||||
Copyright Vulcan Inc. 2020 via Living Computers: Museum + Labs, Seattle, WA.
|
||||
Contributed under the BSD 2-clause license.
|
||||
|
||||
*/
|
||||
#ifndef _MASSBUS_RP_HPP_
|
||||
#define _MASSBUS_RP_HPP_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
using namespace std;
|
||||
|
||||
#include "storagedrive.hpp"
|
||||
#include "rh11.hpp"
|
||||
#include "massbus_device.hpp"
|
||||
|
||||
// Registers
|
||||
enum class Registers
|
||||
{
|
||||
Control = 00,
|
||||
Status = 01,
|
||||
Error1 = 02,
|
||||
Maintenance = 03,
|
||||
AttentionSummary = 04,
|
||||
DesiredAddress = 05,
|
||||
LookAhead = 07,
|
||||
DriveType = 06,
|
||||
SerialNo = 014,
|
||||
Offset = 011,
|
||||
DesiredCylinderAddress = 012,
|
||||
CurrentCylinderAddress = 013,
|
||||
Error2 = 010,
|
||||
Error3 = 015,
|
||||
ECCPosition = 016,
|
||||
ECCPattern = 017,
|
||||
};
|
||||
|
||||
// Control Function codes
|
||||
#define RP_GO 01
|
||||
#define RP_FUNC 076
|
||||
|
||||
enum class FunctionCode
|
||||
{
|
||||
Nop = 00,
|
||||
Unload = 01,
|
||||
Recalibrate = 03,
|
||||
DriveClear = 04,
|
||||
Release = 05,
|
||||
Search = 014,
|
||||
WriteCheckData = 024,
|
||||
WriteCheckHeaderAndData = 025,
|
||||
WriteData = 030,
|
||||
WriteHeaderAndData = 031,
|
||||
ReadData = 034,
|
||||
ReadHeaderAndData = 035,
|
||||
Seek = 02,
|
||||
Offset = 06,
|
||||
ReturnToCenterline = 07,
|
||||
PackAcknowledge = 011,
|
||||
ReadInPreset = 010,
|
||||
};
|
||||
|
||||
//
|
||||
// Register metadata
|
||||
//
|
||||
struct rp_register_data
|
||||
{
|
||||
bool ActiveOnDATI;
|
||||
bool ActiveOnDATO;
|
||||
uint16_t ResetValue;
|
||||
uint16_t WritableBits;
|
||||
};
|
||||
|
||||
//
|
||||
// Encapsulates MASSBUS control logic for RP04/05/06 moving-head disks.
|
||||
// Talks to one or more rp_drive units.
|
||||
//
|
||||
class massbus_rp_c: public device_c, public massbus_device_c
|
||||
{
|
||||
public:
|
||||
massbus_rp_c(rh11_c* controller);
|
||||
virtual ~massbus_rp_c();
|
||||
|
||||
public:
|
||||
bool ImplementsRegister(uint32_t register) override;
|
||||
std::string RegisterName(uint32_t register) override;
|
||||
|
||||
bool RegisterActiveOnDATI(uint32_t register) override;
|
||||
bool RegisterActiveOnDATO(uint32_t register) override;
|
||||
|
||||
uint16_t RegisterResetValue(uint32_t register) override;
|
||||
uint16_t RegisterWritableBits(uint32_t register) override;
|
||||
|
||||
void WriteRegister(uint32_t unit, uint32_t register, uint16_t value) override;
|
||||
uint16_t ReadRegister(uint32_t unit, uint32_t register) override;
|
||||
|
||||
private:
|
||||
void DoCommand(uint32_t unit, uint16_t command);
|
||||
|
||||
// background worker function
|
||||
void worker(unsigned instance) override;
|
||||
|
||||
void on_power_changed(void) override;
|
||||
void on_init_changed(void) override;
|
||||
private:
|
||||
rh11_c* _controller;
|
||||
|
||||
rp_register_data _registerMetadata[16] =
|
||||
{
|
||||
{ false, false, 0, 0 }, // 0, not used
|
||||
{ false, false, 0, 0177700 }, // Status
|
||||
{ false, true , 0, 0177777 }, // Error #1 - writable by diagnostics
|
||||
{ false, true , 0, 0177777 }, // Maintenance
|
||||
{ false, false, 0, 0 }, // Attention summary
|
||||
{ false, false, 0, 0017437 }, // Desired Sector/Track
|
||||
{ false, false, 0, 0 }, // Look Ahead
|
||||
{ false, false, 0, 0 }, // Drive Type
|
||||
{ false, false, 0, 0 }, // Serial Number
|
||||
{ false, false, 0, 0177777 }, // Offset
|
||||
{ false, false, 0, 0001777 }, // Desired Cylinder
|
||||
{ false, false, 0, 0 }, // Current Cylinder
|
||||
{ false, false, 0, 0 }, // Error #2
|
||||
{ false, false, 0, 0 }, // Error #3
|
||||
{ false, false, 0, 0 }, // ECC Position
|
||||
{ false, false, 0, 0 }, // ECC Pattern
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -17,7 +17,8 @@
|
||||
//
|
||||
// Implements the backing store for MSCP disk images
|
||||
//
|
||||
class mscp_drive_c: public storagedrive_c {
|
||||
class mscp_drive_c: public storagedrive_c
|
||||
{
|
||||
public:
|
||||
mscp_drive_c(storagecontroller_c *controller, uint32_t driveNumber);
|
||||
~mscp_drive_c(void);
|
||||
@ -55,7 +56,8 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
struct DriveInfo {
|
||||
struct DriveInfo
|
||||
{
|
||||
char TypeName[16];
|
||||
size_t BlockCount;
|
||||
uint32_t MediaID;
|
||||
|
||||
291
10.02_devices/2_src/rh11.cpp
Executable file
291
10.02_devices/2_src/rh11.cpp
Executable file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
rh11_cpp: RH11 UNIBUS-MASSBUS controller
|
||||
|
||||
Copyright Vulcan Inc. 2020 via Living Computers: Museum + Labs, Seattle, WA.
|
||||
Contributed under the BSD 2-clause license.
|
||||
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "unibus.h"
|
||||
#include "unibusadapter.hpp"
|
||||
#include "unibusdevice.hpp"
|
||||
#include "storagecontroller.hpp"
|
||||
#include "rh11.hpp"
|
||||
#include "massbus_rp.hpp"
|
||||
|
||||
rh11_c::rh11_c() :
|
||||
storagecontroller_c(),
|
||||
_massbus(nullptr),
|
||||
_interruptEnable(false),
|
||||
_busAddress(0),
|
||||
_unit(0)
|
||||
{
|
||||
// static config
|
||||
name.value = "rh";
|
||||
type_name.value = "RH11";
|
||||
log_label = "rh";
|
||||
|
||||
// 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);
|
||||
|
||||
// TODO: allow configuration for different device types
|
||||
_massbus.reset(new massbus_rp_c(this));
|
||||
|
||||
// The RH11 controller exposes up to 32 registers, not all are used
|
||||
// and use depends on the devices attached to the MASSBUS.
|
||||
// TODO: What does an RH11 do when an unimplemented register is accessed?
|
||||
register_count = 32;
|
||||
|
||||
for (int i=0; i<register_count; i++)
|
||||
{
|
||||
RH_reg[i] = &(this->registers[i]);
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case RHCS1:
|
||||
// Control & Status Reg 1
|
||||
strcpy(RH_reg[i]->name, "RHCS1");
|
||||
RH_reg[i]->active_on_dati = false;
|
||||
RH_reg[i]->active_on_dato = true;
|
||||
RH_reg[i]->reset_value = 0x0008;
|
||||
RH_reg[i]->writable_bits = 0x037f;
|
||||
break;
|
||||
|
||||
case RHWC:
|
||||
// Word count
|
||||
strcpy(RH_reg[i]->name, "RHWC");
|
||||
RH_reg[i]->active_on_dati = false;
|
||||
RH_reg[i]->active_on_dato = false;
|
||||
RH_reg[i]->reset_value = 0;
|
||||
RH_reg[i]->writable_bits = 0xffff;
|
||||
break;
|
||||
|
||||
case RHBA:
|
||||
// Bus address
|
||||
strcpy(RH_reg[i]->name, "RHBA");
|
||||
RH_reg[i]->active_on_dati = false;
|
||||
RH_reg[i]->active_on_dato = false;
|
||||
RH_reg[i]->reset_value = 0;
|
||||
RH_reg[i]->writable_bits = 0xffff;
|
||||
break;
|
||||
|
||||
case RHCS2:
|
||||
// Control & Status Reg 2
|
||||
strcpy(RH_reg[i]->name, "RHCS2");
|
||||
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 = 0x003f;
|
||||
break;
|
||||
|
||||
case RHDB:
|
||||
// Data Buffer (maintenance only)
|
||||
strcpy(RH_reg[i]->name, "RHDB");
|
||||
RH_reg[i]->active_on_dati = true;
|
||||
RH_reg[i]->active_on_dato = true;
|
||||
RH_reg[i]->reset_value = 0;
|
||||
RH_reg[i]->writable_bits = 0xffff;
|
||||
break;
|
||||
|
||||
default:
|
||||
//
|
||||
// This is a "REMOTE" register implemented by the device(s)
|
||||
// attached to the massbus.
|
||||
//
|
||||
if (_massbus->ImplementsRegister(i))
|
||||
{
|
||||
strcpy(RH_reg[i]->name, _massbus->RegisterName(i).c_str());
|
||||
RH_reg[i]->active_on_dati = _massbus->RegisterActiveOnDATI(i);
|
||||
RH_reg[i]->active_on_dato = _massbus->RegisterActiveOnDATO(i);
|
||||
RH_reg[i]->reset_value = _massbus->RegisterResetValue(i);
|
||||
RH_reg[i]->writable_bits = _massbus->RegisterWritableBits(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not implemented by this device type
|
||||
RH_reg[i] = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rh11_c::~rh11_c()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rh11_c::write_register(
|
||||
uint32_t reg,
|
||||
uint16_t value)
|
||||
{
|
||||
set_register_dati_value(
|
||||
RH_reg[_massbusToUnibusRegisterMap[reg]],
|
||||
value,
|
||||
"write_register");
|
||||
}
|
||||
|
||||
uint16_t
|
||||
rh11_c::read_register(
|
||||
uint32_t reg)
|
||||
{
|
||||
return get_register_dato_value(
|
||||
RH_reg[_massbusToUnibusRegisterMap[reg]]);
|
||||
}
|
||||
|
||||
// return false, if illegal parameter value.
|
||||
// verify "new_value", must output error messages
|
||||
bool rh11_c::on_param_changed(parameter_c *param)
|
||||
{
|
||||
// no own parameter or "enable" logic
|
||||
if (param == &priority_slot)
|
||||
{
|
||||
dma_request.set_priority_slot(priority_slot.new_value);
|
||||
intr_request.set_priority_slot(priority_slot.new_value);
|
||||
}
|
||||
else if (param == &intr_level)
|
||||
{
|
||||
intr_request.set_level(intr_level.new_value);
|
||||
}
|
||||
else if
|
||||
(param == &intr_vector)
|
||||
{
|
||||
intr_request.set_vector(intr_vector.new_value);
|
||||
}
|
||||
return storagecontroller_c::on_param_changed(param); // more actions (for enable)
|
||||
}
|
||||
|
||||
// Background worker.
|
||||
// Handle device operations.
|
||||
void rh11_c::worker(unsigned instance)
|
||||
{
|
||||
UNUSED(instance); // only one
|
||||
|
||||
worker_init_realtime_priority(rt_device);
|
||||
|
||||
bool do_interrupt = true;
|
||||
timeout_c timeout;
|
||||
|
||||
/*
|
||||
while (!workers_terminate)
|
||||
{
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//
|
||||
// process DATI/DATO access to the RK11's "active" registers.
|
||||
// !! called asynchronuously by PRU, with SSYN asserted and blocking UNIBUS.
|
||||
// The time between PRU event and program flow into this callback
|
||||
// is determined by ARM Linux context switch
|
||||
//
|
||||
// UNIBUS DATO cycles let dati_flipflops "flicker" outside of this proc:
|
||||
// do not read back dati_flipflops.
|
||||
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)
|
||||
{
|
||||
case RHCS1: // Control & Status 1
|
||||
{
|
||||
if (UNIBUS_CONTROL_DATO == unibus_control)
|
||||
{
|
||||
// IE bit
|
||||
_interruptEnable = !!(value & 0x40);
|
||||
|
||||
// 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 %x BA 0%o", _interruptEnable, _busAddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RHCS2: // Control & Status 2
|
||||
{
|
||||
if (UNIBUS_CONTROL_DATO == unibus_control)
|
||||
{
|
||||
_unit = (value & 0x7);
|
||||
_busAddressIncrementProhibit = !!(value & 0x8);
|
||||
_parityTest = !!(value & 0x10);
|
||||
|
||||
// TODO: handle System Register Clear (bit 5)
|
||||
INFO("RHCS2: unit %d", _unit);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// See if a massbus device wishes to answer
|
||||
if (RH_reg[device_reg->index] != nullptr)
|
||||
{
|
||||
if (UNIBUS_CONTROL_DATO == unibus_control)
|
||||
{
|
||||
_massbus->WriteRegister(_unit, _unibusToMassbusRegisterMap[device_reg->index], value);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_register_dati_value(
|
||||
device_reg,
|
||||
_massbus->ReadRegister(_unit, _unibusToMassbusRegisterMap[device_reg->index]),
|
||||
"on_after_register_access");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void rh11_c::invoke_interrupt(void)
|
||||
{
|
||||
}
|
||||
|
||||
void rh11_c::reset_controller(void)
|
||||
{
|
||||
reset_unibus_registers();
|
||||
|
||||
}
|
||||
|
||||
void rh11_c::on_power_changed(void)
|
||||
{
|
||||
storagecontroller_c::on_power_changed();
|
||||
|
||||
if (power_down)
|
||||
{
|
||||
// power-on defaults
|
||||
reset_controller();
|
||||
}
|
||||
}
|
||||
|
||||
// UNIBUS INIT: clear all registers
|
||||
void rh11_c::on_init_changed(void)
|
||||
{
|
||||
// write all registers to "reset-values"
|
||||
if (init_asserted)
|
||||
{
|
||||
reset_controller();
|
||||
}
|
||||
|
||||
storagecontroller_c::on_init_changed();
|
||||
}
|
||||
|
||||
void
|
||||
rh11_c::on_drive_status_changed(storagedrive_c *drive)
|
||||
{
|
||||
|
||||
}
|
||||
158
10.02_devices/2_src/rh11.hpp
Executable file
158
10.02_devices/2_src/rh11.hpp
Executable file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
rh11.hpp: RH11 UNIBUS-MASSBUS controller
|
||||
|
||||
Copyright Vulcan Inc. 2020 via Living Computers: Museum + Labs, Seattle, WA.
|
||||
Contributed under the BSD 2-clause license.
|
||||
|
||||
*/
|
||||
#ifndef _RH11_HPP_
|
||||
#define _RH11_HPP_
|
||||
|
||||
#include <fstream>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "unibusadapter.hpp"
|
||||
#include "unibusdevice.hpp"
|
||||
#include "storagecontroller.hpp"
|
||||
#include "massbus_device.hpp"
|
||||
|
||||
// Maps the unibus register index to the MASSBUS register number.
|
||||
// -1 entries are local to the rh11.
|
||||
int32_t _unibusToMassbusRegisterMap[] =
|
||||
{
|
||||
00, // 776700
|
||||
-1, // 776702
|
||||
-1, // 776704
|
||||
05, // 776706
|
||||
-1, // 776710
|
||||
01, // 776712
|
||||
02, // 776714
|
||||
04, // 776716
|
||||
07, // 776720
|
||||
-1, // 776722
|
||||
03, // 776724
|
||||
06, // 776726
|
||||
010, // 776730
|
||||
011, // 776732
|
||||
012, // 776734
|
||||
013, // 776736
|
||||
014, // 776740
|
||||
015, // 776742
|
||||
016, // etc.
|
||||
017,
|
||||
020,
|
||||
021,
|
||||
022,
|
||||
023,
|
||||
024,
|
||||
025,
|
||||
026,
|
||||
027,
|
||||
030,
|
||||
031,
|
||||
032,
|
||||
033
|
||||
};
|
||||
|
||||
int32_t _massbusToUnibusRegisterMap[] =
|
||||
{
|
||||
00, // 0
|
||||
05,
|
||||
06,
|
||||
012,
|
||||
07,
|
||||
03,
|
||||
013,
|
||||
010,
|
||||
014, // 10
|
||||
015,
|
||||
016,
|
||||
017,
|
||||
020,
|
||||
021,
|
||||
022,
|
||||
023,
|
||||
024, // 20
|
||||
025,
|
||||
026,
|
||||
027,
|
||||
030,
|
||||
031,
|
||||
032,
|
||||
033,
|
||||
034, // 30
|
||||
035,
|
||||
036,
|
||||
037,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
};
|
||||
|
||||
class rh11_c: public storagecontroller_c
|
||||
{
|
||||
private:
|
||||
|
||||
// 32 RH11 Registers:
|
||||
unibusdevice_register_t* RH_reg[32];
|
||||
|
||||
// "Local" registers (or mostly local anyway)
|
||||
#define RHCS1 0
|
||||
#define RHWC 1
|
||||
#define RHBA 2
|
||||
#define RHCS2 4
|
||||
#define RHDB 011
|
||||
|
||||
// Unibusadapter: RH11 has one INTR and DMA
|
||||
// should be merged with RH11::DMARequest
|
||||
dma_request_c dma_request = dma_request_c(this); // operated by unibusadapter
|
||||
intr_request_c intr_request = intr_request_c(this);
|
||||
|
||||
void invoke_interrupt(void);
|
||||
void reset_controller(void);
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<massbus_device_c> _massbus;
|
||||
|
||||
// Control & Status reg 1 bits
|
||||
bool _interruptEnable;
|
||||
uint32_t _busAddress;
|
||||
|
||||
// Control & Status reg 2 bits
|
||||
uint16_t _unit;
|
||||
bool _busAddressIncrementProhibit;
|
||||
bool _parityTest;
|
||||
|
||||
public:
|
||||
|
||||
rh11_c();
|
||||
virtual ~rh11_c();
|
||||
|
||||
// Unibus register access (for devices on massbus)
|
||||
void write_register(uint32_t reg, uint16_t value);
|
||||
uint16_t read_register(uint32_t reg);
|
||||
|
||||
public:
|
||||
|
||||
// background worker function
|
||||
void worker(unsigned instance) override;
|
||||
|
||||
// called by unibusadapter on emulated register access
|
||||
void on_after_register_access(
|
||||
unibusdevice_register_t *device_reg,
|
||||
uint8_t unibus_control) override;
|
||||
|
||||
bool on_param_changed(parameter_c *param) override;
|
||||
void on_power_changed(void) override;
|
||||
void on_init_changed(void) override;
|
||||
|
||||
void on_drive_status_changed(storagedrive_c *drive) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -104,6 +104,8 @@ OBJECTS = $(OBJDIR)/application.o \
|
||||
$(OBJDIR)/uda.o \
|
||||
$(OBJDIR)/mscp_server.o \
|
||||
$(OBJDIR)/mscp_drive.o \
|
||||
$(OBJDIR)/rh11.o \
|
||||
$(OBJDIR)/massbus_rp.o \
|
||||
$(OBJDIR)/rs232.o \
|
||||
$(OBJDIR)/rs232adapter.o \
|
||||
$(OBJDIR)/dl11w.o \
|
||||
@ -239,6 +241,15 @@ $(OBJDIR)/mscp_server.o : $(DEVICE_SRC_DIR)/mscp_server.cpp $(DEVICE_SRC_DIR)/
|
||||
$(OBJDIR)/mscp_drive.o : $(DEVICE_SRC_DIR)/mscp_drive.cpp $(DEVICE_SRC_DIR)/mscp_drive.hpp
|
||||
$(CC) $(CCFLAGS) $< -o $@
|
||||
|
||||
$(OBJDIR)/rh11.o : $(DEVICE_SRC_DIR)/rh11.cpp $(DEVICE_SRC_DIR)/rh11.hpp
|
||||
$(CC) $(CCFLAGS) $< -o $@
|
||||
|
||||
$(OBJDIR)/massbus_device.o : $(DEVICE_SRC_DIR)/massbus_device.cpp $(DEVICE_SRC_DIR)/massbus_device.hpp
|
||||
$(CC) $(CCFLAGS) $< -o $@
|
||||
|
||||
$(OBJDIR)/massbus_rp.o : $(DEVICE_SRC_DIR)/massbus_rp.cpp $(DEVICE_SRC_DIR)/massbus_rp.hpp
|
||||
$(CC) $(CCFLAGS) $< -o $@
|
||||
|
||||
$(OBJDIR)/rs232.o : $(DEVICE_SRC_DIR)/rs232.cpp $(DEVICE_SRC_DIR)/rs232.hpp
|
||||
$(CC) $(CCFLAGS) $< -o $@
|
||||
|
||||
|
||||
@ -52,6 +52,7 @@
|
||||
#include "rl11.hpp"
|
||||
#include "rk11.hpp"
|
||||
#include "uda.hpp"
|
||||
#include "rh11.hpp"
|
||||
#include "dl11w.hpp"
|
||||
#include "cpu.hpp"
|
||||
|
||||
@ -156,6 +157,8 @@ void application_c::menu_devices(const char *menu_code, bool with_emulated_CPU)
|
||||
rk11_c *RK11 = new rk11_c();
|
||||
// Create UDA50
|
||||
uda_c *UDA50 = new uda_c();
|
||||
// Create RH11
|
||||
rh11_c *RH11 = new rh11_c();
|
||||
// Create SLU+ LTC
|
||||
slu_c *DL11 = new slu_c();
|
||||
// to inject characters into DL11 receiver
|
||||
@ -567,6 +570,9 @@ void application_c::menu_devices(const char *menu_code, bool with_emulated_CPU)
|
||||
UDA50->enabled.set(false);
|
||||
delete UDA50;
|
||||
|
||||
RH11->enabled.set(false);
|
||||
delete RH11;
|
||||
|
||||
//test_controller->enabled.set(false);
|
||||
//delete test_controller;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user