reinette-IIe/disk.cpp

130 lines
5.6 KiB
C++

/*
* reinette, a french Apple II emulator, using SDL2
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
* Last modified 1st of July 2021
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include "reinette.h"
Disk::Disk() {
curDrv = 0; // Current Drive - only one can be enabled at a time
// TODO : initialize the unit[x] structs
}
int Disk::load( char *path, int drive) {
FILE *f = fopen(path, "rb"); // open file in read binary mode
if (!f || fread(unit[drive].data, 1, 232960, f) != 232960) // load it into memory and check size
return 0;
fclose(f);
sprintf(unit[drive].pathName, "%s", path); // update floppy image pathName record
// get filename
int i =0, a = 0;
while (unit[drive].pathName[i] != 0) { // find start of filename for disk0
if (unit[drive].pathName[i] == '/' || unit[drive].pathName[i] == '\\')
a = i + 1;
i++;
}
sprintf(unit[drive].fileName, "%s", unit[drive].pathName + a);
// is the file read only ?
f = fopen(path, "ab"); // try to open the file in append binary mode
if (f) { // success, file is writable
unit[drive].readOnly = false; // update the readOnly flag
fclose(f); // and close it untouched
} else {
unit[drive].readOnly = true; // f is NULL, no writable, no need to close it
}
return 1;
}
int Disk::save(int drive) {
if (!unit[drive].pathName[0]) return 0; // no file loaded into drive
if (unit[drive].readOnly) return 0; // file is read only write no aptempted
FILE *f = fopen(unit[drive].pathName, "wb");
if (!f) return 0; // could not open the file in write overide binary
if (fwrite(unit[drive].data, 1, 232960, f) != 232960) { // failed to write the full file (hdd full ?)
fclose(f); // release the ressource
return 0;
}
fclose(f); // success, release the ressource
return 1;
}
int Disk::eject(int drive) {
unit[drive].fileName[0] = 0;
unit[drive].pathName[0] = 0;
unit[drive].readOnly = false;
for (int i=0; i<232960; i++) // erase data
unit[drive].data[i]=0;
return 1;
}
void Disk::stepMotor(uint16_t address) {
static bool phases[2][4] = { 0 }; // phases states (for both drives)
static bool phasesB[2][4] = { 0 }; // phases states Before
static bool phasesBB[2][4] = { 0 }; // phases states Before Before
static int pIdx[2] = { 0 }; // phase index (for both drives)
static int pIdxB[2] = { 0 }; // phase index Before
static int halfTrackPos[2] = { 0 };
address &= 7;
int phase = address >> 1;
phasesBB[curDrv][pIdxB[curDrv]] = phasesB[curDrv][pIdxB[curDrv]];
phasesB[curDrv][pIdx[curDrv]] = phases[curDrv][pIdx[curDrv]];
pIdxB[curDrv] = pIdx[curDrv];
pIdx[curDrv] = phase;
if (!(address & 1)) { // head not moving (PHASE x OFF)
phases[curDrv][phase] = false;
return;
}
if ((phasesBB[curDrv][(phase + 1) & 3]) && (--halfTrackPos[curDrv] < 0)) // head is moving in
halfTrackPos[curDrv] = 0;
if ((phasesBB[curDrv][(phase - 1) & 3]) && (++halfTrackPos[curDrv] > 140)) // head is moving out
halfTrackPos[curDrv] = 140;
phases[curDrv][phase] = true; // update track#
unit[curDrv].track = (halfTrackPos[curDrv] + 1) / 2;
}
void Disk::setDrv(int drv) {
unit[drv].motorOn = unit[!drv].motorOn || unit[drv].motorOn; // if any of the motors were ON
unit[!drv].motorOn = false; // motor of the other drive is set to OFF
curDrv = drv; // set the current drive
}