Superdrive: support for inserting of virtual disks.

This commit is contained in:
Maxim Poliakovski 2022-02-06 21:23:20 +01:00
parent 5e2f2b12e4
commit b9fbd9b7c9
4 changed files with 168 additions and 37 deletions

View File

@ -86,8 +86,9 @@ RawFloppyImg::RawFloppyImg(std::string& file_path) : FloppyImgConverter()
/** For raw images, we're going to ensure that the data fits into
one of the supported floppy disk sizes as well as image size
matches the size of the embedded HFS/MFS volume.
Then we'll attempt to guess disk format based on image size.
*/
int RawFloppyImg::validate()
int RawFloppyImg::calc_phys_params()
{
std::ifstream img_file;
@ -141,22 +142,60 @@ int RawFloppyImg::validate()
return -1;
}
// raw images don't include anything than raw disk data
this->data_size = this->img_size;
// guess disk format from image file size
static struct {
int capacity;
int rec_method;
int num_tracks;
int num_sectors;
int num_sides;
int density;
} size_to_params[] = {
{ 409600, 0, 80, 800, 1, 0}, // 400K GCR
{ 819200, 0, 80, 800, 2, 0}, // 800K GCR
{ 737280, 1, 80, 1440, 2, 0}, // 720K MFM
{1474560, 1, 80, 2880, 2, 1}, // 1440K MFM
};
this->rec_method = -1;
for (int i = 0; i < 4; i++) {
if (this->img_size == size_to_params[i].capacity) {
this->rec_method = size_to_params[i].rec_method;
this->num_tracks = size_to_params[i].num_tracks;
this->num_sectors = size_to_params[i].num_sectors;
this->num_sides = size_to_params[i].num_sides;
this->density = size_to_params[i].density;
}
}
if (this->rec_method == -1) {
LOG_F(ERROR, "RawFloppyImg: could't determine disk format from image size!");
return -1;
}
return 0;
}
/** Guess physical parameters of the target virtual disk based on image size. */
int RawFloppyImg::get_phys_params()
/** Retrieve raw disk data. */
int RawFloppyImg::get_raw_disk_data(char* buf)
{
// disk format: GCR vs MFM
// single-sided vs double-sided
// number of tracks
// number of sectors
return 0;
}
std::ifstream img_file;
img_file.open(img_path, std::ios::in | std::ios::binary);
if (img_file.fail()) {
img_file.close();
LOG_F(ERROR, "RawFloppyImg: Could not open specified floppy image!");
return -1;
}
img_file.seekg(0, img_file.beg);
img_file.read(buf, this->data_size);
img_file.close();
/** Convert high-level image data to low-level disk data. */
int RawFloppyImg::import_data()
{
return 0;
}
@ -166,7 +205,7 @@ int RawFloppyImg::export_data()
return 0;
}
int open_floppy_image(std::string& img_path)
FloppyImgConverter* open_floppy_image(std::string& img_path)
{
FloppyImgConverter *fconv;
@ -176,7 +215,7 @@ int open_floppy_image(std::string& img_path)
if (img_file.fail()) {
img_file.close();
LOG_F(ERROR, "Could not open specified floppy image!");
return -1;
return nullptr;
}
FlopImgType itype = identify_image(img_file);
@ -197,13 +236,13 @@ int open_floppy_image(std::string& img_path)
break;
default:
LOG_F(ERROR, "Unknown/unsupported image format!");
return -1;
return nullptr;
}
if (fconv->validate()) {
LOG_F(ERROR, "Image validation failed!");
return -1;
if (fconv->calc_phys_params()) {
delete fconv;
return nullptr;
}
return 0;
return fconv;
}

View File

@ -44,12 +44,29 @@ enum class FlopImgType {
class FloppyImgConverter {
public:
FloppyImgConverter() = default;
~FloppyImgConverter() = default;
virtual ~FloppyImgConverter() = default;
virtual int validate(void) = 0;
virtual int get_phys_params(void) = 0;
virtual int import_data(void) = 0;
virtual int calc_phys_params(void) = 0;
virtual int get_raw_disk_data(char* buf) = 0;
virtual int export_data(void) = 0;
int get_data_size() { return this->data_size; };
int get_disk_rec_method() { return this->rec_method; };
int get_number_of_tracks() { return this->num_tracks; };
int get_number_of_sides() { return this->num_sides; };
int get_sectors_per_side() { return this->num_sectors; };
int get_rec_density() { return this->density; };
protected:
std::string img_path;
int img_size;
int data_size; // disk data size without image format specific stuff
int rec_method;
int num_tracks;
int num_sides;
int num_sectors;
int density;
};
/** Converter for raw floppy images. */
@ -58,16 +75,11 @@ public:
RawFloppyImg(std::string& file_path);
~RawFloppyImg() = default;
int validate(void);
int get_phys_params(void);
int import_data(void);
int calc_phys_params(void);
int get_raw_disk_data(char* buf);
int export_data(void);
private:
std::string img_path;
int img_size;
};
extern int open_floppy_image(std::string& img_path);
extern FloppyImgConverter* open_floppy_image(std::string& img_path);
#endif // FLOPPY_IMG_H

