// license:GPL-2.0+
// copyright-holders:Karl-Ludwig Deisenhofer
/**********************************************************************

    formats/rx50_dsk.c
    Floppies used by Rainbow 100 and 190.

    The RX50 drive: 5.25" format; 300 rpm; MFM 250 kbps; 96 - 100 tpi
    - single sided with two disk slots (1 drive motor served both).

    DEC used the RX50 in entirely different architectures (Pro / PDP-11).
    Native Rainbow 100 format:
    - SSQD - 80 tracks with 10 sectors per track (512 byte sectors)
    - first two tracks are reserved for loader code (DOS / CPM / custom)
    - FAT and root directory began immediately on track 2.
    - 2:1 sector interleave pattern - except in tracks 0 and 1.
    NOTE: PUTR tends to interleave loader tracks 0 + 1. Not recommended!

    Jeff's RBIMG is first choice for preservation, TeleDisk is second.
    Always check the track layout. Both have problems with weak disks.

    A container to handle copy protected RX 50 disks is needed. Some info
    can be derived from Mark Hittinger's RBACKUP (CP/M source from Nov-94).

    TODO: improve code to accept 40 T / single sided / 9 or 8 sector disks:
      a) disks from VT180 (9 sectors; READ ONLY - enforced by BIOS)

      b) 8 sector 160k MS-DOS disks (READ + WRITE support on DEC)
         FORMAT A: /F:160 on DOS; turn MEDIACHK ON
************************************************************************/

#include "formats/rx50_dsk.h"

#include "ioprocs.h"


// Controller: WD1793
// TRACK LAYOUT IS UNVERIFED. SEE SOURCES:
// - 'esq_dsk16' (uses WD 1772)
// - SDC-RX50 Floppy Controller Manual
// - 'PC 100 SYSTEM SPEC' 4.3 - page 42. (*)
const floppy_image_format_t::desc_e rx50img_format::rx50_10_desc[] = {
	{   MFM, 0x4e, 80 },          // (*)   GAP (1)
	{   MFM, 0x00, 12 },          // Value from (*). (?? = unverified)
	{   RAW, 0x5224, 3 },
	{   MFM, 0xfc, 1 },
	{   MFM, 0x4e, 50 },
	{ MFM, 0x00, 12 },
	{ SECTOR_LOOP_START, 0, 9 }, // 0 ... f.sector_count-1
	{   CRC_CCITT_START, 1 },
	{     RAW, 0x4489, 3 },
	{     MFM, 0xfe, 1 },
	{     TRACK_ID },
	{     HEAD_ID },
	{     SECTOR_ID },
	{     SIZE_ID },
	{   CRC_END, 1 },
	{   CRC, 1 },
	{   MFM, 0x4e, 22 },    // (*) POST-ID GAP (2)
	{   MFM, 0x00, 12 },    // (*)
	{   CRC_CCITT_START, 2 },
	{     RAW, 0x4489, 3 },
	{     MFM, 0xfb, 1 },
	{     SECTOR_DATA, -1 },
	{   CRC_END, 2 },
	{   CRC, 2 },
	{   MFM, 0x4e, 48 },    // GAP (3) - taken from RBACKUP source.
	{   MFM, 0x00, 12 },
	{ SECTOR_LOOP_END },
	{ MFM, 0x4e, 1 },    // UNVERIFIED - ('esq_16' has 170 x $4e)
	{ END }
};

rx50img_format::rx50img_format()
{
}

const char *rx50img_format::name() const
{
	return "rx50";
}

const char *rx50img_format::description() const
{
	return "DEC Rainbow 100 floppy image";
}

const char *rx50img_format::extensions() const
{
	return "img";
}

bool rx50img_format::supports_save() const
{
	return true;
}

