mirror of
https://github.com/livingcomputermuseum/UniBone.git
synced 2026-05-04 06:59:58 +00:00
Merge pull request #1 from livingcomputermuseum/master
Add RK11-D / RK05 emulation
This commit is contained in:
318
10.02_devices/2_src/rk05.cpp
Executable file
318
10.02_devices/2_src/rk05.cpp
Executable file
@@ -0,0 +1,318 @@
|
|||||||
|
/* rk05.cpp: implementation of RK05 disk drive, attached to RK11D controller
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#include "logger.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
#include "rk11.hpp"
|
||||||
|
#include "rk05.hpp"
|
||||||
|
|
||||||
|
rk05_c::rk05_c(storagecontroller_c *controller) :
|
||||||
|
storagedrive_c(controller),
|
||||||
|
_current_cylinder(0),
|
||||||
|
_seek_count(0),
|
||||||
|
_sectorCount(0),
|
||||||
|
_wps(false),
|
||||||
|
_rwsrdy(true),
|
||||||
|
_dry(false),
|
||||||
|
_sok(false),
|
||||||
|
_sin(false),
|
||||||
|
_dru(false),
|
||||||
|
_rk05(true),
|
||||||
|
_dpl(false),
|
||||||
|
_scp(false)
|
||||||
|
{
|
||||||
|
log_label = "RK05";
|
||||||
|
_geometry.Cylinders = 203; // Standard RK05
|
||||||
|
_geometry.Heads = 2;
|
||||||
|
_geometry.Sectors = 12;
|
||||||
|
_geometry.Sector_Size_Bytes = 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Status registers
|
||||||
|
//
|
||||||
|
|
||||||
|
uint32_t rk05_c::get_sector_counter(void)
|
||||||
|
{
|
||||||
|
return _sectorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rk05_c::get_write_protect(void)
|
||||||
|
{
|
||||||
|
return _wps;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rk05_c::get_rws_ready(void)
|
||||||
|
{
|
||||||
|
return _rwsrdy;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rk05_c::get_drive_ready(void)
|
||||||
|
{
|
||||||
|
return _dry;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rk05_c::get_sector_counter_ok(void)
|
||||||
|
{
|
||||||
|
return _sok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rk05_c::get_seek_incomplete(void)
|
||||||
|
{
|
||||||
|
return _sin;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rk05_c::get_drive_unsafe(void)
|
||||||
|
{
|
||||||
|
return _dru;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rk05_c::get_rk05_disk_online(void)
|
||||||
|
{
|
||||||
|
return _rk05;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rk05_c::get_drive_power_low(void)
|
||||||
|
{
|
||||||
|
return _dpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rk05_c::get_search_complete(void)
|
||||||
|
{
|
||||||
|
bool scp = _scp;
|
||||||
|
_scp = false;
|
||||||
|
return scp;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Reset / Power handlers
|
||||||
|
//
|
||||||
|
|
||||||
|
void rk05_c::on_power_changed(void)
|
||||||
|
{
|
||||||
|
// called at high priority.
|
||||||
|
if (power_down)
|
||||||
|
{
|
||||||
|
// power-on defaults
|
||||||
|
drive_reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk05_c::on_init_changed(void)
|
||||||
|
{
|
||||||
|
// called at high priority.
|
||||||
|
|
||||||
|
if (init_asserted)
|
||||||
|
{
|
||||||
|
drive_reset();
|
||||||
|
|
||||||
|
if (!file_is_open())
|
||||||
|
{
|
||||||
|
load_image(image_filepath.value);
|
||||||
|
|
||||||
|
file_open(image_filepath.value, true);
|
||||||
|
_dry = file_is_open();
|
||||||
|
controller->on_drive_status_changed(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Disk actions (read/write/seek/reset)
|
||||||
|
//
|
||||||
|
|
||||||
|
void rk05_c::read_sector(
|
||||||
|
uint32_t cylinder,
|
||||||
|
uint32_t surface,
|
||||||
|
uint32_t sector,
|
||||||
|
uint16_t* out_buffer)
|
||||||
|
{
|
||||||
|
assert(cylinder < _geometry.Cylinders);
|
||||||
|
assert(surface < _geometry.Heads);
|
||||||
|
assert(sector < _geometry.Sectors);
|
||||||
|
|
||||||
|
_current_cylinder = cylinder;
|
||||||
|
|
||||||
|
// SCP is cleared at the start of any function.
|
||||||
|
_scp = false;
|
||||||
|
|
||||||
|
//
|
||||||
|
// reset Read/Write/Seek Ready flag while we do this operation
|
||||||
|
//
|
||||||
|
_rwsrdy = false;
|
||||||
|
controller->on_drive_status_changed(this);
|
||||||
|
|
||||||
|
timeout_c delay;
|
||||||
|
|
||||||
|
// Delay for seek / read.
|
||||||
|
// TODO: maybe base this on real drive specs.
|
||||||
|
delay.wait_ms(10);
|
||||||
|
|
||||||
|
// Read the sector into the buffer passed to us.
|
||||||
|
file_read(
|
||||||
|
reinterpret_cast<uint8_t*>(out_buffer),
|
||||||
|
get_disk_byte_offset(cylinder, surface, sector),
|
||||||
|
_geometry.Sector_Size_Bytes);
|
||||||
|
|
||||||
|
// Set RWS ready now that we're done.
|
||||||
|
_rwsrdy = true;
|
||||||
|
|
||||||
|
controller->on_drive_status_changed(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk05_c::write_sector(
|
||||||
|
uint32_t cylinder,
|
||||||
|
uint32_t surface,
|
||||||
|
uint32_t sector,
|
||||||
|
uint16_t* in_buffer)
|
||||||
|
{
|
||||||
|
assert(cylinder < _geometry.Cylinders);
|
||||||
|
assert(surface < _geometry.Heads);
|
||||||
|
assert(sector < _geometry.Sectors);
|
||||||
|
|
||||||
|
_current_cylinder = cylinder;
|
||||||
|
|
||||||
|
// SCP is cleared at the start of any function.
|
||||||
|
_scp = false;
|
||||||
|
|
||||||
|
//
|
||||||
|
// reset Read/Write/Seek Ready flag while we do this operation
|
||||||
|
//
|
||||||
|
_rwsrdy = false;
|
||||||
|
controller->on_drive_status_changed(this);
|
||||||
|
|
||||||
|
timeout_c delay;
|
||||||
|
|
||||||
|
// Delay for seek / read.
|
||||||
|
// TODO: maybe base this on real drive specs.
|
||||||
|
delay.wait_ms(10);
|
||||||
|
|
||||||
|
// Read the sector into the buffer passed to us.
|
||||||
|
file_write(
|
||||||
|
reinterpret_cast<uint8_t*>(in_buffer),
|
||||||
|
get_disk_byte_offset(cylinder, surface, sector),
|
||||||
|
_geometry.Sector_Size_Bytes);
|
||||||
|
|
||||||
|
// Set RWS ready now that we're done.
|
||||||
|
_rwsrdy = true;
|
||||||
|
|
||||||
|
controller->on_drive_status_changed(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk05_c::seek(
|
||||||
|
uint32_t cylinder)
|
||||||
|
{
|
||||||
|
assert(cylinder < _geometry.Cylinders);
|
||||||
|
|
||||||
|
_seek_count = abs((int32_t)_current_cylinder - (int32_t)cylinder) + 1;
|
||||||
|
_current_cylinder = cylinder;
|
||||||
|
|
||||||
|
if (_seek_count > 0)
|
||||||
|
{
|
||||||
|
// We'll be busy for awhile:
|
||||||
|
_rwsrdy = false;
|
||||||
|
_scp = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_rwsrdy = true;
|
||||||
|
_scp = true;
|
||||||
|
}
|
||||||
|
controller->on_drive_status_changed(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk05_c::set_write_protect(bool protect)
|
||||||
|
{
|
||||||
|
// Not implemented at the moment.
|
||||||
|
_scp = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk05_c::drive_reset(void)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// "The controller directs the selected disk drive to move its
|
||||||
|
// head mechanism to cylinder address 000 and reset all active
|
||||||
|
// error status lines."
|
||||||
|
//
|
||||||
|
// This is basically the same as a seek to cylinder 0 plus
|
||||||
|
// a reset of error status.
|
||||||
|
//
|
||||||
|
_sin = false;
|
||||||
|
_dru = false;
|
||||||
|
_dpl = false;
|
||||||
|
controller->on_drive_status_changed(this);
|
||||||
|
|
||||||
|
seek(0);
|
||||||
|
// SCP change will be posted when the seek instigated above is completed.
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk05_c::worker(void)
|
||||||
|
{
|
||||||
|
timeout_c timeout;
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
if (_seek_count > 0)
|
||||||
|
{
|
||||||
|
// A seek is active. Wait at least 10ms and decrement
|
||||||
|
// The seek count by a certain amount. This is completely fudged.
|
||||||
|
timeout.wait_ms(3);
|
||||||
|
_seek_count -= 25;
|
||||||
|
// since simultaneous interrupts
|
||||||
|
// confuse me right now
|
||||||
|
|
||||||
|
if (_seek_count < 0)
|
||||||
|
{
|
||||||
|
// Out of seeks to do, let the controller know we're done.
|
||||||
|
_scp = true;
|
||||||
|
controller->on_drive_status_changed(this);
|
||||||
|
|
||||||
|
// Set RWSRDY only after posting status change / interrupt...
|
||||||
|
_rwsrdy = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Move SectorCounter to next sector
|
||||||
|
// every 1/300th of a second (or so).
|
||||||
|
// (1600 revs/min = 25 revs / sec = 300 sectors / sec)
|
||||||
|
timeout.wait_ms(3);
|
||||||
|
if (file_is_open())
|
||||||
|
{
|
||||||
|
_sectorCount = (_sectorCount + 1) % 12;
|
||||||
|
_sok = true;
|
||||||
|
controller->on_drive_status_changed(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crude: Check for disk image change; if changed we load the new image.
|
||||||
|
if (image_filepath.value != _currentFilePath)
|
||||||
|
{
|
||||||
|
load_image(image_filepath.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t rk05_c::get_disk_byte_offset(
|
||||||
|
uint32_t cylinder,
|
||||||
|
uint32_t surface,
|
||||||
|
uint32_t sector)
|
||||||
|
{
|
||||||
|
return _geometry.Sector_Size_Bytes *
|
||||||
|
((cylinder * _geometry.Heads * _geometry.Sectors) +
|
||||||
|
(surface * _geometry.Sectors) +
|
||||||
|
sector);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk05_c::load_image(std::string path)
|
||||||
|
{
|
||||||
|
file_open(image_filepath.value, true);
|
||||||
|
_dry = file_is_open();
|
||||||
|
controller->on_drive_status_changed(this);
|
||||||
|
_currentFilePath = path;
|
||||||
|
}
|
||||||
102
10.02_devices/2_src/rk05.hpp
Executable file
102
10.02_devices/2_src/rk05.hpp
Executable file
@@ -0,0 +1,102 @@
|
|||||||
|
/* rk05.cpp: implementation of RK05 disk drive, used with RK11D controller
|
||||||
|
|
||||||
|
*/
|
||||||
|
#ifndef _RK05_HPP_
|
||||||
|
#define _RK05_HPP_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#include "storagedrive.hpp"
|
||||||
|
#include "rk11.hpp"
|
||||||
|
|
||||||
|
enum DriveType
|
||||||
|
{
|
||||||
|
RK05 = 0,
|
||||||
|
RK05f = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Geometry
|
||||||
|
{
|
||||||
|
uint32_t Cylinders;
|
||||||
|
uint32_t Heads;
|
||||||
|
uint32_t Sectors;
|
||||||
|
uint32_t Sector_Size_Bytes;
|
||||||
|
uint32_t Sector_Size_Words;
|
||||||
|
};
|
||||||
|
|
||||||
|
class rk05_c: public storagedrive_c
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// Drive geometry details
|
||||||
|
Geometry _geometry;
|
||||||
|
|
||||||
|
// Current position of the heads
|
||||||
|
volatile uint32_t _current_cylinder;
|
||||||
|
volatile int32_t _seek_count;
|
||||||
|
|
||||||
|
// Current sector under the heads (used to satisfy RKDS register,
|
||||||
|
// incremented by worker thread, unrelated to sector reads/writes)
|
||||||
|
volatile uint32_t _sectorCount;
|
||||||
|
|
||||||
|
// Status bits
|
||||||
|
volatile bool _wps; // Write Protect status
|
||||||
|
volatile bool _rwsrdy; // Indicates that the drive is ready to accept a new function.
|
||||||
|
volatile bool _dry; // Indicates that the drive is powered, loaded, running, rotating, and not unsafe.
|
||||||
|
volatile bool _sok; // Indicates that the _sectorCount value is not in a state of flux.
|
||||||
|
volatile bool _sin; // Indicates that the seek could not be completed.
|
||||||
|
volatile bool _dru; // Indicates that an unusual condition has occurred in the disk drive and is unsafe.
|
||||||
|
volatile bool _rk05; // Always set, identifies the drive as an RK05
|
||||||
|
volatile bool _dpl; // Set when an attempt to initiate a new function (or a function is in progress) when power is low.
|
||||||
|
|
||||||
|
volatile bool _scp; // Indicates the completion of a seek
|
||||||
|
|
||||||
|
std::string _currentFilePath; // Currently loaded disk image if any
|
||||||
|
|
||||||
|
uint64_t get_disk_byte_offset(
|
||||||
|
uint32_t cylinder,
|
||||||
|
uint32_t surface,
|
||||||
|
uint32_t sector);
|
||||||
|
|
||||||
|
void load_image(std::string path);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Geometry get_geometry(void);
|
||||||
|
uint32_t get_cylinder(void);
|
||||||
|
|
||||||
|
// Status bits
|
||||||
|
uint32_t get_sector_counter(void);
|
||||||
|
bool get_write_protect(void);
|
||||||
|
bool get_rws_ready(void);
|
||||||
|
bool get_drive_ready(void);
|
||||||
|
bool get_sector_counter_ok(void);
|
||||||
|
bool get_seek_incomplete(void);
|
||||||
|
bool get_drive_unsafe(void);
|
||||||
|
bool get_rk05_disk_online(void);
|
||||||
|
bool get_drive_power_low(void);
|
||||||
|
|
||||||
|
// Not a status bit per-se, indicates whether a seek has completed since the last status change.
|
||||||
|
bool get_search_complete(void);
|
||||||
|
|
||||||
|
// Commands
|
||||||
|
void read_sector(uint32_t cylinder, uint32_t surface, uint32_t sector, uint16_t* out_buffer);
|
||||||
|
void write_sector(uint32_t cylinder, uint32_t surface, uint32_t sector, uint16_t* in_buffer);
|
||||||
|
void seek(uint32_t cylinder);
|
||||||
|
void set_write_protect(bool protect);
|
||||||
|
void drive_reset(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
DriveType _drivetype;
|
||||||
|
|
||||||
|
rk05_c(storagecontroller_c *controller);
|
||||||
|
|
||||||
|
void on_power_changed(void) override;
|
||||||
|
|
||||||
|
void on_init_changed(void) override;
|
||||||
|
|
||||||
|
// background worker function
|
||||||
|
void worker(void) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
1066
10.02_devices/2_src/rk11.cpp
Executable file
1066
10.02_devices/2_src/rk11.cpp
Executable file
File diff suppressed because it is too large
Load Diff
167
10.02_devices/2_src/rk11.hpp
Executable file
167
10.02_devices/2_src/rk11.hpp
Executable file
@@ -0,0 +1,167 @@
|
|||||||
|
/* rk11.hpp: RK11 UNIBUS controller
|
||||||
|
|
||||||
|
*/
|
||||||
|
#ifndef _RK11_HPP_
|
||||||
|
#define _RK11_HPP_
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#include "utils.hpp"
|
||||||
|
#include "unibusdevice.hpp"
|
||||||
|
#include "storagecontroller.hpp"
|
||||||
|
#include "rk05.hpp"
|
||||||
|
|
||||||
|
class rk11_c: public storagecontroller_c
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
// RK11 Registers (see Table 1-1 of manual):
|
||||||
|
unibusdevice_register_t *RKDS_reg; // Drive Status Register
|
||||||
|
unibusdevice_register_t *RKER_reg; // Error Register
|
||||||
|
unibusdevice_register_t *RKCS_reg; // Control Status Register
|
||||||
|
unibusdevice_register_t *RKWC_reg; // Word Count Register
|
||||||
|
unibusdevice_register_t *RKBA_reg; // Bus Address Register
|
||||||
|
unibusdevice_register_t *RKDA_reg; // Disk Address Register
|
||||||
|
unibusdevice_register_t *RKDB_reg; // Data Buffer Register
|
||||||
|
|
||||||
|
// Drive Status Register (RKDS) bits (those not belonging to the RK05 drive itself)
|
||||||
|
volatile uint16_t _id; // On interrupt, contains the ID of the interrupting drive (3 bits).
|
||||||
|
|
||||||
|
// Updates the RKDS DATI value based on the above bits
|
||||||
|
void update_RKDS(void);
|
||||||
|
|
||||||
|
// Error Register (RKER) bits
|
||||||
|
bool _wce; // Write Check error
|
||||||
|
bool _cse; // Checksum error
|
||||||
|
bool _nxs; // Nonexistent Sector error
|
||||||
|
bool _nxc; // Nonexistent Cylinder error
|
||||||
|
bool _nxd; // Nonexistent Drive error
|
||||||
|
bool _te; // Timing error
|
||||||
|
bool _dlt; // Data late error
|
||||||
|
bool _nxm; // Nonexistent memory error
|
||||||
|
bool _pge; // Programming Error
|
||||||
|
bool _ske; // Seek error
|
||||||
|
bool _wlo; // Write Lockout Violation
|
||||||
|
bool _ovr; // Overrun
|
||||||
|
bool _dre; // Drive Error
|
||||||
|
|
||||||
|
// Updates the RKER DATI value based on the above bits
|
||||||
|
void update_RKER(void);
|
||||||
|
|
||||||
|
// Control/Status Register (RKCS) bits
|
||||||
|
bool _go; // Causes controller to execute function in _function when set
|
||||||
|
uint16_t _function; // The function to perform (3 bits)
|
||||||
|
uint16_t _mex; // Extended address bits for transfer (2 bits)
|
||||||
|
bool _ide; // Interrupt on done when set
|
||||||
|
bool _rdy; // Whether the controller is ready to process a command
|
||||||
|
bool _sse; // Whether to stop on a soft error
|
||||||
|
bool _exb; // Extra bit (unused, but diags expect it to be R/W)
|
||||||
|
bool _fmt; // Modifies read/write operations to allow formatting / header verification
|
||||||
|
bool _iba; // Inhibits incrementing RKBA
|
||||||
|
bool _scp; // Indicates that the last interrupt was due to a seek or reset function.
|
||||||
|
bool _he; // Indicates when a hard error has occurred.
|
||||||
|
bool _err; // Iindicates when any error has occurred
|
||||||
|
|
||||||
|
// Updates the RKCS DATI value based on above Status bits
|
||||||
|
void update_RKCS(void);
|
||||||
|
|
||||||
|
// Disk Address Register (RKDA) bits
|
||||||
|
volatile uint16_t _rkda_sector;
|
||||||
|
volatile uint16_t _rkda_surface;
|
||||||
|
volatile uint16_t _rkda_cyl;
|
||||||
|
volatile uint16_t _rkda_drive;
|
||||||
|
|
||||||
|
// Updates the RKDA DATI value based on the above bits.
|
||||||
|
void update_RKDA(void);
|
||||||
|
|
||||||
|
struct WorkerCommand
|
||||||
|
{
|
||||||
|
volatile rk05_c* drive;
|
||||||
|
volatile uint32_t address;
|
||||||
|
volatile uint16_t function;
|
||||||
|
volatile bool interrupt;
|
||||||
|
volatile bool stop_on_soft_error;
|
||||||
|
volatile bool format;
|
||||||
|
volatile bool iba;
|
||||||
|
} _new_command;
|
||||||
|
|
||||||
|
struct DMARequest
|
||||||
|
{
|
||||||
|
uint32_t address;
|
||||||
|
uint16_t count;
|
||||||
|
bool write;
|
||||||
|
bool iba;
|
||||||
|
uint16_t *buffer;
|
||||||
|
bool timeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
volatile bool _new_command_ready; // Used in sync. between C/S register updates and worker thread.
|
||||||
|
// If set, causes worker to abandon any current command and
|
||||||
|
// pick up a new one.
|
||||||
|
|
||||||
|
|
||||||
|
// Validates the given disk address, returns true if valid.
|
||||||
|
// Sets the appropriate error flags if invalid (and returns false).
|
||||||
|
bool validate_seek(void);
|
||||||
|
|
||||||
|
// Increments RKDA to point to the next sector
|
||||||
|
void increment_RKDA(void);
|
||||||
|
|
||||||
|
// Causes an interrupt if IDE is set
|
||||||
|
void invoke_interrupt(void);
|
||||||
|
|
||||||
|
// Resets all register values on BUS INIT or Control Reset functions
|
||||||
|
// and any other relevant local state.
|
||||||
|
void reset_controller(void);
|
||||||
|
|
||||||
|
rk05_c* selected_drive(void);
|
||||||
|
|
||||||
|
bool check_drive_ready(void);
|
||||||
|
|
||||||
|
bool check_drive_present(void);
|
||||||
|
|
||||||
|
void dma_transfer(DMARequest &request);
|
||||||
|
|
||||||
|
// Drive functions:
|
||||||
|
enum Function
|
||||||
|
{
|
||||||
|
Control_Reset = 0,
|
||||||
|
Write = 1,
|
||||||
|
Read = 2,
|
||||||
|
Write_Check = 3,
|
||||||
|
Seek = 4,
|
||||||
|
Read_Check = 5,
|
||||||
|
Drive_Reset = 6,
|
||||||
|
Write_Lock = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WorkerState
|
||||||
|
{
|
||||||
|
Worker_Idle = 0,
|
||||||
|
Worker_Execute = 1,
|
||||||
|
Worker_Finish = 2,
|
||||||
|
} _worker_state;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
rk11_c();
|
||||||
|
virtual ~rk11_c();
|
||||||
|
|
||||||
|
// background worker function
|
||||||
|
void worker(void) override;
|
||||||
|
|
||||||
|
// called by unibusadapter on emulated register access
|
||||||
|
void on_after_register_access(
|
||||||
|
unibusdevice_register_t *device_reg,
|
||||||
|
uint8_t unibus_control) override;
|
||||||
|
|
||||||
|
void on_power_changed(void) override;
|
||||||
|
void on_init_changed(void) override;
|
||||||
|
|
||||||
|
void on_drive_status_changed(storagedrive_c* drive);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -88,14 +88,16 @@ OBJECTS = $(OBJDIR)/application.o \
|
|||||||
$(OBJDIR)/cpu.o \
|
$(OBJDIR)/cpu.o \
|
||||||
$(OBJDIR)/ka11.o \
|
$(OBJDIR)/ka11.o \
|
||||||
$(OBJDIR)/rl0102.o \
|
$(OBJDIR)/rl0102.o \
|
||||||
$(OBJDIR)/rl11.o \
|
$(OBJDIR)/rl11.o \
|
||||||
|
$(OBJDIR)/rk11.o \
|
||||||
|
$(OBJDIR)/rk05.o \
|
||||||
$(OBJDIR)/storagedrive.o \
|
$(OBJDIR)/storagedrive.o \
|
||||||
$(OBJDIR)/storagecontroller.o \
|
$(OBJDIR)/storagecontroller.o \
|
||||||
$(OBJDIR)/demo_io.o \
|
$(OBJDIR)/demo_io.o \
|
||||||
$(OBJDIR)/demo_regs.o \
|
$(OBJDIR)/demo_regs.o \
|
||||||
$(OBJDIR)/unibusdevice.o \
|
$(OBJDIR)/unibusdevice.o \
|
||||||
$(OBJDIR)/device.o \
|
$(OBJDIR)/device.o \
|
||||||
$(OBJDIR)/parameter.o \
|
$(OBJDIR)/parameter.o \
|
||||||
$(OBJDIR)/panel.o \
|
$(OBJDIR)/panel.o \
|
||||||
$(OBJDIR)/unibusadapter.o \
|
$(OBJDIR)/unibusadapter.o \
|
||||||
$(OBJDIR)/unibus.o \
|
$(OBJDIR)/unibus.o \
|
||||||
@@ -187,6 +189,12 @@ $(OBJDIR)/rl0102.o : $(DEVICE_SRC_DIR)/rl0102.cpp $(DEVICE_SRC_DIR)/rl0102.hpp
|
|||||||
$(OBJDIR)/rl11.o : $(DEVICE_SRC_DIR)/rl11.cpp $(DEVICE_SRC_DIR)/rl11.hpp
|
$(OBJDIR)/rl11.o : $(DEVICE_SRC_DIR)/rl11.cpp $(DEVICE_SRC_DIR)/rl11.hpp
|
||||||
$(CC) $(CCFLAGS) $< -o $@
|
$(CC) $(CCFLAGS) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/rk05.o : $(DEVICE_SRC_DIR)/rk05.cpp $(DEVICE_SRC_DIR)/rk05.hpp
|
||||||
|
$(CC) $(CCFLAGS) $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/rk11.o : $(DEVICE_SRC_DIR)/rk11.cpp $(DEVICE_SRC_DIR)/rk11.hpp
|
||||||
|
$(CC) $(CCFLAGS) $< -o $@
|
||||||
|
|
||||||
$(OBJDIR)/storagedrive.o : $(BASE_SRC_DIR)/storagedrive.cpp $(BASE_SRC_DIR)/storagedrive.hpp
|
$(OBJDIR)/storagedrive.o : $(BASE_SRC_DIR)/storagedrive.cpp $(BASE_SRC_DIR)/storagedrive.hpp
|
||||||
$(CC) $(CCFLAGS) $< -o $@
|
$(CC) $(CCFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
#include "demo_io.hpp"
|
#include "demo_io.hpp"
|
||||||
#include "demo_regs.hpp"
|
#include "demo_regs.hpp"
|
||||||
#include "rl11.hpp"
|
#include "rl11.hpp"
|
||||||
|
#include "rk11.hpp"
|
||||||
#include "cpu.hpp"
|
#include "cpu.hpp"
|
||||||
|
|
||||||
|
|
||||||
@@ -80,7 +81,10 @@ void menus_c::menu_devices(void) {
|
|||||||
cur_device = NULL;
|
cur_device = NULL;
|
||||||
|
|
||||||
paneldriver->reset(); // reset I2C, restart worker()
|
paneldriver->reset(); // reset I2C, restart worker()
|
||||||
|
|
||||||
|
// create RK11 + drives
|
||||||
|
rk11_c RK05;
|
||||||
|
|
||||||
demo_io.install();
|
demo_io.install();
|
||||||
demo_io.worker_start();
|
demo_io.worker_start();
|
||||||
|
|
||||||
@@ -91,6 +95,9 @@ void menus_c::menu_devices(void) {
|
|||||||
RL11.connect_to_panel();
|
RL11.connect_to_panel();
|
||||||
RL11.worker_start();
|
RL11.worker_start();
|
||||||
|
|
||||||
|
RK05.install();
|
||||||
|
RK05.worker_start();
|
||||||
|
|
||||||
cpu.install();
|
cpu.install();
|
||||||
cpu.worker_start();
|
cpu.worker_start();
|
||||||
|
|
||||||
@@ -330,6 +337,9 @@ void menus_c::menu_devices(void) {
|
|||||||
RL11.disconnect_from_panel();
|
RL11.disconnect_from_panel();
|
||||||
RL11.uninstall();
|
RL11.uninstall();
|
||||||
|
|
||||||
|
RK05.worker_stop();
|
||||||
|
RK05.uninstall();
|
||||||
|
|
||||||
//demo_regs.worker_stop();
|
//demo_regs.worker_stop();
|
||||||
//demo_regs.uninstall();
|
//demo_regs.uninstall();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user