summaryrefslogblamecommitdiffstatshomepage
path: root/src/lib/formats/g64_dsk.c
blob: 5beba1ca35f6ae149569191bb07ec91c8e5ee72d (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                       
                               



                                                                      
                                             
 

                                                       




                                                                      
                                      




                        
                                            








                                                            
                  
 

                                               






                                                                              
                                          
                                 

                                          

                                                                                         

         
                                           
                     



                                                                                          
 





                                                                                                                    
                                                                                      





                                                                                                                
 


                                                                                                     






                                               


                                                                                                                              
 
                                                                                           
 





                                                                                                            
                                                          
 
                                                                                                                        
 
                                                                
 

                               
 
                                                



                                                                         
 

                                                           
 

                                                            
 
                               
                               
 





                                                                                                                                    
 
                                                                                                          
 


                                      
 


                                                                   
 




                                                                      
 
                                 
         
 
                    

 
                                    
 
                     

 
                                           
 
                                               

 
                                          
 
                         

 
                                                                                      
// license:BSD-3-Clause
// copyright-holders:Curt Coder
/*********************************************************************

    formats/g64_dsk.c

    Commodore 1541/1571 GCR disk image format

    http://unusedino.de/ec64/technical/formats/g64.html

*********************************************************************/

#include "emu.h"
#include "formats/g64_dsk.h"

#define G64_FORMAT_HEADER   "GCR-1541"

g64_format::g64_format()
{
}

const UINT32 g64_format::c1541_cell_size[] =
{
	4000, // 16MHz/16/4
	3750, // 16MHz/15/4
	3500, // 16MHz/14/4
	3250  // 16MHz/13/4
};

int g64_format::identify(io_generic *io, UINT32 form_factor)
{
	char h[8];

	io_generic_read(io, h, 0, 8);
	if (!memcmp(h, G64_FORMAT_HEADER, 8)) {
		return 100;
	}
	return 0;
}

bool g64_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
{
	UINT64 size = io_generic_size(io);
	dynamic_buffer img(size);
	io_generic_read(io, img, 0, size);

	if (img[VERSION]) {
		throw emu_fatalerror("g64_format: Unsupported version %u", img[VERSION]);
	}

	int track_count = img[TRACK_COUNT];
	int head = 0;

	for (int track = 0; track < track_count; track++)
	{
		offs_t track_offset = pick_integer_le(img, TRACK_OFFSET + (track * 4), 4);

		if (!track_offset)
			continue;

		if (track_offset > size)
			throw emu_fatalerror("g64_format: Track %u offset %06x out of bounds", track, track_offset);

		offs_t speed_zone = pick_integer_le(img, SPEED_ZONE + (track * 4), 4);

		if (speed_zone > 3)
			throw emu_fatalerror("g64_format: Unsupported variable speed zones on track %d", track);

		UINT16 track_bytes = pick_integer_le(img, track_offset, 2);
		int track_size = track_bytes * 8;

		LOG_FORMATS("track %u size %u cell %ld\n", track, track_size, 200000000L/track_size);

		generate_track_from_bitstream(track, head, &img[track_offset+2], track_size, image);
	}

	image->set_variant(floppy_image::SSSD);

	return true;
}

int g64_format::generate_bitstream(int track, int head, int speed_zone, UINT8 *trackbuf, int &track_size, floppy_image *image)
{
	int cell_size = c1541_cell_size[speed_zone];

	generate_bitstream_from_track(track, head, cell_size, trackbuf, track_size, image);

	int actual_cell_size = 200000000L/track_size;

	// allow a tolerance of +- 10 us (3990..4010 -> 4000)
	return ((actual_cell_size >= cell_size-10) && (actual_cell_size <= cell_size+10)) ? speed_zone : -1;
}

bool g64_format::save(io_generic *io, floppy_image *image)
{
	UINT8 header[] = { 'G', 'C', 'R', '-', '1', '5', '4', '1', 0x00, 0x54, TRACK_LENGTH & 0xff, TRACK_LENGTH >> 8 };

	io_generic_write(io, header, SIGNATURE, sizeof(header));

	int head = 0;
	int tracks_written = 0;

	dynamic_buffer trackbuf(TRACK_LENGTH-2);
	for (int track = 0; track < 84; track++) {
		offs_t tpos = TRACK_OFFSET + track * 4;
		offs_t spos = SPEED_ZONE + track * 4;
		offs_t dpos = TRACK_DATA + tracks_written * TRACK_LENGTH;

		io_generic_write_filler(io, 0x00, tpos, 4);
		io_generic_write_filler(io, 0x00, spos, 4);

		if (image->get_track_size(track, head) <= 1)
			continue;

		int track_size;
		int speed_zone;

		// figure out the cell size and speed zone from the track data
		if ((speed_zone = generate_bitstream(track, head, 3, trackbuf, track_size, image)) == -1)
			if ((speed_zone = generate_bitstream(track, head, 2, trackbuf, track_size, image)) == -1)
				if ((speed_zone = generate_bitstream(track, head, 1, trackbuf, track_size, image)) == -1)
					if ((speed_zone = generate_bitstream(track, head, 0, trackbuf, track_size, image)) == -1)
						throw emu_fatalerror("g64_format: Cannot determine speed zone for track %u", track);

		LOG_FORMATS("track %u size %u cell %u\n", track, track_size, c1541_cell_size[speed_zone]);

		UINT8 track_offset[4];
		UINT8 speed_offset[4];
		UINT8 track_length[2];

		place_integer_le(track_offset, 0, 4, dpos);
		place_integer_le(speed_offset, 0, 4, speed_zone);
		place_integer_le(track_length, 0, 2, track_size/8);

		io_generic_write(io, track_offset, tpos, 4);
		io_generic_write(io, speed_offset, spos, 4);
		io_generic_write_filler(io, 0xff, dpos, TRACK_LENGTH);
		io_generic_write(io, track_length, dpos, 2);
		io_generic_write(io, trackbuf, dpos + 2, track_size);

		tracks_written++;
	}

	return true;
}

const char *g64_format::name() const
{
	return "g64";
}

const char *g64_format::description() const
{
	return "Commodore 1541 GCR disk image";
}

const char *g64_format::extensions() const
{
	return "g64,g41";
}

const floppy_format_type FLOPPY_G64_FORMAT = &floppy_image_format_creator<g64_format>;