View File

@ -26,6 +26,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <loguru.hpp>
#include <cinttypes>
#include <memory>
using namespace MacSuperdrive;
@ -69,7 +70,7 @@ uint8_t MacSuperDrive::status(uint8_t addr)
case StatusAddr::Disk_In_Drive:
return this->has_disk ^ 1; // reverse logic (active low)!
case StatusAddr::Media_Kind:
return this->media_kind;
return this->media_kind ^ 1; // reverse logic!
default:
LOG_F(WARNING, "Superdrive: unimplemented status request, addr=0x%X", addr);
return 0;
@ -78,8 +79,64 @@ uint8_t MacSuperDrive::status(uint8_t addr)
int MacSuperDrive::insert_disk(std::string& img_path)
{
//open_floppy_image(img_path.c_str());
open_floppy_image(img_path);
if (this->has_disk) {
LOG_F(ERROR, "Superdrive: drive is not empty!");
return -1;
}
FloppyImgConverter* img_conv = open_floppy_image(img_path);
if (img_conv != nullptr) {
this->img_conv = std::unique_ptr<FloppyImgConverter>(img_conv);
set_disk_phys_params();
// allocate memory for raw disk data
this->disk_data = std::unique_ptr<char[]>(new char[this->img_conv->get_data_size()]);
// swallow all raw disk data at once!
this->img_conv->get_raw_disk_data(this->disk_data.get());
// everything is set up, let's say we got a disk
this->has_disk = 1;
} else {
this->has_disk = 0;
}
return 0;
}
void MacSuperDrive::set_disk_phys_params()
{
this->rec_method = this->img_conv->get_disk_rec_method();
this->num_tracks = this->img_conv->get_number_of_tracks();
this->num_sides = this->img_conv->get_number_of_sides();
this->media_kind = this->img_conv->get_rec_density();
if (rec_method == RecMethod::GCR) {
// Apple GCR speeds per group of 16 tracks
static int gcr_rpm_per_group[5] = {394, 429, 472, 525, 590};
// initialize three lookup tables:
// sectors per track
// rpm per track
// logical block number of the first sector in each track
// for easier navigation
for (int grp = 0, blk_num = 0; grp < 5; grp++) {
for (int trk = 0; trk < 16; trk++) {
this->sectors_per_track[grp * 16 + trk] = 12 - grp;
this->rpm_per_track[grp * 16 + trk] = gcr_rpm_per_group[grp];
this->track_start_block[grp * 16 + trk] = blk_num;
blk_num += 12 - grp;
}
}
} else {
int sectors_per_track = this->media_kind ? 18 : 9;
// MFM disks use constant number of sectors per track
// and the fixed rotational speed of 300 RPM
for (int trk = 0; trk < 80; trk++) {
this->sectors_per_track[trk] = sectors_per_track;
this->rpm_per_track[trk] = 300;
this->track_start_block[trk] = trk * sectors_per_track;
}
}
}

View File

@ -25,8 +25,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#define MAC_SUPERDRIVE_H
#include <devices/common/hwcomponent.h>
#include <devices/floppy/floppyimg.h>
#include <cinttypes>
#include <memory>
#include <string>
namespace MacSuperdrive {
@ -47,8 +49,14 @@ enum CommandAddr : uint8_t {
/** Type of media currently in the drive. */
enum MediaKind : uint8_t {
high_density = 0, // 1 or 2 MB disk
low_density = 1
low_density = 0,
high_density = 1, // 1 or 2 MB disk
};
/** Disk recording method. */
enum RecMethod : int {
GCR = 0,
MFM = 1
};
class MacSuperDrive : public HWComponent {
@ -60,9 +68,24 @@ public:
uint8_t status(uint8_t addr);
int insert_disk(std::string& img_path);
protected:
void set_disk_phys_params();
private:
uint8_t media_kind;
uint8_t has_disk;
// physical parameters of the currently inserted disk
uint8_t media_kind;
int rec_method;
int num_tracks;
int num_sides;
int sectors_per_track[80];
int rpm_per_track[80];
int track_start_block[80]; // logical block number of the first sector in a track
std::unique_ptr<FloppyImgConverter> img_conv;
std::unique_ptr<char[]> disk_data;
};
}; // namespace MacSuperdrive