summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/machine/maple-dc.cpp
blob: dcefe0fd84c66dfa5f6474b8452d81ee89d3a425 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                     
 





                                                              

                                                                   
                                                                   





                                                               





                                                                                       





                                                                                            
                                                                                                               
                                                                                                     



                                                                   

                         











                                                                                         
                                              








                                                        
                                











                                     
                   
























                                                                                              

                                          



















                                                                          
                                                                                              
                                              
                                                                           
                                                   











                                                                          
                                                                                              
                                              
                                                                           
                                                   














                                                                                       
                                                                                                                                                               






                                                                               
                                                                         



























                                                                                                 
                                                
                                                                              
                                                   





















                                                                                                            
                                                        
                                                                                      
                                                           
























                                                                              









                                        



















                                            









                                            









                                             
                                                       


















                                            
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert

#include "emu.h"
#include "maple-dc.h"
#include "mie.h"

const device_type MAPLE_DC = &device_creator<maple_dc_device>;

DEVICE_ADDRESS_MAP_START(amap, 32, maple_dc_device)
	AM_RANGE(0x04, 0x07) AM_READWRITE(sb_mdstar_r, sb_mdstar_w)
	AM_RANGE(0x10, 0x13) AM_READWRITE(sb_mdtsel_r, sb_mdtsel_w)
	AM_RANGE(0x14, 0x17) AM_READWRITE(sb_mden_r, sb_mden_w)
	AM_RANGE(0x18, 0x1b) AM_READWRITE(sb_mdst_r, sb_mdst_w)
	AM_RANGE(0x80, 0x83) AM_READWRITE(sb_msys_r, sb_msys_w)
	AM_RANGE(0x8c, 0x8f) AM_WRITE(sb_mdapro_w)
ADDRESS_MAP_END

void maple_dc_device::static_set_maincpu_tag(device_t &device, const char *maincpu_tag)
{
	maple_dc_device &maple_dc = downcast<maple_dc_device &>(device);
	maple_dc.maincpu_tag = maincpu_tag;
}

void maple_dc_device::static_set_irq_cb(device_t &device, void (*irq_cb)(running_machine &))
{
	maple_dc_device &maple_dc = downcast<maple_dc_device &>(device);
	maple_dc.irq_cb = irq_cb;
}

maple_dc_device::maple_dc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
	: device_t(mconfig, MAPLE_DC, "Dreamcast Maple Bus", tag, owner, clock, "maple_dc", __FILE__)
{
	// Do not move that in device_start or there will be a race
	// condition with the maple devices call to register_port.
	memset(devices, 0, sizeof(devices));
	cpu = nullptr;
	irq_cb = nullptr;
}

void maple_dc_device::register_port(int port, maple_device *device)
{
	if(devices[port])
		fatalerror("maple_dc_device: duplicate registration on port %d\n", port);

	devices[port] = device;
}

void maple_dc_device::device_start()
{
	logerror("maple_dc_device started\n");
	cpu = machine().device<sh4_device>(maincpu_tag);
	timer = timer_alloc(0);

	mdstar = 0;

	save_item(NAME(mdstar));
	save_item(NAME(mden));
	save_item(NAME(mdst));
	save_item(NAME(msys));
	save_item(NAME(mdtsel));
	save_item(NAME(dma_state));
	save_item(NAME(dma_adr));
	save_item(NAME(dma_port));
	save_item(NAME(dma_dest));
	save_item(NAME(dma_endflag));
}

void maple_dc_device::device_reset()
{
	mden = 0;
	mdst = 0;
	msys = 0;
	mdtsel = 0;
	dma_state = DMA_IDLE;
	dma_adr = 0;
	dma_port = 0;
	dma_dest = 0;
	dma_endflag = false;
}

void maple_dc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
	timer.adjust(attotime::never);

	switch(dma_state) {
	case DMA_WAIT_REPLY:
		dma_state = DMA_TIMEOUT;
		dma_step();
		break;

	case DMA_WAIT_NOP:
		dma_state = DMA_SEND;
		dma_step();
		break;

	case DMA_DONE:
		dma_state = DMA_IDLE;
		mdst = 0;
		if(irq_cb)
			irq_cb(machine());
		break;

	default:
		logerror("MAPLE: Unexpected timer callback trigger\n");
		break;
	}
}

