summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/am2910.cpp
blob: 70b47c30c68be757cca299109656076db7759d64 (plain) (tree)
1
2
3
4
5
6
7
8
9
10






                                                                            


                                                





                                                                            


                             
                                                      
 
                       










































                                                                                                             
                    
                                                                                     














                                                                                                   
                                                
 
                           

 
                                   



                     
                                     



                       
                                   



                     
                                    



                      
                                   














































                                      
                                    



                                                        
                                                             






                                                         
                                     


                                                          
                                               



                                                         
                                                            




                                                          
                                                 






                                                          
                                                   





                                                         
                                                 





                                                         
                                                      






                                                          
                                                    






                                                          
                                               



                                                          
                                                      






                                                          
                                                    


                                                          
                                          



                                                          
                                     

                                                          
                                            

















































                                                                              
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/***************************************************************************

    am2910.cpp
    AMD Am2910 Microprogram Controller emulation

    TODO:
    - Check /RLD behavior
    - Find and fix bugs that almost surely exist

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

#include "emu.h"
#include "am2910.h"

#define LOG_INSN    (1U << 1)
#define LOG_STACK   (1U << 2)
#define LOG_ERROR   (1U << 3)
#define LOG_ALL     (LOG_INSN | LOG_STACK | LOG_ERROR)

#define VERBOSE     (0)
#include "logmacro.h"

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

DEFINE_DEVICE_TYPE(AM2910, am2910_device, "am2910", "AMD Am2910 Microprogram Controller")

//-------------------------------------------------
//  am2910_device - constructor
//-------------------------------------------------

am2910_device::am2910_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, AM2910, tag, owner, clock)
	, m_pc(0)
	, m_r(0)
	, m_sp(0)
	, m_cc(0)
	, m_ccen(0)
	, m_ci(0)
	, m_rld(0)
	, m_cp(0)
	, m_y(*this)
	, m_full(*this)
	, m_pl(*this)
	, m_map(*this)
	, m_vect(*this)
{
}


void am2910_device::device_start()
{
	save_item(NAME(m_pc));
	save_item(NAME(m_r));
	save_item(NAME(m_sp));
	save_item(NAME(m_stack));
	save_item(NAME(m_cc));
	save_item(NAME(m_ccen));
	save_item(NAME(m_ci));
	save_item(NAME(m_rld));
	save_item(NAME(m_cp));
	save_item(NAME(m_d));
	save_item(NAME(m_i));

	if (clock())
		m_execute_timer = timer_alloc(FUNC(am2910_device::clock_tick), this);
	else
		m_execute_timer = nullptr;
}

void am2910_device::device_reset()
{
	m_pc = 0;
	m_r = 0;
	m_sp = 0;
	memset(m_stack, 0, sizeof(uint16_t) * 5);

	if (m_execute_timer)
		m_execute_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock()));
}

TIMER_CALLBACK_MEMBER(am2910_device::clock_tick)
{
	cp_w(m_cp ? 0 : 1);
}

void am2910_device::cc_w(int state)
{
	m_cc = state;
}

void am2910_device::ccen_w(int state)
{
	m_ccen = state;
}

void am2910_device::ci_w(int state)
{
	m_ci = state;
}

void am2910_device::rld_w(int state)
{
	m_rld = state;
}

void am2910_device::cp_w(int state)
{
	int old_state = m_cp;
	m_cp = state;
	if (!old_state && state)
		execute();
}

void am2910_device::d_w(uint16_t data)
{
	m_d = data;
}

void am2910_device::i_w(uint8_t data)
{
	m_i = data;
}

void am2910_device::update_source()
{
	switch (m_i)
	{
	case 2:
		m_pl(0);
		m_map(1);
		m_vect(0);
		break;
	case 6:
		m_pl(0);
		m_map(0);
		m_vect(1);
		break;
	default:
		m_pl(1);
		m_map(0);
		m_vect(0);
		break;
	}
}

void am2910_device::execute()
{
	if (m_rld == 0)
		m_r = m_d;

	m_pc += (uint16_t)m_ci;
	switch (m_i)
	{
	case 0:     // JZ, Jump Zero
		LOGMASKED(LOG_INSN, "%04x: JZ\n", m_pc);
		m_pc = 0;
		m_sp = 0;
		break;
	case 1:     // CJS, Conditional Jump-To-Subroutine PL
		LOGMASKED(LOG_INSN, "%04x: CJS\n", m_pc);
		if (test_pass())
		{
			push(m_pc);
			m_pc = m_d;
		}
		break;
	case 2:     // JMAP, Jump Map
		LOGMASKED(LOG_INSN, "%04x: JMAP\n", m_pc);
		m_pc = m_d;
		break;
	case 3:     // CJP, Conditional Jump PL
		LOGMASKED(LOG_INSN, "%04x: CJP\n", m_pc);
		if (test_pass())
			m_pc = m_d;
		break;
	case 4:     // PUSH, Push / Conditional Load Counter
		LOGMASKED(LOG_INSN, "%04x: PUSH\n", m_pc);
		push(m_pc);
		if (test_pass())
			m_r = m_d;
		break;
	case 5:     // JSRP, Conditional JSB R/PL
		LOGMASKED(LOG_INSN, "%04x: JSRP\n", m_pc);
		push(m_pc);
		if (test_pass())
			m_pc = m_d;
		else
			m_pc = m_r;
		break;
	case 6:     // CJV, Conditional Jump Vector
		LOGMASKED(LOG_INSN, "%04x: CJV\n", m_pc);
		if (test_pass())
		{
			m_pc = m_d;
		}
		break;
	case 7:     // JRP, Conditional Jump R/PL
		LOGMASKED(LOG_INSN, "%04x: JRP\n", m_pc);
		if (test_pass())
			m_pc = m_d;
		else
			m_pc = m_r;
		break;
	case 8:     // RFCT, Repeat Loop, Counter != 0
		LOGMASKED(LOG_INSN, "%04x: RFCT\n", m_pc);
		if (m_r != 0)
		{
			m_r--;
			m_pc = m_stack[m_sp];
		}
		break;
	case 9:     // RPCT, Repeat PL, Counter != 0
		LOGMASKED(LOG_INSN, "%04x: RPCT\n", m_pc);
		if (m_r != 0)
		{
			m_r--;
			m_pc = m_d;
		}
		break;
	case 10:    // CRTN, Conditional Return
		LOGMASKED(LOG_INSN, "%04x: CRTN\n", m_pc);
		if (test_pass())
			m_pc = m_stack[m_sp];
		break;
	case 11:    // CJPP, Conditional Jump PL & Pop
		LOGMASKED(LOG_INSN, "%04x: CJPP\n", m_pc);
		if (test_pass())
		{
			m_pc = m_d;
			pop();
		}
		break;
	case 12:    // LDCT, Load Counter & Continue
		LOGMASKED(LOG_INSN, "%04x: LDCT\n", m_pc);
		m_r = m_d;
		break;
	case 13:    // LOOP, Test End Loop
		LOGMASKED(LOG_INSN, "%04x: LOOP\n", m_pc);
		if (!test_pass())
			m_pc = m_stack[m_sp];
		break;
	case 14:    // CONT, Continue
		LOGMASKED(LOG_INSN, "%04x: CONT\n", m_pc);
		break;
	case 15:    // TWB, Three-Way Branch
		LOGMASKED(LOG_INSN, "%04x: TWB\n", m_pc);
		if (!test_pass())
		{
			if (m_r != 0)
			{
				m_r--;
				m_pc = m_stack[m_sp];
			}
			else
			{
				m_pc = m_d;
			}
		}
		break;
	default:
		LOGMASKED(LOG_ERROR, "Unrecognized Instruction: %08x\n", m_i);
	}

	m_y(m_pc);
}

bool am2910_device::test_pass()
{
	return m_ccen != 0 || m_cc == 0;
}

void am2910_device::push(uint16_t value)
{
	if (m_sp < 4)
	{
		m_sp++;
		if (m_sp == 4)
		{
			m_full(1);
		}
	}
	m_stack[m_sp] = value;
}

void am2910_device::pop()
{
	if (m_sp > 0)
	{
		m_sp--;
		if (m_sp == 3)
		{
			m_full(0);
		}
	}
}