// 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 constexpr T BIT_MASK(unsigned n) { return (T)1U << n; } template void BIT_CLR(T& w , unsigned n) { w &= ~BIT_MASK(n); } template void BIT_SET(T& w , unsigned n) { w |= BIT_MASK(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 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 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); }