void rx50img_format::find_size(util::random_read &io, uint8_t &track_count, uint8_t &head_count, uint8_t &sector_count)
{
	head_count = 1;

	uint32_t expected_size = 0;
	uint64_t size;
	if (io.length(size))
	{
		track_count = head_count = sector_count = 0;
		return;
	}

	track_count = 80;
	sector_count = 10;
	expected_size = 512 * track_count * head_count * sector_count;

	if (size == expected_size) // standard format has 409600 byte
		return;
/*
    track_count = 40;
    sector_count = 9; // [VT 180]
    expected_size = 512 * track_count * head_count * sector_count;
    if (size == expected_size)
        return;

    track_count = 40;
    sector_count = 8; // [DOS]
    expected_size = 512 * track_count * head_count * sector_count;
    if (size == expected_size)
        return;
*/
	track_count = head_count = sector_count = 0;
}

int rx50img_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants)
{
	uint8_t track_count, head_count, sector_count;
	find_size(io, track_count, head_count, sector_count);

	if(track_count)
		return 50;
	return 0;
}

	//  /* Sectors are numbered 1 to 10 */
bool rx50img_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image)
{
	uint8_t track_count, head_count, sector_count;
	find_size(io, track_count, head_count, sector_count);
	if(track_count == 0)
		return false;

	uint8_t sectdata[10*512];
	desc_s sectors[10];
	for(int i=0; i<sector_count; i++) {
		sectors[i].data = sectdata + 512*i;
		sectors[i].size = 512;
		sectors[i].sector_id = i + 1; // SECTOR_ID +1  <===
	}

	int track_size = sector_count*512;
	for(int track=0; track < track_count; track++) {
		for(int head=0; head < head_count; head++) {
			size_t actual;
			io.read_at((track*head_count + head)*track_size, sectdata, track_size, actual);
			generate_track(rx50_10_desc, track, head, sectors, sector_count, 102064, image);  // 98480
		}
	}

	image->set_variant(floppy_image::SSQD);

	return true;
}

bool rx50img_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image)
{
	int track_count, head_count, sector_count;
	get_geometry_mfm_pc(image, 2000, track_count, head_count, sector_count);

	if(track_count != 80)
		track_count = 80;

	// Happens for a fully unformatted floppy
	if(!head_count)
		head_count = 1;

	if(sector_count == 9) // [VT180] 9 sector format : no save!
		return false;

	if(sector_count != 10) // either 8 or 10 sectors
		sector_count = 10; // [STANDARD]

	/*
	if(sector_count != 10) // either 8 or 10 sectors
	{
	  if(sector_count == 8)
	  {
	      track_count = 40;  // [DOS]
	  } else
	  {
	      sector_count = 10; // [STANDARD]
	  }
	}
*/
	uint8_t sectdata[11*512];
	int track_size = sector_count*512;

	for(int track=0; track < track_count; track++) {
		for(int head=0; head < head_count; head++) {
			get_track_data_mfm_pc(track, head, image, 2000, 512, sector_count, sectdata);
			size_t actual;
			io.write_at((track*head_count + head)*track_size, sectdata, track_size, actual);
		}
	}
	return true;
}

const floppy_format_type FLOPPY_RX50IMG_FORMAT = &floppy_image_format_creator<rx50img_format>;


/*

// Native 400K format (80 T * 10 S * 512 bytes) on 'quad density' RX50 drives
// ( 5.25" single sided; 300 rpm; MFM 250 kbps; 96 - 100 tpi ).
//
// The BIOS can also * read * VT-180 disks and access MS-DOS 160 k disks (R + W)
// ( 40 tracks; single sided with 9 or 8 sectors per track )
static LEGACY_FLOPPY_OPTIONS_START( dec100_floppy )
    LEGACY_FLOPPY_OPTION( dec100_floppy, "td0", "Teledisk floppy disk image", td0_dsk_identify, td0_dsk_construct, td0_dsk_destruct, nullptr )
    LEGACY_FLOPPY_OPTION( dec100_floppy, "img", "DEC Rainbow 100", basicdsk_identify_default, basicdsk_construct_default,    nullptr,
        HEADS([1])
        TRACKS(40/[80])
        SECTORS(8/9/[10])
        SECTOR_LENGTH([512])
        INTERLEAVE([0])
        FIRST_SECTOR_ID([1])
                        )
LEGACY_FLOPPY_OPTIONS_END

*/
