// license:BSD-3-Clause
// copyright-holders:David Haywood

// todo, scrap this and use the core SAB 2797B emulation
// (FM - MFM type) @ 1.25mhz (oscillates 1.250~1.251)


#include "emu.h"
#include "cedar_magnet_flop.h"

DEFINE_DEVICE_TYPE(CEDAR_MAGNET_FLOP, cedar_magnet_flop_device, "cedmag_flop", "Cedar Floppy Simulation")

cedar_magnet_flop_device::cedar_magnet_flop_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, CEDAR_MAGNET_FLOP, tag, owner, clock)
	, m_disk(*this, "disk")
{
}


void cedar_magnet_flop_device::device_add_mconfig(machine_config &config)
{
	NVRAM(config, "floppy_nvram", nvram_device::DEFAULT_NONE);
}


void cedar_magnet_flop_device::device_start()
{
	subdevice<nvram_device>("floppy_nvram")->set_base(memregion("disk")->base(), 0xf0000);
}

void cedar_magnet_flop_device::device_reset()
{
	m_flopdat = 0;
	m_flopcmd = 0;
	m_flopsec = 0;
	m_flopstat = 0;
	m_floptrk = 0;
}

u8 cedar_magnet_flop_device::port60_r()
{
	u8 ret = m_flopstat;
	return ret;
}

u8 cedar_magnet_flop_device::port61_r()
{
	u8 ret = m_curtrack;
	return ret;
}

u8 cedar_magnet_flop_device::port63_r()
{
	u8 ret = machine().rand();

	// printf("%s: port63_r (DATA) (%02x)\n", machine().describe_context().c_str(), ret);

	if ((m_flopcmd&0xf0) == 0x90) // reading data
	{
		int side = (m_flopcmd & 0x02)>>1;
		int read_offset_base = (m_flopsec * 0x400) + (m_curtrack * 0x3000) + (side * 0x1800);

		int sector_size = 1024;

		if (m_secoffs < sector_size)
		{
			m_flopstat |= 0x05;

			int read_offset = read_offset_base + m_secoffs;
			ret = m_disk[read_offset];

			if (m_secoffs == 0)
			{
				// this is weird data, protection??
				if(read_offset_base==0xea400)
					printf("reading sector %d offset %d (from disk image at %04x) (cur track %02x cur side %02x cur sector %02x)\n", m_flopsec, m_secoffs, read_offset, m_curtrack, side, m_flopsec);
			}

			m_secoffs++;

			if (m_secoffs == sector_size)
			{
				//printf("finished sector read\n");
				m_flopstat &= ~0x05;

				m_secoffs = 0;
				m_flopsec++;
			}
		}
		else
		{
			printf("read past sector!! %d\n", m_secoffs);
			m_secoffs++;
		}

	}
	else
	{
		fatalerror("read data in non-read mode?\n");
	}
//
	return ret;
}

void cedar_magnet_flop_device::port60_w(u8 data)
{
	//printf("%s: port60_w (COMMAND) %02x\n", machine().describe_context().c_str(), data);
	m_flopcmd = data;


	switch (m_flopcmd & 0xf0)
	{
	case 0x00:
		//printf("restore\n");
		m_flopstat = 0x06;
		m_curtrack = 0x00;
		break;

	case 0x10:
		//printf("seek track\n");
		m_curtrack = m_flopdat;
		break;


	case 0x90:
		//printf("read sector\n");
		m_flopstat |= 0x07;
		m_secoffs = 0;
		break;

	case 0xb0:
		//printf("write sector\n");
		m_flopstat |= 0x07;
		m_secoffs = 0;
		break;

	case 0xd0:
		//printf("force interrupt?\n");
	//  m_flopstat = 0x06;
	//  m_flopstat &= ~0x07;
	//  m_maincpu->set_input_line(0, HOLD_LINE);

		break;


	default:
		printf("unhandled disk command %02x\n", m_flopcmd);
	}

}

void cedar_magnet_flop_device::port62_w(u8 data)
{
	//printf("%s: port62_w (SECTOR) %02x\n", machine().describe_context().c_str(), data);
	m_flopsec = data;

	if (m_flopsec < 200)
	{
		printf("sector specified <200!\n");
	}

	m_flopsec -= 200;
}

void cedar_magnet_flop_device::port63_w(u8 data)
{
	//printf("%s: port63_w (DATA) %02x\n", machine().describe_context().c_str(), data);
	m_flopdat = data;

	if ((m_flopcmd & 0xf0) == 0xb0) // writing data
	{
		int side = (m_flopcmd & 0x02)>>1;
		int read_offset_base = (m_flopsec * 0x400) + (m_curtrack * 0x3000) + (side * 0x1800);

		int sector_size = 1024;

		if (m_secoffs < sector_size)
		{
			m_flopstat |= 0x05;

			int read_offset = read_offset_base + m_secoffs;
			m_disk[read_offset] = data;

			if (m_secoffs == 0)
			{
				printf("writing sector %d offset %d (from disk image at %04x) (cur track %02x cur side %02x cur sector %02x)\n", m_flopsec, m_secoffs, read_offset, m_curtrack, side, m_flopsec);
			}

			m_secoffs++;

			if (m_secoffs == sector_size)
			{
				//printf("finished sector read\n");
				m_flopstat &= ~0x05;

				m_secoffs = 0;
				m_flopsec++;
			}
		}
	}

}

void cedar_magnet_flop_device::write(offs_t offset, u8 data)
{
	switch (offset & 3)
	{
		case 0x00:port60_w(data);break;
	//  case 0x01:port61_w(space, offset, data);break;
		case 0x02:port62_w(data);break;
		case 0x03:port63_w(data);break;
		default:break;
	}
}

u8 cedar_magnet_flop_device::read(offs_t offset)
{
	switch (offset & 3)
	{
		case 0x00: return port60_r();
		case 0x01: return port61_r();
		//case 0x02: return port62_r(space, offset);
		case 0x03: return port63_r();
		default: return 0x00;
	}

	return 0x00;
}
