summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/i3002.cpp
blob: 932646f11145b6ad19f53df148ef913a6de20a20 (plain) (tree)













































































































                                                                                                              
                                   















                                                       
                                                                                      









                                                    



                                       
































                                                                                               
                                                                         









                                                                                    
                                                                                   




























                                                                                                   
                                                                         

































                                                                                                                     
                                                                         





















                                                                                               
                                                                         








                                                                                    
                                                                         





















                                                                                      
                                                                         








                                                                           
                                                                         























                                                                        
                                                                         





















                                                                       
                                                                         








                                                                       
                                                                                   




















                                                                              
                                                                         








                                                                       
                                                                                   











                                                                             
                           




                                  
                           
 
// license:BSD-3-Clause
// copyright-holders:F. Ulivi
/**********************************************************************

    i3002.cpp

    Intel 3002 Central Processing Element

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

#include "emu.h"
#include "i3002.h"

// Device type definition
DEFINE_DEVICE_TYPE(I3002, i3002_device, "i3002", "Intel i3002 CPE")

// Bit manipulation
namespace {
	template<typename T> constexpr T BIT_MASK(unsigned n)
	{
		return (T)1U << n;
	}

	template<typename T> void BIT_CLR(T& w , unsigned n)
	{
		w &= ~BIT_MASK<T>(n);
	}

	template<typename T> void BIT_SET(T& w , unsigned n)
	{
		w |= BIT_MASK<T>(n);
	}
}

// Table to decode bits 0..3 of FC into RG and register index
struct fc_fields {
	uint8_t rg; // Register group [0..2] ("I" , "II" , "III" in Intel docs)
	unsigned reg;   // Register index
};

constexpr std::array<struct fc_fields , 16> fc_field_tab =
	{{
	  { 0 , i3002_device::REG_R0 }, // 0000
	  { 0 , i3002_device::REG_R1 }, // 0001
	  { 0 , i3002_device::REG_R2 }, // 0010
	  { 0 , i3002_device::REG_R3 }, // 0011
	  { 0 , i3002_device::REG_R4 }, // 0100
	  { 0 , i3002_device::REG_R5 }, // 0101
	  { 0 , i3002_device::REG_R6 }, // 0110
	  { 0 , i3002_device::REG_R7 }, // 0111
	  { 0 , i3002_device::REG_R8 }, // 1000
	  { 0 , i3002_device::REG_R9 }, // 1001
	  { 1 , i3002_device::REG_T },  // 1010
	  { 1 , i3002_device::REG_AC }, // 1011
	  { 0 , i3002_device::REG_T },  // 1100
	  { 0 , i3002_device::REG_AC }, // 1101
	  { 2 , i3002_device::REG_T },  // 1110
	  { 2 , i3002_device::REG_AC }  // 1111
	}};

// Register names
static const std::array<const char* , i3002_device::REG_COUNT> reg_names =
	{{
	  "R0",
	  "R1",
	  "R2",
	  "R3",
	  "R4",
	  "R5",
	  "R6",
	  "R7",
	  "R8",
	  "R9",
	  "T",
	  "AC",
	  "MAR"
	}};

i3002_device::i3002_device(const machine_config &mconfig , const char *tag , device_t *owner , uint32_t clock)
	: device_t(mconfig , I3002 , tag , owner , clock)
	, m_co_handler(*this)
	, m_ro_handler(*this)
	, m_ibus_handler(*this)
	, m_mbus_handler(*this)
{
}

const char *i3002_device::reg_name(unsigned reg_idx)
{
	return reg_names[ reg_idx ];
}

void i3002_device::decode_fc(uint8_t fc , uint8_t& fg , uint8_t& rg , unsigned& reg)
{
	// Function group
	fg = (fc >> 4) & 7;

	uint8_t lsn = fc & 0xf;

	// Register & register group
	rg = fc_field_tab[ lsn ].rg;
	reg = fc_field_tab[ lsn ].reg;
}

void i3002_device::fc_kbus_w(uint8_t fc , uint8_t k)
{
	m_fc = fc & 0x7f;
	m_kbus = k & WORD_MASK;
}

void i3002_device::clk_w(int state)
{
	if (state) {
		update();
	}
}

bool i3002_device::update_ro()
{
	// Update RO output if doing a right-shift only
	uint8_t fg;
	uint8_t rg;
	unsigned reg;

	decode_fc(m_fc , fg , rg , reg);

	if (fg == 0 && rg == 2) {
		uint8_t ik = !m_ibus_handler.isnull() ? m_ibus_handler() & m_kbus : 0;
		uint8_t at = m_reg[ reg ];
		set_ro(BIT(at , 0) && !BIT(ik , 0));
		return true;
	} else {
		return false;
	}
}

void i3002_device::device_start()
{
	m_co_handler.resolve_safe();
	m_ro_handler.resolve_safe();
	m_ibus_handler.resolve_safe(0);
	m_mbus_handler.resolve_safe(0);

	save_item(NAME(m_reg));
	save_item(NAME(m_fc));
	save_item(NAME(m_kbus));
	save_item(NAME(m_ci));
	save_item(NAME(m_li));
	save_item(NAME(m_co));
	save_item(NAME(m_ro));
}

void i3002_device::update()
{
	uint8_t fg;
	uint8_t rg;
	unsigned reg;

	decode_fc(m_fc , fg , rg , reg);

	switch (fg) {
	case 0:
		switch (rg) {
		case 0:
			// FC 0 RG I
			{
				uint8_t tmp = (m_reg[ REG_AC ] & m_kbus) + m_reg[ reg ] + m_ci;
				m_reg[ REG_AC ] = m_reg[ reg ] = tmp & WORD_MASK;
				set_co(BIT(tmp , SLICE_SIZE));
			}
			break;

		case 1:
			// FC 0 RG II
			{
				uint8_t m = m_mbus_handler() & WORD_MASK;
				uint8_t tmp = (m_reg[ REG_AC ] & m_kbus) + m + m_ci;
				m_reg[ reg ] = tmp & WORD_MASK;
				set_co(BIT(tmp , SLICE_SIZE));
			}
			break;

		case 2:
			// FC 0 RG III
			{
				// Who designed this mess???
				uint8_t ik = m_ibus_handler() & WORD_MASK & m_kbus;
				uint8_t at = m_reg[ reg ];
				m_reg[ reg ] = 0;
				set_ro(BIT(at , 0) && !BIT(ik , 0));
				if (m_li || (BIT(ik , 1) && BIT(at , 1))) {
					BIT_SET(m_reg[ reg ] , 1);
				}
				if ((BIT(at , 0) && BIT(ik , 0)) || (BIT(at , 1) || BIT(ik , 1))) {
					BIT_SET(m_reg[ reg ] , 0);
				}
			}
			break;
		}
		break;

	case 1:
		switch (rg) {
		case 0:
			// FC 1 RG I
			{
				m_reg[ REG_MAR ] = m_kbus | m_reg[ reg ];
				uint8_t tmp = m_reg[ reg ] + m_kbus + m_ci;
				m_reg[ reg ] = tmp & WORD_MASK;
				set_co(BIT(tmp , SLICE_SIZE));
			}
			break;

		case 1:
			// FC 1 RG II
			{
				uint8_t m = m_mbus_handler() & WORD_MASK;
				m_reg[ REG_MAR ] = m_kbus | m;
				uint8_t tmp = m + m_kbus + m_ci;
				m_reg[ reg ] = tmp & WORD_MASK;
				set_co(BIT(tmp , SLICE_SIZE));
			}
			break;

		case 2:
			// FC 1 RG III
			{
				uint8_t tmp = ((m_reg[ reg ] ^ WORD_MASK) | m_kbus) + (m_reg[ reg ] & m_kbus) + m_ci;
				m_reg[ reg ] = tmp & WORD_MASK;
				set_co(BIT(tmp , SLICE_SIZE));
			}
			break;
		}
		break;

	case 2:
		switch (rg) {
		case 0:
		case 1:
			// FC 2 RG I
			// FC 2 RG II
			{
				uint8_t tmp = (m_reg[ REG_AC ] & m_kbus) + WORD_MASK + m_ci;
				m_reg[ reg ] = tmp & WORD_MASK;
				set_co(BIT(tmp , SLICE_SIZE));
			}
			break;

		case 2:
			// FC 2 RG III
			{
				uint8_t i = m_ibus_handler() & WORD_MASK;
				uint8_t tmp = (i & m_kbus) + WORD_MASK + m_ci;
				m_reg[ reg ] = tmp & WORD_MASK;
				set_co(BIT(tmp , SLICE_SIZE));
			}
			break;
		}
		break;

	case 3:
		switch (rg) {
		case 0:
			// FC 3 RG I
			{
				uint8_t tmp = (m_reg[ REG_AC ] & m_kbus) + m_reg[ reg ] + m_ci;
				m_reg[ reg ] = tmp & WORD_MASK;
				set_co(BIT(tmp , SLICE_SIZE));
			}
			break;

		case 1:
			// FC 3 RG II (== FC 0 RG II)
			{
				uint8_t m = m_mbus_handler() & WORD_MASK;
				uint8_t tmp = (m_reg[ REG_AC ] & m_kbus) + m + m_ci;
				m_reg[ reg ] = tmp & WORD_MASK;
				set_co(BIT(tmp , SLICE_SIZE));
			}
			break;

		case 2:
			// FC 3 RG III
			{
				uint8_t i = m_ibus_handler() & WORD_MASK;
				uint8_t tmp = (i & m_kbus) + m_reg[ reg ] + m_ci;
				m_reg[ reg ] = tmp & WORD_MASK;
				set_co(BIT(tmp , SLICE_SIZE));
			}
			break;
		}
		break;

	case 4:
		switch (rg) {
		case 0:
			// FC 4 RG I
			{
				uint8_t tmp = m_reg[ reg ] & m_reg[ REG_AC ] & m_kbus;
				m_reg[ reg ] = tmp;
				set_co(m_ci || tmp != 0);
			}
			break;

		case 1:
			// FC 4 RG II
			{
				uint8_t m = m_mbus_handler() & WORD_MASK;
				uint8_t tmp = m & m_reg[ REG_AC ] & m_kbus;
				m_reg[ reg ] = tmp;
				set_co(m_ci || tmp != 0);
			}
			break;

		case 2:
			// FC 4 RG III
			{
				uint8_t i = m_ibus_handler() & WORD_MASK;
				uint8_t tmp = i & m_reg[ reg ] & m_kbus;
				m_reg[ reg ] = tmp;
				set_co(m_ci || tmp != 0);
			}
			break;
		}
		break;

	case 5:
		switch (rg) {
		case 0:
		case 2:
			// FC 5 RG I
			// FC 5 RG III
			{
				uint8_t tmp = m_reg[ reg ] & m_kbus;
				m_reg[ reg ] = tmp;
				set_co(m_ci || tmp != 0);
			}
			break;

		case 1:
			// FC 5 RG II
			{
				uint8_t m = m_mbus_handler() & WORD_MASK;
				uint8_t tmp = m & m_kbus;
				m_reg[ reg ] = tmp;
				set_co(m_ci || tmp != 0);
			}
			break;
		}
		break;

	case 6:
		switch (rg) {
		case 0:
			// FC 6 RG I
			{
				uint8_t tmp = m_reg[ REG_AC ] & m_kbus;
				m_reg[ reg ] |= tmp;
				set_co(m_ci || tmp != 0);
			}
			break;

		case 1:
			// FC 6 RG II
			{
				uint8_t m = m_mbus_handler() & WORD_MASK;
				uint8_t tmp = m_reg[ REG_AC ] & m_kbus;
				m_reg[ reg ] = m | tmp;
				set_co(m_ci || tmp != 0);
			}
			break;

		case 2:
			// FC 6 RG III
			{
				uint8_t ik = m_ibus_handler() & WORD_MASK & m_kbus;
				m_reg[ reg ] |= ik;
				set_co(m_ci || ik != 0);
			}
			break;
		}
		break;

	case 7:
		switch (rg) {
		case 0:
			// FC 7 RG I
			{
				uint8_t tmp = m_reg[ REG_AC ] & m_kbus;
				set_co(m_ci || (m_reg[ reg ] & tmp) != 0);
				m_reg[ reg ] = m_reg[ reg ] ^ tmp ^ WORD_MASK;
			}
			break;

		case 1:
			// FC 7 RG II
			{
				uint8_t m = m_mbus_handler() & WORD_MASK;
				uint8_t tmp = m_reg[ REG_AC ] & m_kbus;
				set_co(m_ci || (m & tmp) != 0);
				m_reg[ reg ] = m ^ tmp ^ WORD_MASK;
			}
			break;

		case 2:
			// FC 7 RG III
			{
				uint8_t ik = m_ibus_handler() & WORD_MASK & m_kbus;
				set_co(m_ci || (m_reg[ reg ] & ik) != 0);
				m_reg[ reg ] = m_reg[ reg ] ^ ik ^ WORD_MASK;
			}
			break;
		}
		break;
	}
}

void i3002_device::set_co(bool co)
{
	m_co = co;
	m_co_handler(m_co);
}

void i3002_device::set_ro(bool ro)
{
	m_ro = ro;
	m_ro_handler(m_ro);
}