void maple_dc_device::dma_step()
{
	for(;;) {
		switch(dma_state) {
		case DMA_SEND: {
			sh4_ddt_dma ddtdata;
			UINT32 header[2];
			UINT32 data[512];
			ddtdata.source    = dma_adr; // source address
			ddtdata.length    = 2;       // words to transfer
			ddtdata.size      = 4;       // bytes per word
			ddtdata.buffer    = header;  // destination buffer
			ddtdata.direction = 0;       // 0 source to buffer, 1 buffer to source
			ddtdata.channel   = 0;
			ddtdata.mode      = -1;      // copy from/to buffer
			cpu->sh4_dma_ddt(&ddtdata);
			dma_adr += 8;

			dma_endflag    = header[0] & 0x80000000;
			dma_port       = (header[0] >> 16) & 3;
			UINT32 pattern = (header[0] >> 8) & 7;
			UINT32 length  = (header[0] & 255) + 1;
			dma_dest       = header[1];

			ddtdata.source    = dma_adr; // source address
			ddtdata.length    = length;  // words to transfer
			ddtdata.size      = 4;       // bytes per word
			ddtdata.buffer    = data;    // destination buffer
			ddtdata.direction = 0;       // 0 source to buffer, 1 buffer to source
			ddtdata.channel   = 0;
			ddtdata.mode      = -1;      // copy from/to buffer
			cpu->sh4_dma_ddt(&ddtdata);
			dma_adr += length*4;

			switch(pattern) {
			case 0: // start
				if(devices[dma_port])
					devices[dma_port]->maple_w(data, length);
				else {
					// Avoid spending time on that specific timeout
					dma_state = DMA_TIMEOUT;
					break;
				}
				dma_state = DMA_WAIT_REPLY;

				// the MIE seems too slow for the correct timeout
				// it's rather strange though
				//              timer->adjust(attotime::from_nsec(40000 + 20*(msys>>16))); // The 40us represent the sending and reception time
				timer->adjust(attotime::from_msec(5));
				break;
			case 2: // sdckb occupy permission (light gun protocol)
				logerror("MAPLE: sdckb occupy permission\n");
				break;
			case 3: // reset
				if(devices[dma_port])
					devices[dma_port]->maple_reset();
				break;
			case 4: // sdckb occupy cancel
				logerror("MAPLE: sdckb occupy cancel\n");
				break;
			case 7: // nop
				logerror("MAPLE: nop\n");
				dma_state = DMA_WAIT_NOP;
				break;
			}
			if(dma_state == DMA_SEND && dma_endflag)
				dma_state = DMA_DONE;
			break;
		}

		case DMA_WAIT_REPLY:
			return;

		case DMA_WAIT_NOP:
			return;

		case DMA_TIMEOUT: {
			sh4_ddt_dma ddtdata;
			UINT32 data = 0xffffffff;
			ddtdata.destination = dma_dest; // destination address
			ddtdata.length      = 1;        // words to transfer
			ddtdata.size        = 4;        // bytes per word
			ddtdata.buffer      = &data;    // destination buffer
			ddtdata.direction   = 1;        // 0 source to buffer, 1 buffer to source
			ddtdata.channel     = 0;
			ddtdata.mode        = -1;       // copy from/to buffer
			cpu->sh4_dma_ddt(&ddtdata);
			dma_state = dma_endflag ? DMA_DONE : DMA_SEND;
			break;
		}

		case DMA_GOT_REPLY: {
			timer->adjust(attotime::never);

			sh4_ddt_dma ddtdata;
			UINT32 data[512];
			UINT32 length = 0;
			bool partial = false;
			if(devices[dma_port])
				devices[dma_port]->maple_r(data, length, partial);
			else
				fatalerror("MAPLE: reading from unconnected device on port %d\n", dma_port);

			if(length) {
				ddtdata.destination = dma_dest; // destination address
				ddtdata.length      = length;   // words to transfer
				ddtdata.size        = 4;        // bytes per word
				ddtdata.buffer      = data;     // destination buffer
				ddtdata.direction   = 1;        // 0 source to buffer, 1 buffer to source
				ddtdata.channel     = 0;
				ddtdata.mode        = -1;       // copy from/to buffer
				cpu->sh4_dma_ddt(&ddtdata);
				dma_dest += length*4;
			}

			if(partial)
				dma_state = DMA_WAIT_REPLY;
			else
				dma_state = dma_endflag ? DMA_DONE : DMA_SEND;
			break;
		}
		case DMA_DONE:
			timer->adjust(attotime::from_usec(200));
			return;
		}
	}
}

void maple_dc_device::end_of_reply()
{
	if(dma_state == DMA_WAIT_REPLY) {
		dma_state = DMA_GOT_REPLY;
		dma_step();
	} else
		logerror("MAPLE: Unexpected end of reply\n");
}

void maple_dc_device::maple_hw_trigger()
{
	if(mdtsel & 1) // HW trigger
	{
		dma_adr = mdstar;
		dma_state = DMA_SEND;
		dma_step();
	}
}

READ32_MEMBER(maple_dc_device::sb_mdstar_r)
{
	return mdstar;
}

WRITE32_MEMBER(maple_dc_device::sb_mdstar_w)
{
	mdstar = data & ~31;
}

READ32_MEMBER(maple_dc_device::sb_mden_r)
{
	return mden;
}

WRITE32_MEMBER(maple_dc_device::sb_mden_w)
{
	mden = data & 1;
}

READ32_MEMBER(maple_dc_device::sb_mdtsel_r)
{
	return mdtsel;
}

WRITE32_MEMBER(maple_dc_device::sb_mdtsel_w)
{
	mdtsel = data & 1;
}

READ32_MEMBER(maple_dc_device::sb_mdst_r)
{
	return dma_state != DMA_IDLE ? 1 : 0;
}

WRITE32_MEMBER(maple_dc_device::sb_mdst_w)
{
	UINT32 old = mdst;
	mdst = data & 1;

	if(!old && data && (mden & 1) && mdtsel == 0) {
		dma_adr = mdstar;
		dma_state = DMA_SEND;
		dma_step();
	}
}

READ32_MEMBER(maple_dc_device::sb_msys_r)
{
	return msys;
}

WRITE32_MEMBER(maple_dc_device::sb_msys_w)
{
	msys = data;
}

WRITE32_MEMBER(maple_dc_device::sb_mdapro_w)
{
}