diff --git a/src/apple2.disk_drive.c b/src/apple2.disk_drive.c index ebd53d8..16c3348 100644 --- a/src/apple2.disk_drive.c +++ b/src/apple2.disk_drive.c @@ -4,12 +4,32 @@ #include "apple2.disk_drive.h" -apple2_disk_drive * -apple2_disk_drive_create() -{ - apple2_disk_drive *drive; +/* + * This is the length of a typical disk that is formatted in either DOS + * 3.3 or ProDOS. + */ +#define _140K_ 143360 - drive = malloc(sizeof(apple2_disk_drive)); +/* + * 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() +{ + apple2dd *drive; + + drive = malloc(sizeof(apple2dd)); if (drive == NULL) { log_critical("Could not malloc space for apple2 disk drive"); return NULL; @@ -21,6 +41,7 @@ apple2_disk_drive_create() drive->data = NULL; drive->track_pos = 0; + drive->sector_pos = 0; drive->online = false; drive->write_protect = true; drive->mode = DD_READ; @@ -29,7 +50,7 @@ apple2_disk_drive_create() } void -apple2_disk_drive_free(apple2_disk_drive *drive) +apple2dd_free(apple2dd *drive) { if (drive->data) { vm_segment_free(drive->data); @@ -39,7 +60,7 @@ apple2_disk_drive_free(apple2_disk_drive *drive) } void -apple2_disk_drive_step(apple2_disk_drive *drive, int steps) +apple2dd_step(apple2dd *drive, int steps) { drive->track_pos += steps; @@ -51,7 +72,7 @@ apple2_disk_drive_step(apple2_disk_drive *drive, int steps) } void -apple2_disk_drive_set_mode(apple2_disk_drive *drive, int mode) +apple2dd_set_mode(apple2dd *drive, int mode) { if (mode != DD_READ && mode != DD_WRITE) { return; @@ -61,13 +82,54 @@ apple2_disk_drive_set_mode(apple2_disk_drive *drive, int mode) } void -apple2_disk_drive_turn_on(apple2_disk_drive *drive, bool online) +apple2dd_turn_on(apple2dd *drive, bool online) { drive->online = online; } void -apple2_disk_drive_write_protect(apple2_disk_drive *drive, bool protect) +apple2dd_write_protect(apple2dd *drive, bool protect) { drive->write_protect = protect; } + +static int +position(apple2dd *drive) +{ + if (drive->data->size == _140K_) { + int track_offset; + + track_offset = (drive->track_pos % 2) * 4096; + return track_offset + drive->sector_pos; + } + + return 0; +} + +vm_8bit +apple2dd_read_byte(apple2dd *drive) +{ + vm_8bit byte = vm_segment_get(drive->data, position(drive)); + + // We may have read the very last byte in a sector; if so let's + // adjust the track_pos by two half tracks and reset the sector pos. + drive->sector_pos++; + if (drive->sector_pos > MAX_SECTOR_POS) { + drive->track_pos += 2; + drive->sector_pos = 0; + } + + return byte; +} + +void +apple2dd_write(apple2dd *drive, vm_8bit byte) +{ + vm_segment_set(drive->data, position(drive), byte); + + drive->sector_pos++; + if (drive->sector_pos > MAX_SECTOR_POS) { + drive->track_pos += 2; + drive->sector_pos = 0; + } +}