alpha: most integer instructions (nw)

This commit is contained in:
Patrick Mackinlay 2019-02-19 18:37:12 +07:00
parent 7983685096
commit 7e9c4475e8
3 changed files with 1025 additions and 19 deletions

View File

@ -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/21064-aa-RISC%20Microprocessor%20Preliminary%20Data%20Sheet-apr92.pdf
* http://bitsavers.org/pdf/dec/alpha/Sites_AlphaAXPArchitectureReferenceManual_2ed_1995.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 * 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 "emu.h"
#include "alpha.h" #include "alpha.h"
#include "common.h"
#include "debugger.h" #include "debugger.h"
@ -31,13 +41,24 @@
DEFINE_DEVICE_TYPE(DEC_21064, dec_21064_device, "21064", "DEC Alpha 21064") 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) 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) 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) : 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_dasm_type(alpha_disassembler::dasm_type::TYPE_UNKNOWN)
, m_icount(0) , m_icount(0)
{ {
@ -51,6 +72,8 @@ void alpha_device::device_start()
save_item(NAME(m_r)); save_item(NAME(m_r));
save_item(NAME(m_f)); save_item(NAME(m_f));
save_item(NAME(m_pal_mode));
state_add(STATE_GENPC, "GENPC", m_pc).noshow(); state_add(STATE_GENPC, "GENPC", m_pc).noshow();
state_add(STATE_GENPCBASE, "CURPC", 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() void alpha_device::device_reset()
{ {
m_pc = 0; m_pc = 0;
m_pal_mode = true;
} }
void alpha_device::execute_run() void alpha_device::execute_run()
@ -76,6 +100,20 @@ void alpha_device::execute_run()
{ {
debugger_instruction_hook(m_pc); 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--; 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 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) 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<util::disasm_interface> alpha_device::create_disassembler() std::unique_ptr<util::disasm_interface> alpha_device::create_disassembler()
{ {
return std::make_unique<alpha_disassembler>(m_dasm_type); 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)
{
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;
}
}

View File

@ -16,14 +16,13 @@ public:
protected: protected:
alpha_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); 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_start() override;
virtual void device_reset() override; virtual void device_reset() override;
// device_execute_interface overrides // device_execute_interface overrides
virtual u32 execute_min_cycles() const override { return 1; } virtual u32 execute_min_cycles() const override { return 1; }
virtual u32 execute_max_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_run() override;
virtual void execute_set_input(int inputnum, int state) override; virtual void execute_set_input(int inputnum, int state) override;
@ -34,20 +33,198 @@ protected:
// device_disasm_interface overrides // device_disasm_interface overrides
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; virtual std::unique_ptr<util::disasm_interface> 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 <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> load(u64 address, U &&apply);
template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(address_space &, u64, T)>>::value, void> load_l(u64 address, U &&apply);
template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, void> store(u64 address, U data, T mem_mask = ~T(0));
void fetch(u64 address, std::function<void(u32)> &&apply);
// configuration // configuration
address_space_config m_main_config; address_space_config m_as_config[4];
alpha_disassembler::dasm_type m_dasm_type; alpha_disassembler::dasm_type m_dasm_type;
// emulation state // emulation state
int m_icount; int m_icount;
u64 m_pc; u64 m_pc;
u64 m_r[32]; // R31 is zero u64 m_r[32];
u64 m_f[32]; // F31 is zero 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: public:
dec_21064_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); dec_21064_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);

View File

@ -7,13 +7,13 @@
#pragma once #pragma once
// instruction field extraction // instruction field extraction
#define Ra(x) ((x >> 21) & 31) // 'a' register field #define Ra(x) ((x >> 21) & 31) // 'a' register field
#define Rb(x) ((x >> 16) & 31) // 'b' register field #define Rb(x) ((x >> 16) & 31) // 'b' register field
#define Rc(x) (x & 31) // 'c' register field #define Rc(x) (x & 31) // 'c' register field
#define Im(x) (u64(u8(x >> 13))) // literal immediate 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_M(x) (s64(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_P(x) (s64(s16(x << 4)) >> 4) // hardware load/store 12-bit signed offset
#define Disp_B(x) (s32(x << 11) >> 9) // branch instruction offset #define Disp_B(x) (s64(s32(x << 11)) >> 9) // branch instruction offset
#endif // MAME_CPU_ALPHA_COMMON_H #endif // MAME_CPU_ALPHA_COMMON_H