1
0
mirror of https://github.com/pevans/erc-c.git synced 2024-12-21 23:29:16 +00:00
erc-c/src/apple2.dd.c

188 lines
4.0 KiB
C
Raw Normal View History

2017-12-14 02:30:32 +00:00
/*
* apple2.disk_drive.c
*/
2017-12-15 04:27:45 +00:00
#include "apple2.dd.h"
2017-12-14 02:30:32 +00:00
/*
* This is the length of a typical disk that is formatted in either DOS
* 3.3 or ProDOS.
*/
#define _140K_ 143360
/*
* And this is the length of a disk that has been formatted as a nibble
* file (*.NIB). This is not an Apple thing, exactly; it's more of an
* emulator thing, that emulators had used to try and get around copy
* protection in emulation. It does complicate disk drive operation!
*/
#define _240K_ 245760
/*
* This is the last _accessible_ sector position within a track (you can
* have 0 - 4095).
*/
#define MAX_SECTOR_POS 4095
apple2dd *
apple2dd_create()
2017-12-14 02:30:32 +00:00
{
apple2dd *drive;
2017-12-14 02:30:32 +00:00
drive = malloc(sizeof(apple2dd));
2017-12-14 02:30:32 +00:00
if (drive == NULL) {
log_critical("Could not malloc space for apple2 disk drive");
return NULL;
}
// To begin with, we have no segment for data; that's something that
// will depend on the disk you insert. For example, a DOS 3.3 or
// ProDOS disk will have 140k, but a NIB file would have more.
drive->data = NULL;
drive->track_pos = 0;
drive->sector_pos = 0;
2017-12-14 02:30:32 +00:00
drive->online = false;
drive->write_protect = true;
drive->mode = DD_READ;
return drive;
}
void
apple2dd_free(apple2dd *drive)
2017-12-14 02:30:32 +00:00
{
if (drive->data) {
vm_segment_free(drive->data);
}
free(drive);
}
int
apple2dd_insert(apple2dd *drive, FILE *stream)
{
struct stat finfo;
if (stream == NULL) {
log_critical("File stream is null");
return ERR_BADFILE;
}
// How large is this data set? Let's get the stat info.
if (fstat(fileno(stream), &finfo)) {
log_critical("Couldn't inspect file stream: %s", strerror(errno));
return ERR_BADFILE;
}
if (finfo.st_size != _140K_) {
log_critical("Unexpected file format (file size = %d)", finfo.st_size);
return ERR_BADFILE;
}
// If we have any data, get rid of it. We'll start fresh here.
apple2dd_eject(drive);
drive->data = vm_segment_create(finfo.st_size);
drive->track_pos = 0;
drive->sector_pos = 0;
return OK;
}
void
apple2dd_eject(apple2dd *drive)
{
if (drive->data) {
vm_segment_free(drive->data);
drive->data = NULL;
}
}
2017-12-14 02:30:32 +00:00
void
apple2dd_step(apple2dd *drive, int steps)
2017-12-14 02:30:32 +00:00
{
drive->track_pos += steps;
if (drive->track_pos > MAX_DRIVE_STEPS) {
drive->track_pos = MAX_DRIVE_STEPS;
} else if (drive->track_pos < 0) {
drive->track_pos = 0;
2017-12-14 02:30:32 +00:00
}
}
void
apple2dd_set_mode(apple2dd *drive, int mode)
2017-12-14 02:30:32 +00:00
{
if (mode != DD_READ && mode != DD_WRITE) {
return;
}
drive->mode = mode;
}
void
apple2dd_turn_on(apple2dd *drive, bool online)
2017-12-14 02:30:32 +00:00
{
drive->online = online;
}
void
apple2dd_write_protect(apple2dd *drive, bool protect)
2017-12-14 02:30:32 +00:00
{
drive->write_protect = protect;
}
int
apple2dd_position(apple2dd *drive)
{
// Special case: they didn't load any image data into the "drive".
// Return zero.
if (drive->data == NULL) {
return 0;
}
// This is a normative DOS 3.3 / ProDOS disk. (Except ProDOS is
// separated into 512 byte blocks which _shouldn't_ matter for our
// purposes but let's not talk about that here do-de-doo.)
if (drive->data->size == _140K_) {
int track_offset;
track_offset = (drive->track_pos % 2) * 4096;
return track_offset + drive->sector_pos;
}
return 0;
}
void
apple2dd_shift(apple2dd *drive, int pos)
{
drive->sector_pos += pos;
if (drive->sector_pos > MAX_SECTOR_POS) {
// We need to reset the sector pos to zero, because...
drive->sector_pos = 0;
// We also need to move to the next track, so let's adjust by
// two half-tracks.
apple2dd_step(drive, 2);
}
}
vm_8bit
apple2dd_read_byte(apple2dd *drive)
{
vm_8bit byte = vm_segment_get(drive->data, apple2dd_position(drive));
apple2dd_shift(drive, 1);
return byte;
}
void
apple2dd_write(apple2dd *drive, vm_8bit byte)
{
vm_segment_set(drive->data, apple2dd_position(drive), byte);
apple2dd_shift(drive, 1);
}