From 7e9c4475e8badf8ad13238866192d4dbbffc70a4 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Tue, 19 Feb 2019 18:37:12 +0700 Subject: [PATCH] alpha: most integer instructions (nw) --- src/devices/cpu/alpha/alpha.cpp | 839 +++++++++++++++++++++++++++++++- src/devices/cpu/alpha/alpha.h | 191 +++++++- src/devices/cpu/alpha/common.h | 14 +- 3 files changed, 1025 insertions(+), 19 deletions(-) diff --git a/src/devices/cpu/alpha/alpha.cpp b/src/devices/cpu/alpha/alpha.cpp index 62fbd1bb584..bc77e0b1ada 100644 --- a/src/devices/cpu/alpha/alpha.cpp +++ b/src/devices/cpu/alpha/alpha.cpp @@ -8,13 +8,23 @@ * * 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 - * - skeleton only (wip) + * - 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" @@ -31,13 +41,24 @@ 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_device(mconfig, DEC_21064, tag, owner, 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_main_config("main", ENDIANNESS_LITTLE, 64, 32, 0) + , 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_dasm_type(alpha_disassembler::dasm_type::TYPE_UNKNOWN) , m_icount(0) { @@ -51,6 +72,8 @@ void alpha_device::device_start() 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(); @@ -68,6 +91,7 @@ void alpha_device::device_start() void alpha_device::device_reset() { m_pc = 0; + m_pal_mode = true; } void alpha_device::execute_run() @@ -76,6 +100,20 @@ void alpha_device::execute_run() { 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--; } } @@ -86,15 +124,806 @@ void alpha_device::execute_set_input(int inputnum, int state) device_memory_interface::space_config_vector alpha_device::memory_space_config() const { - return space_config_vector { std::make_pair(0, &m_main_config) }; + /* + * 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) { - return true; + u64 placeholder = s64(s32(address)); + + if (cpu_translate(placeholder, intention)) + { + address = placeholder; + + return true; + } + + return false; } std::unique_ptr alpha_device::create_disassembler() { return std::make_unique(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((m_r[Rb(op)] + Disp_M(op)) & ~7, [this, op](u64 data) { m_r[Ra(op)] = data; }); break; // ldq_u + case 0x0f: store((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(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(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(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(m_r[Rb(op)] + Disp_M(op), [this, op](u64 data) { m_f[Ra(op)] = data; }); break; // ldt + case 0x24: store(m_r[Rb(op)] + Disp_M(op), f_floating_to_u32(m_f[Ra(op)])); break; // stf + case 0x25: store(m_r[Rb(op)] + Disp_M(op), u64_to_g_floating(m_f[Ra(op)])); break; // stg + case 0x26: store(m_r[Rb(op)] + Disp_M(op), f64_to_f32(float64_t{ m_f[Ra(op)] }).v); break; // sts + case 0x27: store(m_r[Rb(op)] + Disp_M(op), m_f[Ra(op)]); break; // stt + case 0x28: load(m_r[Rb(op)] + Disp_M(op), [this, op](s32 data) { m_r[Ra(op)] = s64(data); }); break; // ldl + case 0x29: load(m_r[Rb(op)] + Disp_M(op), [this, op](u64 data) { m_r[Ra(op)] = data; }); break; // ldq + case 0x2a: // ldl_l + load_l(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(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(m_r[Rb(op)] + Disp_M(op), u32(m_r[Ra(op)])); break; // stl + case 0x2d: store(m_r[Rb(op)] + Disp_M(op), m_r[Ra(op)]); break; // stq + case 0x2e: // stl_c + if (m_lock_watch) + { + store(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(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 std::enable_if_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 std::enable_if_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 std::enable_if_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 &&apply) +{ + unsigned const s = (address >> 31) & 6; + + apply(space(s).read_dword(address)); +} + +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; + } + +} diff --git a/src/devices/cpu/alpha/alpha.h b/src/devices/cpu/alpha/alpha.h index b4f5db3712b..ab763439ad8 100644 --- a/src/devices/cpu/alpha/alpha.h +++ b/src/devices/cpu/alpha/alpha.h @@ -16,14 +16,13 @@ public: protected: alpha_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); - // device-level overrides + // device_t overrides virtual void device_start() override; virtual void device_reset() override; // device_execute_interface overrides virtual u32 execute_min_cycles() const override { return 1; } virtual u32 execute_max_cycles() const override { return 1; } - virtual u32 execute_input_lines() const override { return 6; } virtual void execute_run() override; virtual void execute_set_input(int inputnum, int state) override; @@ -34,20 +33,198 @@ protected: // device_disasm_interface overrides virtual std::unique_ptr create_disassembler() override; -private: + virtual void cpu_execute(u32 const op); + virtual bool cpu_translate(u64 &address, int intention) { return false; } + + // execution helpers + static u64 zap_mask(u8 const zap_bits); + static u64 u64_to_g_floating(u64 const data); + static u64 u32_to_f_floating(u32 const data); + static u32 f_floating_to_u32(u64 const data); + + // memory access helpers + template std::enable_if_t>::value, void> load(u64 address, U &&apply); + template std::enable_if_t>::value, void> load_l(u64 address, U &&apply); + template std::enable_if_t::value, void> store(u64 address, U data, T mem_mask = ~T(0)); + void fetch(u64 address, std::function &&apply); + // configuration - address_space_config m_main_config; + address_space_config m_as_config[4]; alpha_disassembler::dasm_type m_dasm_type; // emulation state int m_icount; u64 m_pc; - u64 m_r[32]; // R31 is zero - u64 m_f[32]; // F31 is zero + u64 m_r[32]; + u64 m_f[32]; + + bool m_pal_mode; + memory_passthrough_handler *m_lock_watch; }; -class dec_21064_device : public alpha_device +class alpha_ev4_device : public alpha_device +{ +public: + alpha_ev4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); + +private: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // device_execute_interface overrides + virtual u32 execute_input_lines() const override { return 6; } + + virtual void cpu_execute(u32 const op) override; + virtual bool cpu_translate(u64 &address, int intention) override; + + enum ibx_reg : unsigned + { + IBX_TB_TAG = 0, // w, PALmode only + IBX_ITB_PTE = 1, // r/w, PALmode only + IBX_ICCSR = 2, // r/w + IBX_ITB_PTE_TEMP = 3, // r, PALmode only + IBX_EXC_ADDR = 4, // r/w + IBX_SL_RCV = 5, // r + IBX_ITBZAP = 6, // w, PALmode only + IBX_ITBASM = 7, // w, PALmode only + IBX_ITBIS = 8, // w, PALmode only + IBX_PS = 9, // r/w + IBX_EXC_SUM = 10, // r/w + IBX_PAL_BASE = 11, // r/w + IBX_HIRR = 12, // r + IBX_SIRR = 13, // r/w + IBX_ASTRR = 14, // r/w + IBX_HIER = 16, // r/w + IBX_SIER = 17, // r/w + IBX_ASTER = 18, // r/w + IBX_SL_CLR = 19, // w + IBX_SL_XMIT = 22, // w + }; + + enum ibx_iccsr_mask : u64 + { + IBX_ICCSR_W_PC1 = 0x00000000'00000001, // performance counter 1 interrupt enable + IBX_ICCSR_W_PC0 = 0x00000000'00000008, // performance counter 0 interrupt enable + IBX_ICCSR_W_PCMUX0 = 0x00000000'00000f00, + IBX_ICCSR_W_PCMUX1 = 0x00000007'00000000, + IBX_ICCSR_W_PIPE = 0x00000008'00000000, // pipeline enable + IBX_ICCSR_W_BPE = 0x00000010'00000000, + IBX_ICCSR_W_JSE = 0x00000020'00000000, // jsr stack enable + IBX_ICCSR_W_BHE = 0x00000040'00000000, + IBX_ICCSR_W_DI = 0x00000080'00000000, // dual issue enable + IBX_ICCSR_W_HWE = 0x00000100'00000000, // hardware mode enable + IBX_ICCSR_W_MAP = 0x00000200'00000000, // i-stream superpage enable + IBX_ICCSR_W_FPE = 0x00000400'00000000, // floating-point enable + IBX_ICCSR_W_PCE = 0x00003000'00000000, // performance counter enable + IBX_ICCSR_W_ASN = 0x001f8000'00000000, // address space number + + IBX_ICCSR_R_PC0 = 0x00000000'00000002, // performance counter 0 interrupt enable + IBX_ICCSR_R_PC1 = 0x00000000'00000004, // performance counter 1 interrupt enable + IBX_ICCSR_R_PCMUX0 = 0x00000000'00001e00, + IBX_ICCSR_R_PCMUX1 = 0x00000000'0000e000, + IBX_ICCSR_R_PIPE = 0x00000000'00010000, // pipeline enable + IBX_ICCSR_R_BPE = 0x00000000'00020000, + IBX_ICCSR_R_JSE = 0x00000000'00040000, // jsr stack enable + IBX_ICCSR_R_BHE = 0x00000000'00080000, + IBX_ICCSR_R_DI = 0x00000000'00100000, // dual issue enable + IBX_ICCSR_R_HWE = 0x00000000'00200000, // hardware mode enable + IBX_ICCSR_R_MAP = 0x00000000'00400000, // i-stream superpage enable + IBX_ICCSR_R_FPE = 0x00000000'00800000, // floating-point enable + IBX_ICCSR_R_ASN = 0x00000003'f0000000, // address space number + IBX_ICCSR_R_PCE = 0x00003000'00000000, // performance counter enable + + IBX_ICCSR_W_GRP1 = 0x000007ff'00000000, + }; + enum ibx_ps_mask : u64 + { + IBX_PS_R_CM0 = 0x00000000'00000001, + IBX_PS_R_CM1 = 0x00000004'00000000, + IBX_PS_R_CM = 0x00000004'00000001, + + IBX_PS_W_CM0 = 0x00000000'00000008, + IBX_PS_W_CM1 = 0x00000000'00000010, + }; + enum ibx_pal_base_mask : u64 + { + IBX_PAL_BASE_W = 0x00000003'ffffc000, + }; + + enum abx_reg : unsigned + { + ABX_TB_CTL = 0, // w + ABX_DTB_PTE = 2, // r/w + ABX_DTB_PTE_TEMP = 3, // r + ABX_MM_CSR = 4, // r + ABX_VA = 5, // r + ABX_DTBZAP = 6, // w + ABX_DTBASM = 7, // w + ABX_DTBIS = 8, // w + ABX_BIU_ADDR = 9, // r + ABX_BIU_STAT = 10, // r + ABX_DC_STAT = 12, // r + ABX_FILL_ADDR = 13, // r + ABX_ABOX_CTL = 14, // w + ABX_ALT_MODE = 15, // w + ABX_CC = 16, // w + ABX_CC_CTL = 17, // w + ABX_BIU_CTL = 18, // w + ABX_FILL_SYNDROME = 19, // w + ABX_BC_TAG = 20, // w + ABX_FLUSH_IC = 21, // w + ABX_FLUSH_IC_ASM = 23, // w + }; + + enum abx_abox_ctl_mask : u64 + { + ABX_ABOX_CTL_WB_DIS = 0x0001, // write buffer unload disable + ABX_ABOX_CTL_MCHK_EN = 0x0002, // machine check enable + ABX_ABOX_CTL_CRD_EN = 0x0004, // corrected read data interrupt enable + ABX_ABOX_CTL_IC_SBUF_EN = 0x0008, // icache stream buffer enable + ABX_ABOX_CTL_SPE_1 = 0x0010, // super page enable 1 + ABX_ABOX_CTL_SPE_2 = 0x0020, // super page enable 2 + ABX_ABOX_CTL_EMD_EN = 0x0040, // big-endian mode enable + ABX_ABOX_CTL_STC_NORESULT = 0x0080, // + ABX_ABOX_CTL_NCACHE_NDISTURB = 0x0100, // + ABX_ABOX_CTL_DTB_RR = 0x0200, // dtb round-robin replacement + ABX_ABOX_CTL_DC_ENA = 0x0400, // dcache enable + ABX_ABOX_CTL_DC_FHIT = 0x0800, // dcache force hit + ABX_ABOX_CTL_DC_16K = 0x1000, // select 16K dcache (21064A only) + ABX_ABOX_CTL_F_TAG_ERR = 0x2000, // generate bad dcache tag parity (21064A only) + ABX_ABOX_CTL_NOCHK_PAR = 0x4000, // disable cache parity checks (21064A only) + ABX_ABOX_CTL_DOUBLE_INVAL = 0x8000, // (21064A only) + }; + + enum palcode_entry : u16 + { + RESET = 0x0000, + MCHK = 0x0020, + ARITH = 0x0060, + INTERRUPT = 0x00e0, + D_FAULT = 0x01e0, + ITB_MISS = 0x03e0, + ITB_ACV = 0x07e0, + DTB_MISS_NATIVE = 0x08e0, + DTB_MISS_PAL = 0x09e0, + UNALIGN = 0x11e0, + OPCDEC = 0x13e0, + FEN = 0x17e0, + CALL_PAL = 0x2000, + }; + static constexpr u32 CALL_PAL_MASK = 0x03ffff40; + + u64 ibx_get(u8 reg); + void ibx_set(u8 reg, u64 data); + u64 abx_get(u8 reg); + void abx_set(u8 reg, u64 data); + + u64 m_ibx[32]; + u64 m_abx[32]; + u64 m_pt[32]; +}; + +class dec_21064_device : public alpha_ev4_device { public: dec_21064_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); diff --git a/src/devices/cpu/alpha/common.h b/src/devices/cpu/alpha/common.h index ec2e7ebc236..0c9668f304a 100644 --- a/src/devices/cpu/alpha/common.h +++ b/src/devices/cpu/alpha/common.h @@ -7,13 +7,13 @@ #pragma once // instruction field extraction -#define Ra(x) ((x >> 21) & 31) // 'a' register field -#define Rb(x) ((x >> 16) & 31) // 'b' register field -#define Rc(x) (x & 31) // 'c' register field -#define Im(x) (u64(u8(x >> 13))) // literal immediate field +#define Ra(x) ((x >> 21) & 31) // 'a' register field +#define Rb(x) ((x >> 16) & 31) // 'b' register field +#define Rc(x) (x & 31) // 'c' register field +#define Im(x) (u64(u8(x >> 13))) // literal immediate field -#define Disp_M(x) (s16(x)) // memory instruction 16-bit signed offset -#define Disp_P(x) (s16(x << 4) >> 4) // hardware load/store 12-bit signed offset -#define Disp_B(x) (s32(x << 11) >> 9) // branch instruction offset +#define Disp_M(x) (s64(s16(x))) // memory instruction 16-bit signed offset +#define Disp_P(x) (s64(s16(x << 4)) >> 4) // hardware load/store 12-bit signed offset +#define Disp_B(x) (s64(s32(x << 11)) >> 9) // branch instruction offset #endif // MAME_CPU_ALPHA_COMMON_H