diff options
Diffstat (limited to 'src/devices/cpu/alpha/alpha.cpp')
-rw-r--r-- | src/devices/cpu/alpha/alpha.cpp | 995 |
1 files changed, 0 insertions, 995 deletions
diff --git a/src/devices/cpu/alpha/alpha.cpp b/src/devices/cpu/alpha/alpha.cpp deleted file mode 100644 index 9ebfc6dd09e..00000000000 --- a/src/devices/cpu/alpha/alpha.cpp +++ /dev/null @@ -1,995 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Patrick Mackinlay - -/* - * An implementation of the Digital Alpha CPU family. - * - * Sources: - * - * http://bitsavers.org/pdf/dec/alpha/21064-aa-RISC%20Microprocessor%20Preliminary%20Data%20Sheet-apr92.pdf - * http://bitsavers.org/pdf/dec/alpha/Sites_AlphaAXPArchitectureReferenceManual_2ed_1995.pdf - * https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob_plain;f=opcodes/alpha-opc.c;hb=HEAD - * http://ftp.twaren.net/NetBSD/misc/dec-docs/ - * - * TODO - * - interrupts and exceptions - * - address translation - * - ibox/abox registers - * - floating point instructions - * - primary caches - * - later cpu implementations - * - instruction set extensions - * - big-endian mode - */ - -#include "emu.h" -#include "alpha.h" -#include "common.h" - -#include "debugger.h" - -#include "softfloat3/source/include/softfloat.h" - -#define LOG_GENERAL (1U << 0) -#define LOG_EXCEPTION (1U << 1) -#define LOG_SYSCALLS (1U << 2) - -//#define VERBOSE (LOG_GENERAL | LOG_EXCEPTION) - -#include "logmacro.h" - -DEFINE_DEVICE_TYPE(DEC_21064, dec_21064_device, "21064", "DEC Alpha 21064") - -dec_21064_device::dec_21064_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) - : alpha_ev4_device(mconfig, DEC_21064, tag, owner, clock) -{ -} - -alpha_ev4_device::alpha_ev4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) - : alpha_device(mconfig, type, tag, owner, clock) -{ -} - -alpha_device::alpha_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) - : cpu_device(mconfig, type, tag, owner, clock) - , m_dasm_type(alpha_disassembler::dasm_type::TYPE_UNKNOWN) - , m_as_config - { - address_space_config("0", ENDIANNESS_LITTLE, 64, 32, 0), - address_space_config("1", ENDIANNESS_LITTLE, 64, 32, 0), - address_space_config("2", ENDIANNESS_LITTLE, 64, 32, 0), - address_space_config("3", ENDIANNESS_LITTLE, 64, 32, 0) - } - , m_srom_oe_cb(*this) - , m_srom_data_cb(*this) - , m_icount(0) -{ -} - -void alpha_device::device_start() -{ - set_icountptr(m_icount); - - save_item(NAME(m_pc)); - save_item(NAME(m_r)); - save_item(NAME(m_f)); - - save_item(NAME(m_pal_mode)); - - state_add(STATE_GENPC, "GENPC", m_pc).noshow(); - state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow(); - - state_add(64, "PC", m_pc); - - // integer registers - for (unsigned i = 0; i < 32; i++) - state_add(i, util::string_format("R%d", i).c_str(), m_r[i]); - - // floating point registers - for (unsigned i = 0; i < 32; i++) - state_add(i + 32, util::string_format("F%d", i).c_str(), m_f[i]); - - m_srom_oe_cb.resolve_safe(); - m_srom_data_cb.resolve_safe(0); -} - -void alpha_device::device_reset() -{ - m_pc = 0; - m_pal_mode = true; -} - -void alpha_device::execute_run() -{ - while (m_icount > 0) - { - debugger_instruction_hook(m_pc); - - fetch(m_pc, - [this](u32 const op) - { - // update the program counter - m_pc += 4; - - // execute an instruction - cpu_execute(op); - - // reset always-zero registers - m_r[31] = 0; - m_f[31] = 0; - }); - - m_icount--; - } -} - -void alpha_device::execute_set_input(int inputnum, int state) -{ -} - -device_memory_interface::space_config_vector alpha_device::memory_space_config() const -{ - /* - * EV4 devices have a 34-bit physical address space. This is mapped using - * the top two bits to select one of four memory spaces with the other 32 - * bits giving the offset within each space. This approach works out quite - * well for the jensen hardware, which uses the first space for memory, and - * the others for a variety of I/O memory mapping. - * - * Note: space numbers are multiplied by two to avoid the special handling - * applied to the decrypted opcode space (number 3). - */ - return space_config_vector { - std::make_pair(0, &m_as_config[0]), - std::make_pair(2, &m_as_config[1]), - std::make_pair(4, &m_as_config[2]), - std::make_pair(6, &m_as_config[3]) - }; -} - -bool alpha_device::memory_translate(int spacenum, int intention, offs_t &address) -{ - u64 placeholder = s64(s32(address)); - - if (cpu_translate(placeholder, intention)) - { - address = placeholder; - - return true; - } - - return false; -} - -std::unique_ptr<util::disasm_interface> alpha_device::create_disassembler() -{ - return std::make_unique<alpha_disassembler>(m_dasm_type); -} - -void alpha_device::cpu_execute(u32 const op) -{ - switch ((op >> 26) & 0x3f) - { - case 0x08: m_r[Ra(op)] = m_r[Rb(op)] + Disp_M(op); break; // lda - case 0x09: m_r[Ra(op)] = m_r[Rb(op)] + (Disp_M(op) << 16); break; // ldah - case 0x0b: load<u64>((m_r[Rb(op)] + Disp_M(op)) & ~7, [this, op](u64 data) { m_r[Ra(op)] = data; }); break; // ldq_u - case 0x0f: store<u64>((m_r[Rb(op)] + Disp_M(op)) & ~7, m_r[Ra(op)]); break; // stq_u - - case 0x10: // INTA* (integer arithmetic) - switch ((op >> 5) & 0xff) - { - // register variants - case 0x00: m_r[Rc(op)] = s64(s32(m_r[Ra(op)]) + s32(m_r[Rb(op)])); break; // addl - case 0x02: m_r[Rc(op)] = s64(s32(m_r[Ra(op)] << 2) + s32(m_r[Rb(op)])); break; // s4addl - case 0x09: m_r[Rc(op)] = s64(s32(m_r[Ra(op)]) - s32(m_r[Rb(op)])); break; // subl - case 0x0b: m_r[Rc(op)] = s64(s32(m_r[Ra(op)] << 2) - s32(m_r[Rb(op)])); break; // s4subl - case 0x0f: // cmpbge - { - u8 temp = 0; - for (unsigned i = 0; i < 8; i++) - if (u8(m_r[Ra(op)] >> (i * 8)) >= u8(m_r[Rb(op)] >> (i * 8))) - temp |= (1U << i); - - m_r[Rc(op)] = u64(temp); - } - break; - case 0x12: m_r[Rc(op)] = s64(s32(m_r[Ra(op)] << 3) + s32(m_r[Rb(op)])); break; // s8addl - case 0x1b: m_r[Rc(op)] = s64(s32(m_r[Ra(op)] << 3) - s32(m_r[Rb(op)])); break; // s8subl - case 0x1d: m_r[Rc(op)] = m_r[Ra(op)] < m_r[Rb(op)]; break; // cmpult - case 0x20: m_r[Rc(op)] = m_r[Ra(op)] + m_r[Rb(op)]; break; // addq - case 0x22: m_r[Rc(op)] = (m_r[Ra(op)] << 2) + m_r[Rb(op)]; break; // s4addq - case 0x29: m_r[Rc(op)] = m_r[Ra(op)] - m_r[Rb(op)]; break; // subq - case 0x2b: m_r[Rc(op)] = (m_r[Ra(op)] << 2) - m_r[Rb(op)]; break; // s4subq - case 0x2d: m_r[Rc(op)] = m_r[Ra(op)] == m_r[Rb(op)]; break; // cmpeq - case 0x32: m_r[Rc(op)] = (m_r[Ra(op)] << 3) + m_r[Rb(op)]; break; // s8addq - case 0x3b: m_r[Rc(op)] = (m_r[Ra(op)] << 3) - m_r[Rb(op)]; break; // s8subq - case 0x3d: m_r[Rc(op)] = m_r[Ra(op)] <= m_r[Rb(op)]; break; // cmpule - case 0x40: m_r[Rc(op)] = s64(s32(m_r[Ra(op)]) + s32(m_r[Rb(op)])); break; // addl/v - case 0x49: m_r[Rc(op)] = s64(s32(m_r[Ra(op)]) - s32(m_r[Rb(op)])); break; // subl/v - case 0x4d: m_r[Rc(op)] = s64(m_r[Ra(op)]) < s64(m_r[Rb(op)]); break; // cmplt - case 0x60: m_r[Rc(op)] = m_r[Ra(op)] + m_r[Rb(op)]; break; // addq/v - case 0x69: m_r[Rc(op)] = m_r[Ra(op)] - m_r[Rb(op)]; break; // subq/v - case 0x6d: m_r[Rc(op)] = s64(m_r[Ra(op)]) <= s64(m_r[Rb(op)]); break; // cmple - - // immediate variants - case 0x80: m_r[Rc(op)] = s64(s32(m_r[Ra(op)]) + s32(Im(op))); break; // addl - case 0x82: m_r[Rc(op)] = s64(s32(m_r[Ra(op)] << 2) + s32(Im(op))); break; // s4addl - case 0x89: m_r[Rc(op)] = s64(s32(m_r[Ra(op)]) - s32(Im(op))); break; // subl - case 0x8b: m_r[Rc(op)] = s64(s32(m_r[Ra(op)] << 2) - s32(Im(op))); break; // s4subl - case 0x8f: // cmpbge - { - u8 temp = 0; - for (unsigned i = 0; i < 8; i++) - if (u8(m_r[Ra(op)] >> (i * 8)) >= u8(Im(op))) - temp |= (1U << i); - - m_r[Rc(op)] = u64(temp); - } - break; - case 0x92: m_r[Rc(op)] = s64(s32(m_r[Ra(op)] << 3) + s32(Im(op))); break; // s4addl - case 0x9b: m_r[Rc(op)] = s64(s32(m_r[Ra(op)] << 3) - s32(Im(op))); break; // s8subl - case 0x9d: m_r[Rc(op)] = m_r[Ra(op)] < Im(op); break; // cmpult - case 0xa0: m_r[Rc(op)] = m_r[Ra(op)] + Im(op); break; // addq - case 0xa2: m_r[Rc(op)] = (m_r[Ra(op)] << 2) + Im(op); break; // s4addq - case 0xa9: m_r[Rc(op)] = m_r[Ra(op)] - Im(op); break; // subq - case 0xab: m_r[Rc(op)] = (m_r[Ra(op)] << 2) - Im(op); break; // s4subq - case 0xad: m_r[Rc(op)] = m_r[Ra(op)] == Im(op); break; // cmpeq - case 0xb2: m_r[Rc(op)] = (m_r[Ra(op)] << 3) + Im(op); break; // s8addq - case 0xbb: m_r[Rc(op)] = (m_r[Ra(op)] << 3) - Im(op); break; // s8subq - case 0xbd: m_r[Rc(op)] = m_r[Ra(op)] <= Im(op); break; // cmpule - case 0xc0: m_r[Rc(op)] = s64(s32(m_r[Ra(op)]) + s32(Im(op))); break; // addl/v - case 0xc9: m_r[Rc(op)] = s64(s32(m_r[Ra(op)]) - s32(Im(op))); break; // subl/v - case 0xcd: m_r[Rc(op)] = s64(m_r[Ra(op)]) < s64(Im(op)); break; // cmplt - case 0xe0: m_r[Rc(op)] = m_r[Ra(op)] + Im(op); break; // addq/v - case 0xe9: m_r[Rc(op)] = m_r[Ra(op)] - Im(op); break; // subq/v - case 0xed: m_r[Rc(op)] = s64(m_r[Ra(op)]) <= s64(Im(op)); break; // cmple - } - break; - case 0x11: // INTL* (integer logical) - switch ((op >> 5) & 0xff) - { - // register variants - case 0x00: m_r[Rc(op)] = m_r[Ra(op)] & m_r[Rb(op)]; break; // and - case 0x08: m_r[Rc(op)] = m_r[Ra(op)] & ~m_r[Rb(op)]; break; // bic - case 0x14: // cmovlbs - if (BIT(m_r[Ra(op)], 0)) - m_r[Rc(op)] = m_r[Rb(op)]; - break; - case 0x16: // cmovlbc - if (!BIT(m_r[Ra(op)], 0)) - m_r[Rc(op)] = m_r[Rb(op)]; - break; - case 0x20: m_r[Rc(op)] = m_r[Ra(op)] | m_r[Rb(op)]; break; // bis - case 0x24: // cmoveq - if (m_r[Ra(op)] == 0) - m_r[Rc(op)] = m_r[Rb(op)]; - break; - case 0x26: // cmovne - if (m_r[Ra(op)] != 0) - m_r[Rc(op)] = m_r[Rb(op)]; - break; - case 0x28: m_r[Rc(op)] = m_r[Ra(op)] | ~m_r[Rb(op)]; break; // ornot - case 0x40: m_r[Rc(op)] = m_r[Ra(op)] ^ m_r[Rb(op)]; break; // xor - case 0x44: // cmovlt - if (s64(m_r[Ra(op)]) < 0) - m_r[Rc(op)] = m_r[Rb(op)]; - break; - case 0x46: // cmovge - if (s64(m_r[Ra(op)]) >= 0) - m_r[Rc(op)] = m_r[Rb(op)]; - break; - case 0x48: m_r[Rc(op)] = m_r[Ra(op)] ^ ~m_r[Rb(op)]; break; // eqv - case 0x61: m_r[Rc(op)] = m_r[Rb(op)]; break; // amask - case 0x64: // cmovle - if (s64(m_r[Ra(op)]) <= 0) - m_r[Rc(op)] = m_r[Rb(op)]; - break; - case 0x66: // cmovgt - if (s64(m_r[Ra(op)]) > 0) - m_r[Rc(op)] = m_r[Rb(op)]; - break; - - // immediate variants - case 0x80: m_r[Rc(op)] = m_r[Ra(op)] & Im(op); break; // and - case 0x88: m_r[Rc(op)] = m_r[Ra(op)] & ~Im(op); break; // bic - case 0x94: // cmovlbs - if (BIT(m_r[Ra(op)], 0)) - m_r[Rc(op)] = Im(op); - break; - case 0x96: // cmovlbc - if (!BIT(m_r[Ra(op)], 0)) - m_r[Rc(op)] = Im(op); - break; - case 0xa0: m_r[Rc(op)] = m_r[Ra(op)] | Im(op); break; // bis - case 0xa4: // cmoveq - if (m_r[Ra(op)] == 0) - m_r[Rc(op)] = Im(op); - break; - case 0xa6: // cmovne - if (m_r[Ra(op)] != 0) - m_r[Rc(op)] = Im(op); - break; - case 0xa8: m_r[Rc(op)] = m_r[Ra(op)] | ~Im(op); break; // ornot - case 0xc0: m_r[Rc(op)] = m_r[Ra(op)] ^ Im(op); break; // xor - case 0xc4: // cmovlt - if (s64(m_r[Ra(op)]) < 0) - m_r[Rc(op)] = Im(op); - break; - case 0xc6: // cmovge - if (s64(m_r[Ra(op)]) >= 0) - m_r[Rc(op)] = Im(op); - break; - case 0xc8: m_r[Rc(op)] = m_r[Ra(op)] ^ ~Im(op); break; // eqv - case 0xe1: m_r[Rc(op)] = Im(op); break; // amask - case 0xe4: // cmovle - if (s64(m_r[Ra(op)]) <= 0) - m_r[Rc(op)] = Im(op); - break; - case 0xe6: // cmovgt - if (s64(m_r[Ra(op)]) > 0) - m_r[Rc(op)] = Im(op); - break; - case 0xec: m_r[Rc(op)] = 0; break; // implver - } - break; - case 0x12: // INTS* (integer shift) - switch ((op >> 5) & 0xff) - { - // register variants - case 0x02: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(u8(0x01) << (m_r[Rb(op)] & 7)); break; // mskbl - case 0x06: m_r[Rc(op)] = (m_r[Ra(op)] >> ((m_r[Rb(op)] & 7) * 8)) & zap_mask(~u8(0x01)); break; // extbl - case 0x0b: m_r[Rc(op)] = (m_r[Ra(op)] << ((m_r[Rb(op)] & 7) * 8)) & zap_mask(~(u8(0x01) << (m_r[Rb(op)] & 7))); break; // insbl - case 0x12: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(u8(0x03) << (m_r[Rb(op)] & 7)); break; // mskwl - case 0x16: m_r[Rc(op)] = (m_r[Ra(op)] >> ((m_r[Rb(op)] & 7) * 8)) & zap_mask(~u8(0x03)); break; // extwl - case 0x1b: m_r[Rc(op)] = (m_r[Ra(op)] << ((m_r[Rb(op)] & 7) * 8)) & zap_mask(~(u8(0x03) << (m_r[Rb(op)] & 7))); break; // inswl - case 0x22: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(u8(0x0f) << (m_r[Rb(op)] & 7)); break; // mskll - case 0x26: m_r[Rc(op)] = (m_r[Ra(op)] >> ((m_r[Rb(op)] & 7) * 8)) & zap_mask(~u8(0x0f)); break; // extll - case 0x2b: m_r[Rc(op)] = (m_r[Ra(op)] << ((m_r[Rb(op)] & 7) * 8)) & zap_mask(~(u8(0x0f) << (m_r[Rb(op)] & 7))); break; // insll - case 0x30: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(m_r[Rb(op)]); break; // zap - case 0x31: m_r[Rc(op)] = m_r[Ra(op)] & ~zap_mask(m_r[Rb(op)]); break; // zapnot - case 0x32: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(u8(0xff) << (m_r[Rb(op)] & 7)); break; // mskql - case 0x34: m_r[Rc(op)] = m_r[Ra(op)] >> (m_r[Rb(op)] & 63); break; // srl - case 0x36: m_r[Rc(op)] = (m_r[Ra(op)] >> ((m_r[Rb(op)] & 7) * 8)) & zap_mask(u8(~u8(0xff))); break; // extql - case 0x39: m_r[Rc(op)] = m_r[Ra(op)] << (m_r[Rb(op)] & 63); break; // sll - case 0x3b: m_r[Rc(op)] = (m_r[Ra(op)] << ((m_r[Rb(op)] & 7) * 8)) & zap_mask(~(u8(0xff) << (m_r[Rb(op)] & 7))); break; // insql - case 0x3c: m_r[Rc(op)] = s64(m_r[Ra(op)]) >> (m_r[Rb(op)] & 63); break; // sra - case 0x52: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(u8(0x03) >> (8 - (m_r[Rb(op)] & 7))); break; // mskwh - case 0x57: m_r[Rc(op)] = (m_r[Ra(op)] >> (64 - ((m_r[Rb(op)] & 7) * 8))) & zap_mask(~(u8(0x03) >> (8 - (m_r[Rb(op)] & 7)))); break; // inswh - case 0x5a: m_r[Rc(op)] = (m_r[Ra(op)] << (64 - ((m_r[Rb(op)] & 7) * 8))) & zap_mask(~u8(0x03)); break; // extwh - case 0x62: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(u8(0x0f) >> (8 - (m_r[Rb(op)] & 7))); break; // msklh - case 0x67: m_r[Rc(op)] = (m_r[Ra(op)] >> (64 - ((m_r[Rb(op)] & 7) * 8))) & zap_mask(~(u8(0x0f) >> (8 - (m_r[Rb(op)] & 7)))); break; // inslh - case 0x6a: m_r[Rc(op)] = (m_r[Ra(op)] << (64 - ((m_r[Rb(op)] & 7) * 8))) & zap_mask(~u8(0x0f)); break; // extlh - case 0x72: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(u8(0xff) >> (8 - (m_r[Rb(op)] & 7))); break; // mskqh - case 0x77: m_r[Rc(op)] = (m_r[Ra(op)] >> (64 - ((m_r[Rb(op)] & 7) * 8))) & zap_mask(~(u8(0xff) >> (8 - (m_r[Rb(op)] & 7)))); break; // insqh - case 0x7a: m_r[Rc(op)] = (m_r[Ra(op)] << (64 - ((m_r[Rb(op)] & 7) * 8))) & zap_mask(u8(~u8(0xff))); break; // extqh - - // immediate variants - case 0x82: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(u8(0x01) << (Im(op) & 7)); break; // mskbl - case 0x86: m_r[Rc(op)] = (m_r[Ra(op)] >> ((Im(op) & 7) * 8)) & zap_mask(~u8(0x01)); break; // extbl - case 0x8b: m_r[Rc(op)] = (m_r[Ra(op)] << ((Im(op) & 7) * 8)) & zap_mask(~(u8(0x01) << (Im(op) & 7))); break; // insbl - case 0x92: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(u8(0x03) << (Im(op) & 7)); break; // mskwl - case 0x96: m_r[Rc(op)] = (m_r[Ra(op)] >> ((Im(op) & 7) * 8)) & zap_mask(~u8(0x03)); break; // extwl - case 0x9b: m_r[Rc(op)] = (m_r[Ra(op)] << ((Im(op) & 7) * 8)) & zap_mask(~(u8(0x03) << (Im(op) & 7))); break; // inswl - case 0xa2: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(u8(0x0f) << (Im(op) & 7)); break; // mskll - case 0xa6: m_r[Rc(op)] = (m_r[Ra(op)] >> ((Im(op) & 7) * 8)) & zap_mask(~u8(0x0f)); break; // extll - case 0xab: m_r[Rc(op)] = (m_r[Ra(op)] << ((Im(op) & 7) * 8)) & zap_mask(~(u8(0x0f) << (Im(op) & 7))); break; // insll - case 0xb0: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(Im(op)); break; // zap - case 0xb1: m_r[Rc(op)] = m_r[Ra(op)] & ~zap_mask(Im(op)); break; // zapnot - case 0xb2: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(u8(0xff) << (Im(op) & 7)); break; // mskql - case 0xb4: m_r[Rc(op)] = m_r[Ra(op)] >> (Im(op) & 63); break; // srl - case 0xb6: m_r[Rc(op)] = (m_r[Ra(op)] >> ((Im(op) & 7) * 8)) & zap_mask(u8(~u8(0xff))); break; // extql - case 0xb9: m_r[Rc(op)] = m_r[Ra(op)] << (Im(op) & 63); break; // sll - case 0xbb: m_r[Rc(op)] = (m_r[Ra(op)] << ((Im(op) & 7) * 8)) & zap_mask(~(u8(0xff) << (Im(op) & 7))); break; // insql - case 0xbc: m_r[Rc(op)] = s64(m_r[Ra(op)]) >> (Im(op) & 63); break; // sra - case 0xd2: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(u8(0x03) >> (8 - (Im(op) & 7))); break; // mskwh - case 0xd7: m_r[Rc(op)] = (m_r[Ra(op)] >> (64 - ((Im(op) & 7) * 8))) & zap_mask(~(u8(0x03) >> (8 - (Im(op) & 7)))); break; // inswh - case 0xda: m_r[Rc(op)] = (m_r[Ra(op)] << (64 - ((Im(op) & 7) * 8))) & zap_mask(~u8(0x03)); break; // extwh - case 0xe2: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(u8(0x0f) >> (8 - (Im(op) & 7))); break; // msklh - case 0xe7: m_r[Rc(op)] = (m_r[Ra(op)] >> (64 - ((Im(op) & 7) * 8))) & zap_mask(~(u8(0x0f) >> (8 - (Im(op) & 7)))); break; // inslh - case 0xea: m_r[Rc(op)] = (m_r[Ra(op)] << (64 - ((Im(op) & 7) * 8))) & zap_mask(~u8(0x0f)); break; // extlh - case 0xf2: m_r[Rc(op)] = m_r[Ra(op)] & zap_mask(u8(0xff) >> (8 - (Im(op) & 7))); break; // mskqh - case 0xf7: m_r[Rc(op)] = (m_r[Ra(op)] >> (64 - ((Im(op) & 7) * 8))) & zap_mask(~(u8(0xff) >> (8 - (Im(op) & 7)))); break; // insqh - case 0xfa: m_r[Rc(op)] = (m_r[Ra(op)] << (64 - ((Im(op) & 7) * 8))) & zap_mask(u8(~u8(0xff))); break; // extqh - } - break; - case 0x13: // INTM* (integer multiply) - switch ((op >> 5) & 0xff) - { - // register variants - case 0x00: m_r[Rc(op)] = s64(s32(u32(m_r[Ra(op)]) * u32(m_r[Rb(op)]))); break; // mull - case 0x20: m_r[Rc(op)] = m_r[Ra(op)] * m_r[Rb(op)]; break; // mulq - case 0x30: mulu_64x64(m_r[Ra(op)], m_r[Rb(op)], &m_r[Rc(op)]); break; // umulh - case 0x40: m_r[Rc(op)] = s64(s32(u32(m_r[Ra(op)]) * u32(m_r[Rb(op)]))); break; // mull/v - case 0x60: m_r[Rc(op)] = m_r[Ra(op)] * m_r[Rb(op)]; break; // mulq/v - - // immediate variants - case 0x80: m_r[Rc(op)] = s64(s32(u32(m_r[Ra(op)]) * u32(Im(op)))); break; // mull - case 0xa0: m_r[Rc(op)] = m_r[Ra(op)] * Im(op); break; // mulq - case 0xb0: mulu_64x64(m_r[Ra(op)], Im(op), &m_r[Rc(op)]); break; // umulh - case 0xc0: m_r[Rc(op)] = s64(s32(u32(m_r[Ra(op)]) * u32(Im(op)))); break; // mull/v - case 0xe0: m_r[Rc(op)] = m_r[Ra(op)] * Im(op); break; // mulq/v - } - break; - //case 0x14: // ITFP* (integer to floating) - //case 0x15: // FLTV* (vax floating) - //case 0x16: // FLTI* (ieee floating) - //case 0x17: // FLTL* (floating) - - case 0x18: // MISC* (miscellaneous) - // TODO: all of these are effectively no-ops for now - switch (u16(op)) - { - case 0x0000: break; // trapb - case 0x0400: break; // excb - case 0x4000: break; // mb - case 0x4400: break; // wmb - case 0x8000: break; // fetch - case 0xa000: break; // fetch_m - case 0xc000: break; // rpcc - case 0xe000: break; // rc - case 0xe800: break; // ecb - case 0xf000: break; // rs - case 0xf800: break; // wh64 - } - break; - - case 0x1a: // JSR* - m_r[Ra(op)] = m_pc; - m_pc = m_r[Rb(op)] & ~3; - break; - - case 0x20: load<u32>(m_r[Rb(op)] + Disp_M(op), [this, op](u32 data) { m_f[Ra(op)] = u32_to_f_floating(data); }); break; // ldf - case 0x21: load<u64>(m_r[Rb(op)] + Disp_M(op), [this, op](u64 data) { m_f[Ra(op)] = u64_to_g_floating(data); }); break; // ldg - case 0x22: load<u32>(m_r[Rb(op)] + Disp_M(op), [this, op](u32 data) { m_f[Ra(op)] = f32_to_f64(float32_t{ data }).v; }); break; // lds - case 0x23: load<u64>(m_r[Rb(op)] + Disp_M(op), [this, op](u64 data) { m_f[Ra(op)] = data; }); break; // ldt - case 0x24: store<u32>(m_r[Rb(op)] + Disp_M(op), f_floating_to_u32(m_f[Ra(op)])); break; // stf - case 0x25: store<u64>(m_r[Rb(op)] + Disp_M(op), u64_to_g_floating(m_f[Ra(op)])); break; // stg - case 0x26: store<u32>(m_r[Rb(op)] + Disp_M(op), f64_to_f32(float64_t{ m_f[Ra(op)] }).v); break; // sts - case 0x27: store<u64>(m_r[Rb(op)] + Disp_M(op), m_f[Ra(op)]); break; // stt - case 0x28: load<u32>(m_r[Rb(op)] + Disp_M(op), [this, op](s32 data) { m_r[Ra(op)] = s64(data); }); break; // ldl - case 0x29: load<u64>(m_r[Rb(op)] + Disp_M(op), [this, op](u64 data) { m_r[Ra(op)] = data; }); break; // ldq - case 0x2a: // ldl_l - load_l<u32>(m_r[Rb(op)] + Disp_M(op), - [this, op](address_space &space, u64 address, s32 data) - { - if (m_lock_watch) - m_lock_watch->remove(); - - m_r[Ra(op)] = s64(data); - - space.install_write_tap(offs_t(address & ~15), offs_t(address | 15), "ldl_l", - [this](offs_t offset, u64 &data, u64 mem_mask) - { - m_lock_watch->remove(); - m_lock_watch = nullptr; - }); - }); - break; - case 0x2b: // ldq_l - load_l<u64>(m_r[Rb(op)] + Disp_M(op), - [this, op](address_space &space, u64 address, u64 data) - { - if (m_lock_watch) - m_lock_watch->remove(); - - m_r[Ra(op)] = data; - - space.install_write_tap(offs_t(address & ~15), offs_t(address | 15), "ldq_l", - [this](offs_t offset, u64 &data, u64 mem_mask) - { - m_lock_watch->remove(); - m_lock_watch = nullptr; - }); - }); - break; - case 0x2c: store<u32>(m_r[Rb(op)] + Disp_M(op), u32(m_r[Ra(op)])); break; // stl - case 0x2d: store<u64>(m_r[Rb(op)] + Disp_M(op), m_r[Ra(op)]); break; // stq - case 0x2e: // stl_c - if (m_lock_watch) - { - store<u32>(m_r[Rb(op)] + Disp_M(op), u32(m_r[Ra(op)])); - m_r[Ra(op)] = 1; - - m_lock_watch->remove(); - m_lock_watch = nullptr; - } - else - m_r[Ra(op)] = 0; - break; - case 0x2f: // stq_c - if (m_lock_watch) - { - store<u64>(m_r[Rb(op)] + Disp_M(op), m_r[Ra(op)]); - m_r[Ra(op)] = 1; - - m_lock_watch->remove(); - m_lock_watch = nullptr; - } - else - m_r[Ra(op)] = 0; - break; - - // branch format - case 0x30: // br - m_r[Ra(op)] = m_pc; - m_pc += Disp_B(op); - break; - case 0x31: // fbeq - if (!(m_f[Ra(op)] & 0x7fffffff'ffffffffULL)) - m_pc += Disp_B(op); - break; - case 0x32: // fblt - if (BIT(m_f[Ra(op)], 63) && (m_f[Ra(op)] & 0x7fffffff'ffffffffULL)) - m_pc += Disp_B(op); - break; - case 0x33: // fble - if (BIT(m_f[Ra(op)], 63) || !(m_f[Ra(op)] & 0x7fffffff'ffffffffULL)) - m_pc += Disp_B(op); - break; - case 0x34: // bsr - m_r[Ra(op)] = m_pc; - m_pc += Disp_B(op); - break; - case 0x35: // fbne - if (m_f[Ra(op)] & 0x7fffffff'ffffffffULL) - m_pc += Disp_B(op); - break; - case 0x36: // fbge - if (!BIT(m_f[Ra(op)], 63) || !(m_f[Ra(op)] & 0x7fffffff'ffffffffULL)) - m_pc += Disp_B(op); - break; - case 0x37: // fbgt - if (!BIT(m_f[Ra(op)], 63) && (m_f[Ra(op)] & 0x7fffffff'ffffffffULL)) - m_pc += Disp_B(op); - break; - case 0x38: // blbc - if (!BIT(m_r[Ra(op)], 0)) - m_pc += Disp_B(op); - break; - case 0x39: // beq - if (m_r[Ra(op)] == 0) - m_pc += Disp_B(op); - break; - case 0x3a: // blt - if (s64(m_r[Ra(op)]) < 0) - m_pc += Disp_B(op); - break; - case 0x3b: // ble - if (s64(m_r[Ra(op)]) <= 0) - m_pc += Disp_B(op); - break; - case 0x3c: // blbs - if (BIT(m_r[Ra(op)], 0)) - m_pc += Disp_B(op); - break; - case 0x3d: // bne - if (m_r[Ra(op)] != 0) - m_pc += Disp_B(op); - break; - case 0x3e: // bge - if (s64(m_r[Ra(op)]) >= 0) - m_pc += Disp_B(op); - break; - case 0x3f: // bgt - if (s64(m_r[Ra(op)]) > 0) - m_pc += Disp_B(op); - break; - } -} - -u64 alpha_device::zap_mask(u8 const zap_bits) -{ - u64 mask = 0; - - for (unsigned i = 0; i < 8; i++) - if (!BIT(zap_bits, i)) - mask |= (0xffULL << (i << 3)); - - return mask; -} - -// transform from f_floating memory to register format -u64 alpha_device::u32_to_f_floating(u32 const data) -{ - if (!BIT(data, 14) && (data & 0x00003f80UL)) - return - (u64(data & 0x0000c000UL) << 48) | - (u64(7) << 61) | - (u64(data & 0x00003fffUL) << 45) | - (u64(data & 0xffff0000UL) << 13); - else - return - (u64(data & 0x0000c000UL) << 48) | - (u64(data & 0x00003fffUL) << 45) | - (u64(data & 0xffff0000UL) << 13); -} - -// transform from f_floating register to memory format -u32 alpha_device::f_floating_to_u32(u64 const data) -{ - return - (u32(data >> 48) & 0x0000c000UL) | - (u32(data >> 45) & 0x00003fffUL) | - (u32(data >> 13) & 0xffff0000UL); -} - -// transform between g_floating register and memory format -u64 alpha_device::u64_to_g_floating(u64 const data) -{ - return - ((data & 0x00000000'0000ffffULL) << 48) | - ((data & 0x00000000'ffff0000ULL) << 16) | - ((data & 0x0000ffff'00000000ULL) >> 16) | - ((data & 0xffff0000'00000000ULL) >> 48); -} - -bool alpha_ev4_device::cpu_translate(u64 &address, int intention) -{ - // trim virtual address to 43 bits - address &= 0x7ff'ffffffff; - - if (intention & TRANSLATE_FETCH) - { - // instruction superpage mapping - if ((m_ibx[IBX_ICCSR] & IBX_ICCSR_R_MAP) && !(m_ibx[IBX_PS] & IBX_PS_R_CM) && (address >> 41) == 2) - { - address &= 0x3'ffffffff; - - return true; - } - } - else - { - // data superpage 1 mapping - if ((m_abx[ABX_ABOX_CTL] & ABX_ABOX_CTL_SPE_1) && !(m_ibx[IBX_PS] & IBX_PS_R_CM) && (address >> 30) == 0x1ffe) - { - address &= 0x3fffffff; - - return true; - } - - // data superpage 2 mapping - if ((m_abx[ABX_ABOX_CTL] & ABX_ABOX_CTL_SPE_2) && !(m_ibx[IBX_PS] & IBX_PS_R_CM) && (address >> 41) == 2) - { - address &= 0x3'ffffffff; - - return true; - } - } - - return true; -} - -template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> alpha_device::load(u64 address, U &&apply) -{ - cpu_translate(address, TRANSLATE_READ); - - unsigned const s = (address >> 31) & 6; - - switch (sizeof(T)) - { - case 1: apply(T(space(s).read_byte(address))); break; - case 2: apply(T(space(s).read_word(address))); break; - case 4: apply(T(space(s).read_dword(address))); break; - case 8: apply(T(space(s).read_qword(address))); break; - } -} - -template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(address_space &, u64, T)>>::value, void> alpha_device::load_l(u64 address, U &&apply) -{ - cpu_translate(address, TRANSLATE_READ); - - unsigned const s = (address >> 31) & 6; - - switch (sizeof(T)) - { - case 4: apply(space(s), address, T(space(s).read_dword(address))); break; - case 8: apply(space(s), address, T(space(s).read_qword(address))); break; - } -} - -template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, void> alpha_device::store(u64 address, U data, T mem_mask) -{ - cpu_translate(address, TRANSLATE_WRITE); - - unsigned const s = (address >> 31) & 6; - - switch (sizeof(T)) - { - case 1: space(s).write_byte(address, T(data)); break; - case 2: space(s).write_word(address, T(data), mem_mask); break; - case 4: space(s).write_dword(address, T(data), mem_mask); break; - case 8: space(s).write_qword(address, T(data), mem_mask); break; - } -} - -void alpha_device::fetch(u64 address, std::function<void(u32)> &&apply) -{ - cpu_translate(address, TRANSLATE_FETCH); - - apply(icache_fetch(address)); -} - -u32 alpha_device::read_srom(unsigned const bits) -{ - u32 data = 0; - - for (unsigned i = 0; i < bits; i++) - if (m_srom_data_cb()) - data |= (1U << i); - - return data; -} - -void alpha_ev4_device::device_start() -{ - alpha_device::device_start(); - - save_item(NAME(m_ibx)); - save_item(NAME(m_abx)); - save_item(NAME(m_pt)); -} - -void alpha_ev4_device::device_reset() -{ - alpha_device::device_reset(); - - m_ibx[IBX_ICCSR] = IBX_ICCSR_R_PC0 | IBX_ICCSR_R_PC1; // FIXME: ASN - m_ibx[IBX_PAL_BASE] = 0; - - m_abx[ABX_ABOX_CTL] = 0; - m_abx[ABX_BIU_CTL] = 0; -} - -void alpha_ev4_device::cpu_execute(u32 const op) -{ - switch (op >> 26) - { - case 0x00: // call_pal - { - u16 offset = CALL_PAL | ((op & 0x3f) << 6); - if (op & 0x80) - { - // unprivileged - if (op & CALL_PAL_MASK) - offset = OPCDEC; - else - offset |= 0x1000; - } - else - { - // privileged - if ((op & CALL_PAL_MASK) || (m_ibx[IBX_PS] & IBX_PS_R_CM)) - offset = OPCDEC; - } - - m_ibx[IBX_EXC_ADDR] = m_pc; - if (m_pal_mode) - m_ibx[IBX_EXC_ADDR] |= 1; - - m_pal_mode = true; - m_pc = m_ibx[IBX_PAL_BASE] | offset; - } - break; - - case 0x19: // hw_mfpr - if (op & 0x20) - m_r[Ra(op)] = ibx_get(Rc(op)); - if (op & 0x40) - m_r[Ra(op)] = abx_get(Rc(op)); - if (op & 0x80) - m_r[Ra(op)] = m_pt[Rc(op)]; - break; - - case 0x1d: // hw_mtpr - if (op & 0x20) - ibx_set(Rc(op), m_r[Ra(op)]); - if (op & 0x40) - abx_set(Rc(op), m_r[Ra(op)]); - if (op & 0x80) - m_pt[Rc(op)] = m_r[Ra(op)]; - break; - case 0x1e: // hw_rei - m_pc = m_ibx[IBX_EXC_ADDR] & ~3; - m_pal_mode = BIT(m_ibx[IBX_EXC_ADDR], 0); - - if (m_lock_watch) - { - m_lock_watch->remove(); - m_lock_watch = nullptr; - } - break; - - default: - alpha_device::cpu_execute(op); - break; - } -} - -u64 alpha_ev4_device::ibx_get(u8 reg) -{ - switch (ibx_reg(reg)) - { - // PALmode only - case IBX_ITB_PTE: - case IBX_ITB_PTE_TEMP: - if (m_pal_mode) - return m_ibx[reg]; - else - return 0; - - case IBX_ICCSR: - case IBX_EXC_ADDR: - case IBX_SL_RCV: - case IBX_PS: - case IBX_EXC_SUM: - case IBX_PAL_BASE: - case IBX_HIRR: - case IBX_SIRR: - case IBX_ASTRR: - case IBX_HIER: - case IBX_SIER: - case IBX_ASTER: - return m_ibx[reg]; - - default: - logerror("invalid mfpr/i register %d (%s)\n", reg, machine().describe_context()); - return 0; - } -} - -#define IBX_SET(Reg, Field) if (data & IBX_##Reg##_W_##Field) m_ibx[reg] |= IBX_##Reg##_R_##Field -#define IBX_SHL(Reg, Field, Shift) m_ibx[reg] |= (data & IBX_##Reg##_W_##Field) << Shift -#define IBX_SHR(Reg, Field, Shift) m_ibx[reg] |= (data & IBX_##Reg##_W_##Field) >> Shift - -void alpha_ev4_device::ibx_set(u8 reg, u64 data) -{ - switch (ibx_reg(reg)) - { - // PALmode only - case IBX_TB_TAG: - case IBX_ITB_PTE: - case IBX_ITBZAP: - case IBX_ITBASM: - case IBX_ITBIS: - if (m_pal_mode) - { - m_ibx[reg] = data; - return; - } - break; - - case IBX_EXC_ADDR: - case IBX_EXC_SUM: - case IBX_SIRR: - case IBX_ASTRR: - case IBX_HIER: - case IBX_SIER: - case IBX_ASTER: - case IBX_SL_CLR: - case IBX_SL_XMIT: - m_ibx[reg] = data; - return; - - case IBX_ICCSR: - m_ibx[reg] = data & IBX_ICCSR_R_PCE; - IBX_SET(ICCSR, PC1); - IBX_SET(ICCSR, PC0); - IBX_SHL(ICCSR, PCMUX0, 1); - IBX_SHR(ICCSR, GRP1, 19); - IBX_SHR(ICCSR, ASN, 19); - return; - - case IBX_PS: - m_ibx[reg] = 0; - IBX_SET(PS, CM0); - IBX_SET(PS, CM1); - return; - - case IBX_PAL_BASE: - m_ibx[reg] = data & IBX_PAL_BASE_W; - return; - - default: - logerror("invalid mtpr/i register %d (%s)\n", reg, machine().describe_context()); - break; - } -} - -u64 alpha_ev4_device::abx_get(u8 reg) -{ - switch (abx_reg(reg)) - { - case ABX_DTB_PTE: - case ABX_DTB_PTE_TEMP: - case ABX_MM_CSR: - case ABX_VA: - case ABX_BIU_ADDR: - case ABX_BIU_STAT: - case ABX_DC_STAT: - case ABX_FILL_ADDR: - return m_abx[reg]; - - default: - logerror("invalid mfpr/a register %d (%s)\n", reg, machine().describe_context()); - return 0; - } -} - -void alpha_ev4_device::abx_set(u8 reg, u64 data) -{ - switch (abx_reg(reg)) - { - case ABX_TB_CTL: - case ABX_DTB_PTE: - case ABX_DTBZAP: - case ABX_DTBASM: - case ABX_DTBIS: - case ABX_ABOX_CTL: - case ABX_ALT_MODE: - case ABX_CC: - case ABX_CC_CTL: - case ABX_BIU_CTL: - case ABX_FILL_SYNDROME: - case ABX_BC_TAG: - case ABX_FLUSH_IC: - case ABX_FLUSH_IC_ASM: - m_abx[reg] = data; - return; - - default: - logerror("invalid mtpr/a register %d (%s)\n", reg, machine().describe_context()); - break; - } -} - -void dec_21064_device::device_reset() -{ - alpha_ev4_device::device_reset(); - - m_srom_oe_cb(0); - - // load icache from srom - for (icache_block &block : m_icache) - { - block.lw[0] = read_srom(32); - block.lw[2] = read_srom(32); - block.lw[4] = read_srom(32); - block.lw[6] = read_srom(32); - - block.tag = read_srom(21); - block.aav = read_srom(8); - - block.lw[1] = read_srom(32); - block.lw[3] = read_srom(32); - block.lw[5] = read_srom(32); - block.lw[7] = read_srom(32); - - block.bht = read_srom(8); - } - - m_srom_oe_cb(1); -} - -u32 dec_21064_device::icache_fetch(u64 const address) -{ - icache_block &block = m_icache[(address >> 5) & 0xff]; - - // check tag, valid, and asm or asn - if ((block.tag != (address >> 13)) || !(block.aav & AAV_V) || (!(block.aav & AAV_ASM) && ((block.aav & AAV_ASN) != (((m_ibx[IBX_ICCSR] & IBX_ICCSR_R_ASN) >> 28))))) - { - // fetch a new block - block.tag = address >> 13; - block.aav = AAV_V | ((m_ibx[IBX_ICCSR] & IBX_ICCSR_R_ASN) >> 28); // TODO: set ASM depending on PTE - - // always set ASM if istream superpage mapping is enabled - if (m_ibx[IBX_ICCSR] & IBX_ICCSR_R_MAP) - block.aav |= AAV_ASM; - - address_space &s = space((address >> 31) & 6); - for (unsigned i = 0; i < 8; i++) - block.lw[i] = s.read_dword(address | (i << 2)); - } - - return block.lw[(address >> 2) & 7]; -} |