/*************************************************************************** Copyright Olivier Galibert All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name 'MAME' nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************/ /* DONE: * Support auto-identification heuristics for determining disk image speed, capture clock rate, and number of multireads per image. * TODO: * Scale captured data based on the guessed clock rate and samplerate to match the internal 200mhz representation * Handle 0xFF bytes properly * Correctly note exact index timing. */ #include "emu.h" #include "dfi_dsk.h" #include #define NUMBER_OF_MULTIREADS 3 // threshholds for brickwall windowing //define MIN_CLOCKS 65 // number_please apple2 wants 40 min #define MIN_CLOCKS 60 //define MAX_CLOCKS 260 #define MAX_CLOCKS 270 #define MIN_THRESH (MIN_CLOCKS*(clock_rate/25000000)) #define MAX_THRESH (MAX_CLOCKS*(clock_rate/25000000)) // constants to help guess clockrate and rpm // constant is 25mhz / 6 revolutions per second (360rpm) = 4166667 +- 2.5% #define REV25_MIN 4062500 #define REV25_MAX 4270833 // define the following to show a histogram per track //define TRACK_HISTOGRAM 1 #undef TRACK_HISTOGRAM dfi_format::dfi_format() : floppy_image_format_t() { } const char *dfi_format::name() const { return "dfi"; } const char *dfi_format::description() const { return "DiscFerret flux dump format"; } const char *dfi_format::extensions() const { return "dfi"; } bool dfi_format::supports_save() const { return false; } int dfi_format::identify(io_generic *io, UINT32 form_factor) { char sign[4]; io_generic_read(io, sign, 0, 4); if (memcmp(sign, "DFER", 4)==0) fatalerror("Old type Discferret image detected; the mess Discferret decoder will not handle this properly, bailing out!\n"); return memcmp(sign, "DFE2", 4) ? 0 : 100; } bool dfi_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) { int size = io_generic_size(io); int pos = 4; UINT8 *data = 0; int data_size = 0; // size of currently allocated array for a track int onerev_time = 0; // time for one revolution, used to guess clock and rpm for DFE2 files unsigned long clock_rate = 100000000; // sample clock rate in megahertz int rpm=360; // drive rpm while(pos < size) { UINT8 h[10]; io_generic_read(io, h, pos, 10); UINT16 track = (h[0] << 8) | h[1]; UINT16 head = (h[2] << 8) | h[3]; // Ignore sector UINT32 tsize = (h[6] << 24) | (h[7] << 16) | (h[8] << 8) | h[9]; // if the position-so-far-in-file plus 10 (for the header) plus track size // is larger than the size of the file, free buffers and bail out if(pos+tsize+10 > size) { if(data) global_free(data); return false; } // reallocate the data array if it gets too small if(tsize > data_size) { if(data) global_free(data); data_size = tsize; data = global_alloc_array(UINT8, data_size); } pos += 10; // skip the header, we already read it io_generic_read(io, data, pos, tsize); pos += tsize; // for next time we read, increment to the beginning of next header int index_time = 0; // what point the last index happened int index_count = 0; // number of index pulses per track //int index_polarity = 1; // current polarity of index, starts high int total_time = 0; // total sampled time per track for(int i=0; i REV25_MIN) && (onerev_time < REV25_MAX)) { fprintf(stderr, "Guess: speed: 360rpm, clock 25MHz\n"); clock_rate = 25000000; rpm = 360; } else if ((onerev_time > REV25_MIN*1.2) && (onerev_time < REV25_MAX*1.2)) { fprintf(stderr, "Guess: speed: 300rpm, clock 25MHz\n"); clock_rate = 25000000; rpm = 300; } else if ((onerev_time > REV25_MIN*2) && (onerev_time < REV25_MAX*2)) { fprintf(stderr, "Guess: speed: 360rpm, clock 50MHz\n"); clock_rate = 50000000; rpm = 360; } else if ((onerev_time > (REV25_MIN*2)*1.2) && (onerev_time < (REV25_MAX*2)*1.2)) { fprintf(stderr, "Guess: speed: 300rpm, clock 50MHz\n"); clock_rate = 50000000; rpm = 300; } else if ((onerev_time > REV25_MIN*4) && (onerev_time < REV25_MAX*4)) { fprintf(stderr, "Guess: speed: 360rpm, clock 100MHz\n"); clock_rate = 100000000; rpm = 360; } else if ((onerev_time > (REV25_MIN*4)*1.2) && (onerev_time < (REV25_MAX*4)*1.2)) { fprintf(stderr, "Guess: speed: 300rpm, clock 100MHz\n"); clock_rate = 100000000; rpm = 300; } else fprintf(stderr, "WARNING: Cannot Guess Speed! Assuming 360rpm, 100Mhz clock!\n"); fprintf(stderr,"Actual rpm based on index: %f\n", ((double)clock_rate/(double)onerev_time)*60); } rpm += 0; // HACK: prevent GCC 4.6+ from warning "variable set but unused" if(!index_time) index_time = total_time; image->set_track_size(track, head, tsize); int cur_time = 0; int prev_time = 0; #ifdef TRACK_HISTOGRAM // histogram int time_buckets[4096]; for (int i = 0; i < 4096; i++) time_buckets[i] = 0; #endif index_count = 0; //index_polarity = 0; UINT32 mg = floppy_image::MG_A; UINT32 *buf = image->get_buffer(track, head); int tpos = 0; buf[tpos++] = mg; for(int i=0; i MIN_THRESH) && (trans_time <= MAX_THRESH))) { mg = mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; buf[tpos++] = mg | UINT32((200000000ULL*cur_time)/index_time); prev_time = cur_time; } // the long case: we probably missed a transition, stuff an extra guessed one in there to see if it helps if (trans_time > MAX_THRESH) { mg = mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; if (((track%2)==0)&&(head==0)) fprintf(stderr,"missed transition, total time for transition is %d\n",trans_time); #ifndef FAKETRANS_ONE buf[tpos++] = mg | UINT32((200000000ULL*(cur_time-(trans_time/2)))/index_time); // generate imaginary transition at half period #else buf[tpos++] = mg | UINT32((200000000ULL*(cur_time-((trans_time*2)/3)))/index_time); mg = mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; buf[tpos++] = mg | UINT32((200000000ULL*(cur_time-(trans_time/3)))/index_time); #endif mg = mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; buf[tpos++] = mg | UINT32(200000000ULL*cur_time/index_time); // generate transition now prev_time = cur_time; } } } #ifdef TRACK_HISTOGRAM if (((track%2)==0)&&(head==0)) { for (int i = 0; i < 4096; i++) { fprintf(stderr,"%4d:%4d ", i, time_buckets[i]); if (((i+1)%10)==0) fprintf(stderr,"\n"); } } fprintf(stderr,"\n"); #endif index_count = 0; image->set_track_size(track, head, tpos); } if(data) global_free(data); return true; } const floppy_format_type FLOPPY_DFI_FORMAT = &floppy_image_format_creator;