summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/machine/namco_c148.cpp
blob: cfcc1a0ac8674201ae6fef62ba10858c5f012ac8 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
                       
                                  

                                                                            
                                
 




                                                                               
                                                     
 
                                                                             
                                                              
                                         
                                         
                                         
                            




                                                              
                                   











                                                                   
                                        
                                                     
                                                                    

                                                                            



                       
                         
                     
 






                                                                            
                                                                                                  










                                                                                                                     
                                                           


                               
                                                 



                              



















                                                                                                                                                                  








                                                   
                                                                
                                                                               

                                     


                                     
                                                                         







                                           








                                                   
                              
                           


                           

 


















                                                                                                                                                   
                                                                            
               

                                                                            




                                                                                         
 
                                               
 

                                                                       
                                                                                                    

                                                        

 




                                                                                                                                                                       











                                                                                                                               
 
                                                                            
              
                                                                            
 

                                        
                                                    



                                          
                                

 

                                          
                                


                                                                










                                              



                                                                                            

 



                                                                            

                                            

                                                                

 




                                                               














                                                               



                                                                                                                                     
                                      






                                                     



                                            
 
// license:BSD-3-Clause
// copyright-holders:Angelo Salese
/***************************************************************************

    Namco C148 - CPU Bus Manager

    Does some Memory Decode, Interrupt Handling, 3 bit PIO port, Bus Controller

    Based off implementation from K.Wilkins and Phil Stroffolino

    TODO:
    - hookup C116 device, @see mame/machine/namcoic.h

=============================================================================
Interrupt Controller C148          1C0000-1FFFFF  R/W  D00-D02
    Bus Controller?                1C0XXX
    ????????                       1C2XXX
    ????????                       1C4XXX
    -x- master priority bit?
    Master/Slave IRQ level         1C6XXX              D00-D02
    EXIRQ level                    1C8XXX              D00-D02
    POSIRQ level                   1CAXXX              D00-D02
    SCIRQ level                    1CCXXX              D00-D02
    VBLANK IRQ level               1CEXXX              D00-D02
    xxx irq level for specific irq.
    ????????                       1D0XXX
    ????????                       1D4000 trigger master/slave INT?

    Acknowlegde Master/Slave IRQ   1D6XXX ack master/slave INT
    Acknowledge EXIRQ              1D8XXX
    Acknowledge POSIRQ             1DAXXX
    Acknowledge SCIRQ              1DCXXX
    Acknowledge VBLANK IRQ         1DEXXX

    EEPROM Ready status            1E0XXX         R    D01
    Sound CPU Reset control        1E2XXX           W  D01
    Slave 68000 & IO CPU Reset     1E4XXX           W  D01
    xxx PIO ports, per-HW / CPU specific
    Watchdog reset kicker          1E6XXX           W
    xxx Unknown at current stage if internal or external to the C148

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

#include "emu.h"
#include "namco_c148.h"

#define VERBOSE         0
#include "logmacro.h"



//**************************************************************************
//  GLOBAL VARIABLES
//**************************************************************************

// device type definition
DEFINE_DEVICE_TYPE(NAMCO_C148, namco_c148_device, "namco_c148", "Namco C148 Interrupt Controller")


//**************************************************************************
//  LIVE DEVICE
//**************************************************************************

//-------------------------------------------------
//  namco_c148_device - constructor
//-------------------------------------------------

namco_c148_device::namco_c148_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, NAMCO_C148, tag, owner, clock),
	m_out_ext1_cb(*this),
	m_out_ext2_cb(*this),
	m_hostcpu_tag(nullptr),
	m_linked_c148_tag(finder_base::DUMMY_TAG)
{
}

// (*) denotes master CPU only
void namco_c148_device::map(address_map &map)
{
	map(0x04000, 0x05fff).rw(this, FUNC(namco_c148_device::bus_ctrl_r), FUNC(namco_c148_device::bus_ctrl_w)).umask16(0x00ff);
	map(0x06000, 0x07fff).rw(this, FUNC(namco_c148_device::cpu_irq_level_r), FUNC(namco_c148_device::cpu_irq_level_w)).umask16(0x00ff); // CPUIRQ lv
	map(0x08000, 0x09fff).rw(this, FUNC(namco_c148_device::ex_irq_level_r), FUNC(namco_c148_device::ex_irq_level_w)).umask16(0x00ff); // EXIRQ lv
	map(0x0a000, 0x0bfff).rw(this, FUNC(namco_c148_device::pos_irq_level_r), FUNC(namco_c148_device::pos_irq_level_w)).umask16(0x00ff); // POSIRQ lv
	map(0x0c000, 0x0dfff).rw(this, FUNC(namco_c148_device::sci_irq_level_r), FUNC(namco_c148_device::sci_irq_level_w)).umask16(0x00ff); // SCIRQ lv
	map(0x0e000, 0x0ffff).rw(this, FUNC(namco_c148_device::vblank_irq_level_r), FUNC(namco_c148_device::vblank_irq_level_w)).umask16(0x00ff); // VBlank IRQ lv

	map(0x10000, 0x11fff).w(this, FUNC(namco_c148_device::cpu_irq_assert_w));
	map(0x16000, 0x17fff).rw(this, FUNC(namco_c148_device::cpu_irq_ack_r), FUNC(namco_c148_device::cpu_irq_ack_w)); // CPUIRQ ack
	map(0x18000, 0x19fff).rw(this, FUNC(namco_c148_device::ex_irq_ack_r), FUNC(namco_c148_device::ex_irq_ack_w)); // EXIRQ ack
	map(0x1a000, 0x1bfff).rw(this, FUNC(namco_c148_device::pos_irq_ack_r), FUNC(namco_c148_device::pos_irq_ack_w)); // POSIRQ ack
	map(0x1c000, 0x1dfff).rw(this, FUNC(namco_c148_device::sci_irq_ack_r), FUNC(namco_c148_device::sci_irq_ack_w)); // SCIRQ ack
	map(0x1e000, 0x1ffff).rw(this, FUNC(namco_c148_device::vblank_irq_ack_r), FUNC(namco_c148_device::vblank_irq_ack_w)); // VBlank IRQ ack
	map(0x20000, 0x21fff).r(this, FUNC(namco_c148_device::ext_r)).umask16(0x00ff); // EEPROM ready status (*)
	map(0x22000, 0x23fff).nopr().w(this, FUNC(namco_c148_device::ext1_w)).umask16(0x00ff); // sound CPU reset (*)
	map(0x24000, 0x25fff).w(this, FUNC(namco_c148_device::ext2_w)).umask16(0x00ff); // slave & i/o reset (*)
	map(0x26000, 0x27fff).noprw(); // watchdog
}



//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void namco_c148_device::device_start()
{
	m_hostcpu = machine().device<cpu_device>(m_hostcpu_tag);
	m_linked_c148 = machine().device<namco_c148_device>(m_linked_c148_tag);
	assert(m_hostcpu != nullptr);

	m_out_ext1_cb.resolve_safe();
	m_out_ext2_cb.resolve_safe();

	// TODO: link to SCI, EX and the screen device controller devices

	save_item(NAME(m_irqlevel.cpu));
	save_item(NAME(m_irqlevel.ex));
	save_item(NAME(m_irqlevel.sci));
	save_item(NAME(m_irqlevel.pos));
	save_item(NAME(m_irqlevel.vblank));
	save_item(NAME(m_posirq_line));
	save_item(NAME(m_bus_reg));
}


//-------------------------------------------------
//  device_reset - device-specific reset
//-------------------------------------------------

void namco_c148_device::device_reset()
{
	m_irqlevel.vblank = 0;
	m_irqlevel.pos = 0;
	m_irqlevel.sci = 0;
	m_irqlevel.ex = 0;
	m_irqlevel.cpu = 0;
}

//-------------------------------------------------
//  device_validity_check - device-specific checks
//-------------------------------------------------

void namco_c148_device::device_validity_check(validity_checker &valid) const
{
	device_t *const hostcpu = mconfig().root_device().subdevice(m_hostcpu_tag);
	if (!hostcpu)
		osd_printf_error("Host CPU device %s not found\n", m_hostcpu_tag ? m_hostcpu_tag : "<nullptr>");
	else if (!dynamic_cast<cpu_device *>(hostcpu))
		osd_printf_error("Host CPU device %s is not an instance of cpu_device\n", m_hostcpu_tag ? m_hostcpu_tag : "<nullptr>");

	device_t *const linked_c148 = mconfig().root_device().subdevice(m_linked_c148_tag);
	if ((finder_base::DUMMY_TAG != m_linked_c148_tag) && !linked_c148)
		osd_printf_error("Linked C148 device %s not found\n", m_linked_c148_tag ? m_linked_c148_tag : "<nullptr>");
	else if (linked_c148 && !dynamic_cast<namco_c148_device *>(linked_c148))
		osd_printf_error("Linked C148 device %s is not an instance of c148_device\n", m_linked_c148_tag ? m_linked_c148_tag : "<nullptr>");
}

//**************************************************************************
//  IRQ section
//**************************************************************************

READ8_MEMBER( namco_c148_device::pos_irq_level_r )      { return m_irqlevel.pos & 7; }
READ8_MEMBER( namco_c148_device::vblank_irq_level_r )   { return m_irqlevel.vblank & 7; }
READ8_MEMBER( namco_c148_device::cpu_irq_level_r )      { return m_irqlevel.cpu & 7; }
READ8_MEMBER( namco_c148_device::ex_irq_level_r )       { return m_irqlevel.ex & 7; }
READ8_MEMBER( namco_c148_device::sci_irq_level_r )      { return m_irqlevel.sci & 7; }

inline void namco_c148_device::flush_irq_acks()
{
	// If writing an IRQ priority register, clear any pending IRQs.
	// Dirt Fox and Winning Run require this behaviour
	// TODO: literal behaviour, Winning Run GPU doesn't seem to care about irq ack ports at all?
	for(int i=0;i<8;i++)
		m_hostcpu->set_input_line(i,CLEAR_LINE);
}

WRITE8_MEMBER( namco_c148_device::pos_irq_level_w )     { m_irqlevel.pos = data & 7;    flush_irq_acks(); if(data != 0) { LOG("%s: pos IRQ level = %02x\n",data); }   }
WRITE8_MEMBER( namco_c148_device::vblank_irq_level_w )  { m_irqlevel.vblank = data & 7; flush_irq_acks(); LOG("%s: vblank IRQ level = %02x\n",data);  }
WRITE8_MEMBER( namco_c148_device::cpu_irq_level_w )     { m_irqlevel.cpu = data & 7;    flush_irq_acks(); LOG("%s: cpu IRQ level = %02x\n",data); }
WRITE8_MEMBER( namco_c148_device::ex_irq_level_w )      { m_irqlevel.ex = data & 7;     flush_irq_acks(); LOG("%s: ex IRQ level = %02x\n",data);  }
WRITE8_MEMBER( namco_c148_device::sci_irq_level_w )     { m_irqlevel.sci = data & 7;    flush_irq_acks(); LOG("%s: sci IRQ level = %02x\n",data); }

READ16_MEMBER( namco_c148_device::vblank_irq_ack_r )    { m_hostcpu->set_input_line(m_irqlevel.vblank, CLEAR_LINE); return 0; }
READ16_MEMBER( namco_c148_device::pos_irq_ack_r )       { m_hostcpu->set_input_line(m_irqlevel.pos, CLEAR_LINE);    return 0; }
READ16_MEMBER( namco_c148_device::cpu_irq_ack_r )       { m_hostcpu->set_input_line(m_irqlevel.cpu, CLEAR_LINE);    return 0; }
READ16_MEMBER( namco_c148_device::ex_irq_ack_r )        { m_hostcpu->set_input_line(m_irqlevel.ex, CLEAR_LINE);     return 0; }
READ16_MEMBER( namco_c148_device::sci_irq_ack_r )       { m_hostcpu->set_input_line(m_irqlevel.sci, CLEAR_LINE);    return 0; }

WRITE16_MEMBER( namco_c148_device::vblank_irq_ack_w )   { m_hostcpu->set_input_line(m_irqlevel.vblank, CLEAR_LINE); }
WRITE16_MEMBER( namco_c148_device::pos_irq_ack_w )      { m_hostcpu->set_input_line(m_irqlevel.pos, CLEAR_LINE); }
WRITE16_MEMBER( namco_c148_device::cpu_irq_ack_w )      { m_hostcpu->set_input_line(m_irqlevel.cpu, CLEAR_LINE); }
WRITE16_MEMBER( namco_c148_device::ex_irq_ack_w )       { m_hostcpu->set_input_line(m_irqlevel.ex, CLEAR_LINE); }
WRITE16_MEMBER( namco_c148_device::sci_irq_ack_w )      { m_hostcpu->set_input_line(m_irqlevel.sci, CLEAR_LINE); }

//**************************************************************************
//  Comm ports
//**************************************************************************

READ8_MEMBER( namco_c148_device::ext_r )
{
	return 0xff; // TODO: bit 0 EEPROM bit ready
}

WRITE8_MEMBER( namco_c148_device::ext1_w )
{
	m_out_ext1_cb(data & 7);
}

WRITE8_MEMBER( namco_c148_device::ext2_w )
{
	m_out_ext2_cb(data & 7);
	// TODO: bit 1/2 in Winning Run GPU might be irq enable?
}

READ8_MEMBER( namco_c148_device::bus_ctrl_r )
{
	return m_bus_reg;
}

WRITE8_MEMBER( namco_c148_device::bus_ctrl_w )
{
	m_bus_reg = data & 7;
}


WRITE16_MEMBER( namco_c148_device::cpu_irq_assert_w)
{
	// TODO: Starblade relies on this for showing large polygons, is it the right place?
	m_linked_c148->cpu_irq_trigger();
}

//**************************************************************************
//  GETTERS/SETTERS
//**************************************************************************

void namco_c148_device::vblank_irq_trigger()
{
	// TODO: Phelios doesn't ack the vblank irq at all!
	m_hostcpu->set_input_line(m_irqlevel.vblank, HOLD_LINE);
}

void namco_c148_device::pos_irq_trigger()
{
	m_hostcpu->set_input_line(m_irqlevel.pos, ASSERT_LINE);
}

void namco_c148_device::cpu_irq_trigger()
{
	m_hostcpu->set_input_line(m_irqlevel.cpu, ASSERT_LINE);
}

void namco_c148_device::ex_irq_trigger()
{
	m_hostcpu->set_input_line(m_irqlevel.ex, ASSERT_LINE);
}

void namco_c148_device::sci_irq_trigger()
{
	m_hostcpu->set_input_line(m_irqlevel.sci, ASSERT_LINE);
}

// TODO: these doesn't belong here, needs C116 device
READ8_MEMBER( namco_c148_device::ext_posirq_line_r )
{
	// TODO: same as regular register? winrun91 reads here and subs with integer 0x39 for a new posirq that never gets triggered.
	return (m_posirq_line) & 0xff;
}

WRITE8_MEMBER( namco_c148_device::ext_posirq_line_w )
{
	m_posirq_line = data;
}

uint8_t namco_c148_device::get_posirq_line()
{
	return m_posirq_line;
}