diff --git a/include/apple2.dd.h b/include/apple2.dd.h index f6f563e..b904113 100644 --- a/include/apple2.dd.h +++ b/include/apple2.dd.h @@ -140,6 +140,12 @@ struct apple2dd { vm_segment *image; int image_type; + /* + * This is the means by which we can save the image data back to the + * origin stream, if possible. + */ + FILE *stream; + /* * A disk drive may be "off" or "on", regardless of whether it's * been selected by the peripheral interface. @@ -182,7 +188,10 @@ extern apple2dd *apple2_dd_create(); extern int apple2_dd_insert(apple2dd *, FILE *, int); extern int apple2_dd_position(apple2dd *); extern vm_8bit apple2_dd_read(apple2dd *); +extern vm_8bit apple2_dd_switch_rw(apple2dd *); extern void apple2_dd_eject(apple2dd *); +extern void apple2_dd_encode(apple2dd *); +extern void apple2_dd_decode(apple2dd *); extern void apple2_dd_free(apple2dd *); extern void apple2_dd_map(vm_segment *); extern void apple2_dd_set_mode(apple2dd *, int); @@ -191,7 +200,6 @@ extern void apple2_dd_step(apple2dd *, int); extern void apple2_dd_switch_drive(apple2 *, size_t); extern void apple2_dd_switch_latch(apple2dd *, vm_8bit); extern void apple2_dd_switch_phase(apple2dd *, size_t); -extern vm_8bit apple2_dd_switch_rw(apple2dd *); extern void apple2_dd_turn_on(apple2dd *, bool); extern void apple2_dd_write(apple2dd *); extern void apple2_dd_write_protect(apple2dd *, bool); diff --git a/include/apple2.enc.h b/include/apple2.enc.h index 6f8068b..a33ff9c 100644 --- a/include/apple2.enc.h +++ b/include/apple2.enc.h @@ -64,5 +64,6 @@ extern int apple2_enc_sector(vm_segment *, vm_segment *, int, int); extern int apple2_enc_sector_header(vm_segment *, int, int, int); extern int apple2_enc_track(vm_segment *, vm_segment *, int, int); extern vm_segment *apple2_enc_dos(vm_segment *); +extern vm_segment *apple2_enc_nib(vm_segment *); #endif diff --git a/include/vm_segment.h b/include/vm_segment.h index 481ff77..ecbf0a9 100644 --- a/include/vm_segment.h +++ b/include/vm_segment.h @@ -62,6 +62,7 @@ struct vm_segment { extern int vm_segment_copy(vm_segment *, vm_segment *, size_t, size_t, size_t); extern int vm_segment_copy_buf(vm_segment *, const vm_8bit *, size_t, size_t, size_t); extern int vm_segment_fread(vm_segment *, FILE *, size_t, size_t); +extern int vm_segment_fwrite(vm_segment *, FILE *, size_t, size_t); extern int vm_segment_read_map(vm_segment *, size_t, vm_segment_read_fn); extern int vm_segment_set(vm_segment *, size_t, vm_8bit); extern int vm_segment_set16(vm_segment *, size_t, vm_16bit); diff --git a/src/apple2.dd.c b/src/apple2.dd.c index 3605449..1e3b1c4 100644 --- a/src/apple2.dd.c +++ b/src/apple2.dd.c @@ -2,8 +2,10 @@ * apple2.disk_drive.c */ -#include "apple2.h" #include "apple2.dd.h" +#include "apple2.dec.h" +#include "apple2.enc.h" +#include "apple2.h" /* * Create a new disk drive. We do not create a memory segment for the @@ -70,21 +72,77 @@ apple2_dd_insert(apple2dd *drive, FILE *stream, int type) // If we have any data, get rid of it. We'll start fresh here. apple2_dd_eject(drive); - drive->data = vm_segment_create(finfo.st_size); + drive->image = vm_segment_create(finfo.st_size); drive->track_pos = 0; drive->sector_pos = 0; // Read the data from the stream and write into the memory segment - err = vm_segment_fread(drive->data, stream, 0, finfo.st_size); + err = vm_segment_fread(drive->image, stream, 0, finfo.st_size); if (err != OK) { log_critical("Could not read data into disk drive"); return err; } + drive->stream = stream; drive->image_type = type; + + // Now we need to build the data segment + apple2_dd_encode(drive); + return OK; } +void +apple2_dd_encode(apple2dd *drive) +{ + switch (drive->image_type) { + case DD_NIBBLE: + drive->data = apple2_enc_nib(drive->image); + break; + + case DD_DOS33: + case DD_PRODOS: + drive->data = apple2_enc_dos(drive->image); + break; + + default: + log_critical("Unknown image type"); + exit(1); + } +} + +void +apple2_dd_save(apple2dd *drive) +{ + // First bring the image segment back into sync with with the data + // segment. + apple2_dd_decode(drive); + + if (drive->stream) { + rewind(drive->stream); + vm_segment_fwrite(drive->image, drive->stream, 0, drive->image->size); + } +} + +void +apple2_dd_decode(apple2dd *drive) +{ + switch (drive->image_type) { + case DD_NIBBLE: + apple2_dec_nib(drive->image, drive->data); + break; + + case DD_DOS33: + case DD_PRODOS: + apple2_dec_dos(drive->image, drive->data); + break; + + default: + log_critical("Unknown image type"); + exit(1); + } +} + /* * Evaluate the value of the phase_state against the last known phase, * and decide from there whether we should step forward or backward by a @@ -177,8 +235,13 @@ void apple2_dd_eject(apple2dd *drive) { if (drive->data) { + // Save off anything else we have left + apple2_dd_save(drive); + vm_segment_free(drive->data); + vm_segment_free(drive->image); drive->data = NULL; + drive->image = NULL; } drive->track_pos = 0; diff --git a/src/vm_segment.c b/src/vm_segment.c index b77ef47..19557de 100644 --- a/src/vm_segment.c +++ b/src/vm_segment.c @@ -176,7 +176,7 @@ vm_segment_copy(vm_segment *dest, size_t src_index, size_t length) { - if (src_index + length >= src->size) { + if (src_index + length > src->size) { log_critical( "Attempt to copy beyond bounds of vm_segment (%d + %d >= %d)", src_index, @@ -186,7 +186,7 @@ vm_segment_copy(vm_segment *dest, return ERR_OOB; } - if (dest_index + length >= dest->size) { + if (dest_index + length > dest->size) { log_critical( "Attempt to copy beyond bounds of vm_segment (%d + %d >= %d)", dest_index, @@ -286,6 +286,19 @@ vm_segment_fread(vm_segment *segment, FILE *stream, size_t offset, size_t len) return OK; } +int +vm_segment_fwrite(vm_segment *seg, FILE *stream, size_t off, size_t len) +{ + fwrite(seg->memory + off, sizeof(vm_8bit), len, stream); + + if (ferror(stream)) { + log_critical("Could not write to the file stream: %s", strerror(errno)); + return ERR_BADFILE; + } + + return OK; +} + /* * Change the internal notion of the machine used by map functions */